forked from aylei/leetcode-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rs
229 lines (214 loc) · 7.91 KB
/
main.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
mod problem;
use regex::Regex;
use std::env;
use std::fs;
use std::io;
use std::io::Write;
use std::path::Path;
/// main() helps to generate the submission template .rs
fn main() {
println!("Welcome to leetcode-rust system.");
let mut solved_ids = get_solved_ids();
loop {
println!("Please enter a frontend problem id, or \"random\" to generate a random one.");
let mut is_random = false;
let mut id: u32 = 0;
let mut id_arg = String::new();
io::stdin()
.read_line(&mut id_arg)
.expect("Failed to read line");
let id_arg = id_arg.trim();
match id_arg {
"random" => {
println!("You select random mode.");
id = generate_random_id(&solved_ids);
is_random = true;
println!("Generate random problem: {}", &id);
}
_ => {
id = id_arg
.parse::<u32>()
.unwrap_or_else(|_| panic!("not a number: {}", id_arg));
if solved_ids.contains(&id) {
println!(
"The problem you chose is invalid (the problem may have been solved \
or may have no rust version)."
);
continue;
}
}
}
let problem = problem::get_problem(id).unwrap_or_else(|| {
panic!(
"Error: failed to get problem #{} \
(The problem may be paid-only or may not be exist).",
id
)
});
let code = problem.code_definition.iter().find(|&d| d.value == "rust");
if code.is_none() {
println!("Problem {} has no rust version.", &id);
solved_ids.push(problem.question_id);
continue;
}
let code = code.unwrap();
let file_name = format!(
"n{:04}_{}",
problem.question_id,
problem.title_slug.replace("-", "_")
);
let file_path = Path::new("./src").join(format!("{}.rs", file_name));
if file_path.exists() {
panic!("problem already initialized");
}
let template = fs::read_to_string("./template.rs").unwrap();
let source = template
.replace("__PROBLEM_TITLE__", &problem.title)
.replace("__PROBLEM_DESC__", &build_desc(&problem.content))
.replace(
"__PROBLEM_DEFAULT_CODE__",
&insert_return_in_code(&problem.return_type, &code.default_code),
)
.replace("__PROBLEM_ID__", &format!("{}", problem.question_id))
.replace("__EXTRA_USE__", &parse_extra_use(&code.default_code));
let mut file = fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&file_path)
.unwrap();
file.write_all(source.as_bytes()).unwrap();
drop(file);
let mut lib_file = fs::OpenOptions::new()
.write(true)
.append(true)
.open("./src/lib.rs")
.unwrap();
writeln!(lib_file, "mod {};", file_name);
break;
}
}
fn generate_random_id(except_ids: &[u32]) -> u32 {
use rand::Rng;
use std::fs;
let mut rng = rand::thread_rng();
loop {
let res: u32 = rng.gen_range(1, 1106);
if !except_ids.contains(&res) {
return res;
}
println!(
"Generate a random num ({}), but it is invalid (the problem may have been solved \
or may have no rust version). Regenerate..",
res
);
}
}
fn get_solved_ids() -> Vec<u32> {
let paths = fs::read_dir("./src").unwrap();
let mut solved_ids = Vec::new();
for path in paths {
let path = path.unwrap().path();
let s = path.to_str().unwrap();
if !s.starts_with('n') {
continue;
}
let id = &s[7..11];
let id = id.parse::<u32>().unwrap();
solved_ids.push(id);
}
solved_ids
}
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 super::util::linked_list::{ListNode, to_list};")
}
if code.contains("pub struct TreeNode") {
extra_use_line.push_str("\nuse super::util::tree::{TreeNode, to_tree};")
}
if code.contains("pub struct Point") {
extra_use_line.push_str("\nuse super::util::point::Point;")
}
extra_use_line
}
fn insert_return_in_code(return_type: &str, code: &str) -> String {
let re = Regex::new(r"\{[ \n]+}").unwrap();
match return_type {
"ListNode" => re
.replace(&code, "{\n Some(Box::new(ListNode::new(0)))\n }")
.to_string(),
"ListNode[]" => re.replace(&code, "{\n vec![]\n }").to_string(),
"TreeNode" => re
.replace(
&code,
"{\n Some(Rc::new(RefCell::new(TreeNode::new(0))))\n }",
)
.to_string(),
"boolean" => re.replace(&code, "{\n false\n }").to_string(),
"character" => re.replace(&code, "{\n '0'\n }").to_string(),
"character[][]" => re.replace(&code, "{\n vec![]\n }").to_string(),
"double" => re.replace(&code, "{\n 0f64\n }").to_string(),
"double[]" => re.replace(&code, "{\n vec![]\n }").to_string(),
"int[]" => re.replace(&code, "{\n vec![]\n }").to_string(),
"integer" => re.replace(&code, "{\n 0\n }").to_string(),
"integer[]" => re.replace(&code, "{\n vec![]\n }").to_string(),
"integer[][]" => re.replace(&code, "{\n vec![]\n }").to_string(),
"list<String>" => re.replace(&code, "{\n vec![]\n }").to_string(),
"list<TreeNode>" => re.replace(&code, "{\n vec![]\n }").to_string(),
"list<boolean>" => re.replace(&code, "{\n vec![]\n }").to_string(),
"list<double>" => re.replace(&code, "{\n vec![]\n }").to_string(),
"list<integer>" => re.replace(&code, "{\n vec![]\n }").to_string(),
"list<list<integer>>" => re.replace(&code, "{\n vec![]\n }").to_string(),
"list<list<string>>" => re.replace(&code, "{\n vec![]\n }").to_string(),
"list<string>" => re.replace(&code, "{\n vec![]\n }").to_string(),
"null" => code.to_string(),
"string" => re
.replace(&code, "{\n String::new()\n }")
.to_string(),
"string[]" => re.replace(&code, "{\n vec![]\n }").to_string(),
"void" => code.to_string(),
"NestedInteger" => code.to_string(),
"Node" => code.to_string(),
_ => code.to_string(),
}
}
fn build_desc(content: &str) -> String {
// TODO: fix this shit
content
.replace("<strong>", "")
.replace("</strong>", "")
.replace("<em>", "")
.replace("</em>", "")
.replace("</p>", "")
.replace("<p>", "")
.replace("<b>", "")
.replace("</b>", "")
.replace("<pre>", "")
.replace("</pre>", "")
.replace("<ul>", "")
.replace("</ul>", "")
.replace("<li>", "")
.replace("</li>", "")
.replace("<code>", "")
.replace("</code>", "")
.replace("<i>", "")
.replace("</i>", "")
.replace("<sub>", "")
.replace("</sub>", "")
.replace("</sup>", "")
.replace("<sup>", "^")
.replace(" ", " ")
.replace(">", ">")
.replace("<", "<")
.replace(""", "\"")
.replace("−", "-")
.replace("'", "'")
.replace("\n\n", "\n")
.replace("\n", "\n * ")
}