refactor: 重写题目获得逻辑

This commit is contained in:
2024-01-12 23:07:53 +08:00
parent aedfa99c55
commit 6f82b0a9c9
6 changed files with 311 additions and 577 deletions

View File

@@ -0,0 +1,104 @@
use std::error::Error;
use serde_derive::{Deserialize, Serialize};
use super::{Problem, Problems, Query, Fetcher};
const PROBLEMS_URL: &str = "https://leetcode.cn/api/problems/algorithms/";
const GRAPHQL_URL: &str = "https://leetcode.cn/graphql";
impl Fetcher {
pub fn new() -> Fetcher {
Fetcher {
client: reqwest::Client::new()
}
}
pub async fn get_problems(&self) -> Result<Problems, reqwest::Error> {
Ok(reqwest::get(PROBLEMS_URL)
.await?
.json()
.await?
)
}
pub async fn get_problem(self, question_id: u32) -> Result<Problem, Box<dyn Error>> {
let problems = self.get_problems().await?;
for problem in &problems.stat_status_pairs {
match problem.stat.frontend_question_id.parse::<u32>() {
Ok(id) => {
if id == question_id {
if problem.paid_only {
return Err("failed to get paid only problem".into())
}
let query = match &problem.stat.question_title_slug {
None => {
Err::<Query, Box<dyn Error>>("failed to get problem title slug".into())
}
Some(value) => {
Ok(Query::new(value.as_str()))
}
}?;
let response = self.client
.post(GRAPHQL_URL)
.json(&query)
.send()
.await?
.json::<RawProblem>()
.await?;
let title = problem.stat.question_title.clone()
.ok_or::<Box<dyn Error>>("failed to get problem title".into())?;
let title_slug = problem.stat.question_title_slug.clone()
.ok_or::<Box<dyn Error>>("failed to get problem title slug".into())?;
let return_type = {
let v = serde_json::from_str::<serde_json::Value>(
&response.data.question.meta_data);
v.and_then(|x| {
return Ok(x.to_string().replace("\"", ""))
})
}?;
let code_definition = serde_json::from_str(
&response.data.question.code_definition
)?;
return Ok(Problem {
title,
title_slug,
code_definition,
content: response.data.question.content,
question_id: id,
return_type
})
}
}
Err(_) => {}
}
}
Err("failed to get target problem".into())
}
}
#[derive(Debug, Serialize, Deserialize)]
struct RawProblem {
data: Data,
}
#[derive(Debug, Serialize, Deserialize)]
struct Data {
question: Question,
}
#[derive(Debug, Serialize, Deserialize)]
struct Question {
content: String,
stats: String,
#[serde(rename = "codeDefinition")]
code_definition: String,
#[serde(rename = "sampleTestCase")]
sample_test_case: String,
#[serde(rename = "metaData")]
meta_data: String,
}

View File

@@ -0,0 +1,72 @@
use super::{Problem, ProblemManager};
use std::fs;
use regex::{Regex};
impl ProblemManager {
pub fn scan() -> Result<ProblemManager, Box<dyn std::error::Error>> {
let pattern = Regex::new(r"p(\d{4})_")?;
let mut problems = Vec::new();
let mod_content = fs::read_to_string("./src/problem/mod.rs")?;
for i in pattern.captures_iter(&mod_content) {
match i.get(1) {
None => {}
Some(value) => {
match value.as_str().parse::<u32>() {
Ok(id) => {
problems.push(id);
}
Err(_) => {}
}
}
}
}
Ok(ProblemManager {
problem_list: problems
})
}
}
impl Problem {
pub fn get_filename(&self) -> String {
format!("p{}_{}", self.question_id, self.title_slug.replace('-', "_"))
}
pub fn get_file_content(&self) -> Result<String, Box<dyn std::error::Error>> {
let template = fs::read_to_string("./template.rs")?;
let code = self.code_definition
.iter()
.find(|x| x.value == "rust");
let code = code.ok_or::<Box<dyn std::error::Error>>(
format!("problem {} doesn't have rust version", self.question_id).into()
)?;
let source = template
.replace("__PROBLEM_TITLE__", &self.title)
.replace("__PROBLEM_ID__", self.question_id.to_string().as_str())
.replace(
"__PROBLEM_DEFAULT_CODE__",
&code.default_code)
.replace("__EXTRA_USE__", &parse_extra_use(&code.default_code));
Ok(source)
}
}
fn parse_extra_use(code: &str) -> String {
let mut extra_use_line = String::new();
// a linked-list problem
if code.contains("pub struct ListNode") {
extra_use_line.push_str("\nuse crate::util::linked_list::{ListNode, to_list};")
}
if code.contains("pub struct TreeNode") {
extra_use_line.push_str("\nuse crate::util::tree::{TreeNode, to_tree};")
}
if code.contains("pub struct Point") {
extra_use_line.push_str("\nuse crate::util::point::Point;")
}
extra_use_line
}