package org.psjava.judgesubmit; import org.psjava.ds.map.KeysInMap; import org.psjava.ds.map.Map; import org.psjava.ds.map.MutableMap; import org.psjava.ds.set.Set; import org.psjava.ds.set.SetFromIterable; import org.psjava.goods.GoodMutableMapFactory; import org.puredevteam.httpclient.SocketConnectionData; import java.io.IOException; import java.util.TreeMap; class TJU implements JudgeSite { public static final String ENCODING = "UTF-8"; public static final SocketConnectionData CONNECTION_DATA = new SocketConnectionData(false, "acm.tju.edu.cn", 80); @Override public String getName() { return "Tianjin University Online Judge"; } @Override public SocketConnectionData getSocketConnectionData() { return CONNECTION_DATA; } @Override public Set<Language> getSupportedLanguageSet() { return SetFromIterable.create(KeysInMap.get(getLanguageMap())); } @Override public Submitter getSubmitter() { return new Submitter() { @Override public String submitAndGetId(JudgeHttpClient hc, String problemId, String userId, String password, Language language, String sourceCode) throws IOException, InvalidInputException, SiteParsingException, JudgeServiceException { int lastSubmitIdOrZero = receiveLastSubmitIdOrZero(hc, userId); submit(hc, problemId, userId, password, language, sourceCode); int newId = receiveLastSubmitIdOrZero(hc, userId); SiteParsingUtil.assertTrue(newId != lastSubmitIdOrZero); return newId + ""; } private void submit(JudgeHttpClient hc, String problemId, String userId, String password, Language language, String sourceCode) throws IOException, JudgeServiceException, InvalidInputException, SiteParsingException { TreeMap<String, String> param = new TreeMap<String, String>(); param.put("user_id", userId); param.put("passwd", password); param.put("prob_id", problemId); param.put("language", getLanguageMap().get(language)); param.put("source", sourceCode + "\n"); String html = hc.receivePostBodyString("/toj/submit_process.php", param, ENCODING); if (html.contains("Invalid password!") || html.contains("No such user!")) throw InvalidLogInDataException.create(""); if (!html.contains("Your source code has been submitted")) throw new InvalidInputException(SiteParsingUtil.extractMiddleString(html, 0, "<H1><center>", "</center><br>")); } }; } public static int receiveLastSubmitIdOrZero(JudgeHttpClient client, String userId) throws IOException, SiteParsingException, JudgeServiceException { String html = client.receiveGetBodyString("/toj/status.php?user=" + userId, ENCODING); String start = "height=30><td>"; if(!html.contains(start)) return 0; return SiteParsingUtil.parseInt(SiteParsingUtil.extractMiddleString(html, 0, start, "</td>")); } private static Map<Language, String> getLanguageMap() { MutableMap<Language, String> map = GoodMutableMapFactory.getInstance().create(); map.put(Language.JAVA, "2"); map.put(Language.CPP, "1"); map.put(Language.C, "0"); return map; } @Override public SubmitStatusReceiver getSubmitStatusReceiver() { return new SubmitStatusReceiver() { @Override public SubmitStatus receive(JudgeHttpClient client, String submitId) throws IOException, SiteParsingException, InvalidInputException, JudgeServiceException { String html = client.receiveGetBodyString("/toj/status.php?start=" + submitId, ENCODING); String part = SiteParsingUtil.extractMiddleString(html, 0, "<tr align=center height=30>", "<tr align=center height=30>"); String[] lines = part.split("\n"); SubmitStatusCode code = getCode(lines[1]); SiteParsingUtil.assertTrue(lines.length == 5); String timeString = SiteParsingUtil.extractMiddleString(lines[3], 10, "<td>", "<"); int min = SiteParsingUtil.parseInt(SiteParsingUtil.extractMiddleString(timeString, 0, "", "'")); int sec = SiteParsingUtil.parseInt(SiteParsingUtil.extractMiddleString(timeString, 0, "'", ".")); int csec = SiteParsingUtil.parseInt(SiteParsingUtil.extractMiddleString(timeString, 0, ".", "\"")); long time = min * 60 * 1000 + sec * 1000 + csec * 10; long mem = SiteParsingUtil.parseInt(SiteParsingUtil.extractMiddleString(lines[4], 0, "<td>", "K")) * 1024L; return new SubmitStatus(0, code, mem, time, null); } }; } private static SubmitStatusCode getCode(String judgeString) throws SiteParsingException { if (judgeString.indexOf("Accepted") != -1) { return SubmitStatusCode.ACCEPTED; } else if (judgeString.indexOf("Presentation Error") != -1) { return SubmitStatusCode.PRESENTATION_ERROR; } else if (judgeString.indexOf("Runtime Error") != -1) { return SubmitStatusCode.RUNTIME_ERROR; } else if (judgeString.indexOf("Wrong Answer") != -1) { return SubmitStatusCode.WRONG_ANSWER; } else if (judgeString.indexOf("Time Limit") != -1) { return SubmitStatusCode.TIME_LIMIT_EXCEED; } else if (judgeString.indexOf("Memory Limit") != -1) { return SubmitStatusCode.MEMORY_LIMITE_EXCEED; } else if (judgeString.indexOf("Running") != -1) { return SubmitStatusCode.RUNNING; } else if (judgeString.indexOf("Output Limit") != -1) { return SubmitStatusCode.OUTPUT_LIMIT_EXCEED; } else if (judgeString.indexOf("Restricted Function") != -1) { return SubmitStatusCode.RESTRICTED_FUNCTION; } else if (judgeString.indexOf("Compilation Error") != -1) { return SubmitStatusCode.COMPILE_ERROR; } else if (judgeString.indexOf("Compiling") != -1) { return SubmitStatusCode.COMPILING; } else if (judgeString.indexOf("Judging") != -1) { return SubmitStatusCode.JUDGING; } else if (judgeString.indexOf("Internal Error ") != -1) { return SubmitStatusCode.SYSTEM_ERROR; } else { throw new SiteParsingException("Unknown TJU Judge Status Code (" + judgeString + ")"); } } @Override public CompileErrorMessageReceiver getCompileErrorMessageReceiver() { return new CompileErrorMessageReceiver() { @Override public String receive(JudgeHttpClient client, String id, String password, String submitId) throws IOException, SiteParsingException, InvalidInputException, JudgeServiceException { String html = client.receiveGetBodyString("/toj/show_cerror.php?id=" + submitId, ENCODING); String msg = SiteParsingUtil.extractMiddleString(html, 0, "<pre>", "</pre>").trim(); return msg; } }; } }