视频地址
QQ机器人相关指令-对接LeetCode
去网页上截取相关请求路由信息
LeetCode基础URI: https://leetcode-cn.com
提交code的URL
POST /problems/{problem}/submit/
请求参数: problem 对应题目的slug,如longest-substring-without-repeating-characters
请求体
{
"question_id": "142",
"lang": "java",
"typed_code": "/**\\n * Definition for singly-linked list.\\n * class ListNode {\\n * int val;\\n * ListNode next;\\n * ListNode(int x) {\\n * val = x;\\n * next = null;\\n * }\\n * }\\n */\\npublic class Solution {\\n public ListNode detectCycle(ListNode head) {\\n if (head == null) return null;\\n ListNode fast = head, slow = head;\\n while (fast != null && fast.next != null) {\\n slow = slow.next;\\n fast = fast.next.next;\\n if (fast == slow) {\\n break;\\n }\\n }\\n // 上面的代码类似 hasCycle 函数\\n if (fast == null || fast.next == null) {\\n // fast 遇到空指针说明没有环\\n return null;\\n }\\n // 将快指针置回头部,慢指针每次走一步,快指针也每次走一步,直到相遇\\n fast = head;\\n // 快慢指针同步前进,相交点就是环起点\\n while (fast != slow) {\\n fast = fast.next;\\n slow = slow.next;\\n }\\n return fast;\\n }\\n}",
"test_mode": false,
"test_judger": "amet ea ut laboris ad",
"questionSlug": "linked-list-cycle-ii"
}
响应参数
{
"submission_id": 296959889
}
检查code的URL
POST /submissions/detail/{submission_id}/check/
请求参数: submission_id,前面一个URL成功响应后的submission_id
响应参数
# 编译成功
{
"status_code": 10,
"lang": "java",
"run_success": true,
"status_runtime": "0 ms",
"memory": 42612000,
"display_runtime": "0",
"question_id": "142",
"elapsed_time": 167,
"compare_result": "1111111111111111",
"code_output": "",
"std_output": "",
"last_testcase": "",
"expected_output": "",
"task_finish_time": 1649410089047,
"task_name": "judger.judgetask.Judge",
"finished": true,
"status_msg": "Accepted",
"state": "SUCCESS",
"fast_submit": false,
"total_correct": 16,
"total_testcases": 16,
"submission_id": "296871548",
"runtime_percentile": 100,
"status_memory": "41.6 MB",
"memory_percentile": 48.99469999999997,
"pretty_lang": "Java"
}
# 编译出错
{
"status_code": 20,
"lang": "java",
"run_success": false,
"compile_error": "Line 16: error: reached end of file while parsing",
"full_compile_error": "Line 16: error: reached end of file while parsing\n}\n ^",
"status_runtime": "N/A",
"memory": 0,
"question_id": "142",
"task_finish_time": 1649410107119,
"elapsed_time": 0,
"task_name": "judger.judgetask.Judge",
"finished": true,
"status_msg": "Compile Error",
"state": "SUCCESS",
"fast_submit": false,
"total_correct": null,
"total_testcases": null,
"submission_id": "296871728",
"runtime_percentile": null,
"status_memory": "N/A",
"memory_percentile": null,
"pretty_lang": "Java"
}
# 解答错误
{
"status_code": 11,
"lang": "java",
"run_success": true,
"status_runtime": "N/A",
"memory": 42788000,
"display_runtime": "0",
"question_id": "142",
"elapsed_time": 150,
"compare_result": "0101100000000000",
"code_output": "tail connects to node index 0",
"std_output": "",
"last_testcase": "[3,2,0,-4]\n1",
"expected_output": "tail connects to node index 1",
"task_finish_time": 1649410173548,
"task_name": "judger.judgetask.Judge",
"finished": true,
"status_msg": "Wrong Answer",
"state": "SUCCESS",
"fast_submit": false,
"total_correct": 3,
"total_testcases": 16,
"submission_id": "296872413",
"runtime_percentile": null,
"status_memory": "N/A",
"memory_percentile": null,
"pretty_lang": "Java",
"input_formatted": "[3,2,0,-4], 1",
"input": "[3,2,0,-4]\n1"
}
定义LeetCode常量
public interface LeetCodeConstants {
/**
* 基础路由
*/
String BASIC_URI = "https://leetcode-cn.com";
/**
* Cookie
*/
String COOKIE = "";
编写请求的测试用例
@Slf4j
@SpringBootTest
public class LeetCodeTest {
String template = """
===============================================================
提交结果 执行用时 内存消耗 语言 提交时间
%s %s ms %s %s %s
===============================================================
""";
/**
* Gson和FastJson数据转换的坑
* problem: https://blog.csdn.net/JoeBig7/article/details/90233358?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_aa&utm_relevant_index=2
*/
@Test
public void testSubmitQuestion() {
String json = "{\n" +
" "question_id": "142",\n" +
" "lang": "java",\n" +
" "typed_code": "/**\n * Definition for singly-linked list.\n * class ListNode {\n * int val;\n * ListNode next;\n * ListNode(int x) {\n * val = x;\n * next = null;\n * }\n * }\n */\npublic class Solution {\n public ListNode detectCycle(ListNode head) {\n if (head == null) return null;\n ListNode fast = head, slow = head;\n while (fast != null && fast.next != null) {\n slow = slow.next;\n fast = fast.next.next;\n if (fast == slow) {\n break;\n }\n }\n // 上面的代码类似 hasCycle 函数\n if (fast == null || fast.next == null) {\n // fast 遇到空指针说明没有环\n return null;\n }\n // 将快指针置回头部,慢指针每次走一步,快指针也每次走一步,直到相遇\n fast = head;\n // 快慢指针同步前进,相交点就是环起点\n while (fast != slow) {\n fast = fast.next;\n slow = slow.next;\n }\n return fast;\n }\n}",\n" +
" "test_mode": false,\n" +
" "test_judger": "",\n" +
" "questionSlug": "linked-list-cycle-ii"\n" +
"}";
// 题目名称
String problem = "linked-list-cycle-ii";
// 发送http请求
String submitJson = HttpClient.textBody(LeetCodeConstants.BASIC_URI + "/problems/" + problem + "/submit/")
.json(json)
.header("cookie", LeetCodeConstants.COOKIE)
.header("origin", LeetCodeConstants.BASIC_URI)
.asString();
JSON.DEFAULT_PARSER_FEATURE &= ~Feature.UseBigDecimal.getMask();
Map<?, ?> submitMap = JSON.parseObject(submitJson, Map.class);
String submissionId = String.valueOf(submitMap.get("submission_id"));
System.out.println(submissionId);
String statusCode;
Map<?, ?> checkMap;
do {
String checkJson = HttpClient.get(LeetCodeConstants.BASIC_URI + "/submissions/detail/" + submissionId + "/check/")
.header("cookie", LeetCodeConstants.COOKIE)
.header("origin", LeetCodeConstants.BASIC_URI)
.asString();
checkMap = JSON.parseObject(checkJson, Map.class);
statusCode = String.valueOf(checkMap.get("status_code"));
System.out.println(statusCode);
} while (!statusCode.equals("10"));
System.out.println(checkMap);
System.out.println("======================");
String result = String.valueOf(checkMap.get("state"));
Integer displayRuntime = Integer.valueOf(String.valueOf(checkMap.get("display_runtime")));
String statusMemory = String.valueOf(checkMap.get("status_memory"));
String lang = String.valueOf(checkMap.get("lang"));
long taskFinishTime = Long.parseLong(String.valueOf(checkMap.get("task_finish_time")));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String taskFinishTimeStr = sdf.format(new Date(taskFinishTime));
System.out.println(String.format(template, result, displayRuntime, statusMemory, lang, taskFinishTimeStr, submissionId));
System.out.println("======================");
}
}
定义提交检查指令
想实现的效果
check_leetcode_problem reverse-linked-list #
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null) return null;
ListNode fast = head, slow = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (fast == slow) {
break;
}
}
// 上面的代码类似 hasCycle 函数
if (fast == null || fast.next == null) {
// fast 遇到空指针说明没有环
return null;
}
// 将快指针置回头部,慢指针每次走一步,快指针也每次走一步,直到相遇
fast = head;
// 快慢指针同步前进,相交点就是环起点
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
#
定义QQ机器指令: check_leetcode_problem\s(?.{1,100})\s#(?[\s\S]+)#$
测试指令
@Slf4j
@Component("simpleBotLeetCodeEvent")
public class SimpleBotLeetCodeEvent {
@Value("${qq.owner}")
private String ownerCode;
@Value("${qq.group}")
private String groupCode;
@OnPrivate
@Filter(value = "check_leetcode_problem\s(?<problem>.{1,100})\s#(?<code>[\s\S]+)#$", matchType = MatchType.REGEX_MATCHES, trim = true)
public void doPrivateMsg(PrivateMsg event, MsgSender sender, @FilterValue("problem") String problem, @FilterValue("code") String code) {
AccountInfo accountInfo = event.getAccountInfo();
if (ownerCode.equals(accountInfo.getAccountCode())) {
System.out.println(code);
System.out.println(problem);
}
}
}
完成指令调用API-编译成功情况
@Slf4j
@Component("simpleBotLeetCodeEvent")
public class SimpleBotLeetCodeEvent {
@Value("${qq.owner}")
private String ownerCode;
@Value("${qq.group}")
private String groupCode;
@OnPrivate
@Filter(value = "check_leetcode_problem\s(?<problem>.{1,100})\s#(?<code>[\s\S]+)#$", matchType = MatchType.REGEX_MATCHES, trim = true)
public void doPrivateMsg(PrivateMsg event, MsgSender sender, @FilterValue("problem") String problem, @FilterValue("code") String code) {
AccountInfo accountInfo = event.getAccountInfo();
if (ownerCode.equals(accountInfo.getAccountCode())) {
System.out.println(code);
System.out.println(problem);
Map<String, Object> submitRequestMap = new HashMap<>(8);
/**
* TODO
*/
submitRequestMap.put("question_id", "142");
submitRequestMap.put("lang", "java");
submitRequestMap.put("false", false);
submitRequestMap.put("test_judger", "amet ea ut laboris ad");
submitRequestMap.put("questionSlug", "problem");
submitRequestMap.put("typed_code", code);
// 发送http请求
String submitJson = HttpClient.textBody(LeetCodeConstants.BASIC_URI + "/problems/" + problem + "/submit/")
.json(JSON.toJSONString(submitRequestMap))
.header("cookie", LeetCodeConstants.COOKIE)
.header("origin", LeetCodeConstants.BASIC_URI)
.asString();
JSON.DEFAULT_PARSER_FEATURE &= ~Feature.UseBigDecimal.getMask();
Map<?, ?> submitMap = JSON.parseObject(submitJson, Map.class);
String submissionId = String.valueOf(submitMap.get("submission_id"));
String statusCode;
Map<?, ?> checkMap;
do {
String checkJson = HttpClient.get(LeetCodeConstants.BASIC_URI + "/submissions/detail/" + submissionId + "/check/")
.header("cookie", LeetCodeConstants.COOKIE)
.header("origin", LeetCodeConstants.BASIC_URI)
.asString();
checkMap = JSON.parseObject(checkJson, Map.class);
statusCode = String.valueOf(checkMap.get("status_code"));
System.out.println(statusCode);
} while (!statusCode.equals("10"));
String template = """
===============================================================
提交结果 执行用时 内存消耗 语言 提交时间
%s %s ms %s %s %s
===============================================================
""";
String result = String.valueOf(checkMap.get("state"));
Integer displayRuntime = Integer.valueOf(String.valueOf(checkMap.get("display_runtime")));
String statusMemory = String.valueOf(checkMap.get("status_memory"));
String lang = String.valueOf(checkMap.get("lang"));
long taskFinishTime = Long.parseLong(String.valueOf(checkMap.get("task_finish_time")));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String taskFinishTimeStr = sdf.format(new Date(taskFinishTime));
sender.SENDER.sendPrivateMsgAsync(ownerCode, String.format(template, result, displayRuntime, statusMemory, lang, taskFinishTimeStr, submissionId));
}
}
}