Skip to content

Commit

Permalink
[Release] Added Interactive (Partial)
Browse files Browse the repository at this point in the history
  • Loading branch information
leomotors committed Feb 27, 2022
1 parent 7d8db6b commit 89edc6f
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 31 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ All notable changes to Kawaii Cocoa Grader will be documented here

Changelog before 0.2.2 will not be noted here

## [1.0.4] - 2022-02-24
## [1.1.0] - 2022-02-27

- Added Interactive (Partial Support)

## [1.0.4] - 2022-02-25

- Implemented features in Cocoa Discord Utils 1.0.0 *(forgot to do that in previous version)*

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cocoa-grader",
"version": "1.0.4",
"version": "1.1.0",
"description": "Discord Bot Grader",
"main": "dist/bot/client.js",
"repository": "https://github.com/Leomotors/cocoa-grader",
Expand All @@ -19,7 +19,7 @@
"dependencies": {
"@discordjs/builders": "^0.12.0",
"chalk": "^5.0.0",
"cocoa-discord-utils": "^1.1.0-rc.1",
"cocoa-discord-utils": "^1.1.0-rc.2",
"discord.js": "^13.6.0",
"dotenv": "^16.0.0",
"node-fetch": "^3.2.0",
Expand All @@ -31,7 +31,7 @@
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^5.12.1",
"@typescript-eslint/parser": "^5.12.1",
"eslint": "^8.9.0",
"eslint": "^8.10.0",
"prettier": "^2.5.1",
"rimraf": "^3.0.2",
"typescript": "^4.5.5"
Expand Down
4 changes: 3 additions & 1 deletion src/bot/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ client.on("ready", (cli) => {
useActivityGroup(client, groupLoader);
});

new ConsoleManager().useLogout(client).useReload(groupLoader);
new ConsoleManager().useLogout(client).useReload(groupLoader, () => {
loadProblems();
});

checkLogin(client, process.env.DISCORD_TOKEN);
17 changes: 13 additions & 4 deletions src/bot/commands/message/submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import fetch from "node-fetch";

import { getLang, supportedLang } from "../../../grader/compile";
import Grade, { Verdict } from "../../../grader/grader";
import { problemExists } from "../../../grader/problems";
import { isInteractive, problemExists } from "../../../grader/problems";
import { Cocoa, style } from "../../shared";

function EmbedGen(msg: Message, result: Verdict, perf: number, lang: string) {
Expand All @@ -17,7 +17,13 @@ function EmbedGen(msg: Message, result: Verdict, perf: number, lang: string) {
.use(msg)
.setTitle(pb.title)
.setDescription(
`Description: ${pb.description}\nTime Limit: ${pb.timelimit} seconds\nMemory Limit: ${pb.memorylimit} MB\nSubmission Status: **${result.status}**\nSubtasks Verdict: [${result.subtasks}]`
`Description: ${pb.description}\nTime Limit: ${
pb.timelimit
} seconds\nMemory Limit: ${pb.memorylimit} MB\nType: ${
pb.type ?? "normal"
}\nSubmission Status: **${result.status}**\nSubtasks Verdict: [${
result.subtasks
}]`
)
.setThumbnail(
result.status == "Accepted" ? Cocoa.GIF.ThumbsUp : Cocoa.GIF.NoPoi
Expand Down Expand Up @@ -124,10 +130,13 @@ export const submit: CocoaMessage = {
return;
}

const lang = getLang(userLang);
const isInter = isInteractive(problem);
const lang = getLang(userLang, isInter);
if (lang == "Unsupported") {
await msg.reply(
`Unsupported Language! The supported languages are ${supportedLang}`
isInter
? "Unsupported Language! The only supported language for Interactive is C++"
: `Unsupported Language! The supported languages are ${supportedLang}`
);
return;
}
Expand Down
5 changes: 5 additions & 0 deletions src/bot/commands/slash/getstatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ export const getstatement: CocoaSlash = {
value: `${Problem.memorylimit} MB`,
inline: true,
},
{
name: "Type",
value: Problem.type ?? "normal",
inline: true,
},
{
name: "Subtasks",
value: `${Object.keys(Problem.subtasks).length}`,
Expand Down
37 changes: 36 additions & 1 deletion src/grader/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const supportedLang = [
] as const;
export type SupportedLang = typeof supportedLang[number];

export function getLang(str: string): SupportedLang | "Unsupported" {
function _getLang(str: string): SupportedLang | "Unsupported" {
if (str == "cpp" || str == "c++" || str == "cc") return "C++";
if (str == "c") return "C";
if (str == "hs" || str == "haskell") return "Haskell";
Expand All @@ -21,6 +21,19 @@ export function getLang(str: string): SupportedLang | "Unsupported" {
return "Unsupported";
}

export function getLang(
str: string,
isInteractive: boolean
): SupportedLang | "Unsupported" {
const lang = _getLang(str);

if (isInteractive) {
if (lang != "C++") return "Unsupported";
}

return lang;
}

const extensions = {
C: "c",
"C++": "cpp",
Expand Down Expand Up @@ -68,6 +81,28 @@ export async function Compile(
return true;
}

export async function CompileInteractive(
problem: string,
content: string,
id: string
): Promise<boolean> {
try {
await writeFile(`temp/${id}.cpp`, content);
} catch (error) {
console.log(chalk.red(`ERROR while writing file: ${error}`));
return false;
}

try {
await exec(
`g++ problems/${problem}/public/grader.cpp temp/${id}.cpp -Iproblems/${problem}/public -o temp/${id} -std=c++17 -O2 -lm`
);
return true;
} catch (error) {
return false;
}
}

export function getECmd(lang: keyof typeof extensions, id: string) {
if (lang == "JavaScript") return `node ./temp/${id}.js`;
if (lang == "Python") return `python3 ./temp/${id}.py`;
Expand Down
43 changes: 35 additions & 8 deletions src/grader/grader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { promisify } from "util";
import { v4 as uuid } from "uuid";

import { check } from "./check";
import { Compile, getECmd, SupportedLang } from "./compile";
import { Compile, CompileInteractive, getECmd, SupportedLang } from "./compile";
import { getProblems, Problem } from "./problems";
import { numberToAlphabet, shortenVerdicts } from "./utils";

Expand All @@ -28,7 +28,7 @@ export const VerdictDict = {
"Runtime Error": "x",
};

export type CaseVerdict = keyof typeof VerdictDict;
export type CaseVerdict = keyof typeof VerdictDict | number;

export default async function Grade(
problemID: string,
Expand All @@ -47,7 +47,10 @@ export default async function Grade(
mem: 0,
};

const res = await Compile(lang, code, submissionId);
const res =
problem.type == "interactive"
? await CompileInteractive(problemID, code, submissionId)
: await Compile(lang, code, submissionId);
if (!res) {
console.log(`${tag} Graded ${problem.title} [COMPILATION ERROR]`);
return {
Expand All @@ -60,6 +63,7 @@ export default async function Grade(
};
}

const isInteractive = problem.type == "interactive";
let totalScore = 0;
const ecmd = getECmd(lang, submissionId);
const subtaskVerdicts: string[] = [];
Expand All @@ -74,8 +78,17 @@ export default async function Grade(
limits
);

totalScore += subtaskVerdict == "Correct Answer" ? subtaskScore : 0;
subtaskVerdicts.push(VerdictDict[subtaskVerdict]);
totalScore +=
isInteractive && typeof subtaskVerdict == "number"
? subtaskVerdict
: subtaskVerdict == "Correct Answer"
? subtaskScore
: 0;
subtaskVerdicts.push(
typeof subtaskVerdict == "number"
? ` ${subtaskVerdict} `
: VerdictDict[subtaskVerdict]
);
continue;
}

Expand All @@ -92,9 +105,17 @@ export default async function Grade(
limits
);

subtasksScore += subtaskVerdict == "Correct Answer" ? subtask : 0;
subtasksScore +=
isInteractive && typeof subtaskVerdict == "number"
? subtaskVerdict
: subtaskVerdict == "Correct Answer"
? subtask
: 0;
maxsubtaskScore += subtask;
subtasksVerdict += VerdictDict[subtaskVerdict];
subtasksVerdict +=
typeof subtaskVerdict == "number"
? ` ${subtaskVerdict} `
: VerdictDict[subtaskVerdict];
}

subtaskVerdicts.push(`[${subtasksVerdict}]`);
Expand All @@ -108,7 +129,7 @@ export default async function Grade(
return {
status:
totalScore == (problem.maxScore ?? 100) ? "Accepted" : "Rejected",
score: totalScore,
score: Math.floor(totalScore * 100) / 100,
problem,
subtasks: subtaskStr,
submissionId,
Expand Down Expand Up @@ -140,6 +161,12 @@ async function GradeCase(
if (toTok[0] == "TIMEOUT") return "Time Limit Exceeded";
if (toTok[0] != "FINISHED") return "Runtime Error";

if (problem.type == "interactive") {
const casted = +runRes.stdout;

return isNaN(casted) ? 0 : casted;
}

if (
await check(runRes.stdout, `${caseloc}.out`, problem.compare ?? "W")
) {
Expand Down
7 changes: 7 additions & 0 deletions src/grader/problems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ export interface Subtask {
scores: number[];
}

export const ProblemTypes = ["normal", "interactive"] as const;

export interface Problem {
title: string;
description: string;
// * Time Limit in Seconds
timelimit: number;
// * Memory Limit in MB
memorylimit: number;
type?: typeof ProblemTypes[number];
subtasks: { [name: string]: number | Subtask };
// * Default = 100
// TODO Auto Infer maxScore from subtasks
Expand Down Expand Up @@ -67,3 +70,7 @@ export function getProblems(id: string) {
export function problemExists(id: string): boolean {
return id in problemsList;
}

export function isInteractive(id: string) {
return getProblems(id).type == "interactive";
}
26 changes: 13 additions & 13 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,10 @@
resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.4.0.tgz#b6488286a1cc7b41b644d7e6086f25a1c1e6f837"
integrity sha512-zmjq+l/rV35kE6zRrwe8BHqV78JvIh2ybJeZavBi5NySjWXqN3hmmAKg7kYMMXSeiWtSsMoZ/+MQi0DiQWy2lw==

"@eslint/eslintrc@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.1.0.tgz#583d12dbec5d4f22f333f9669f7d0b7c7815b4d3"
integrity sha512-C1DfL7XX4nPqGd6jcP01W9pVM1HYCuUkFk1432D7F0v3JSlUIeOYn9oCoi3eoLZ+iwBSb29BMFxxny0YrrEZqg==
"@eslint/eslintrc@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.0.tgz#7ce1547a5c46dfe56e1e45c3c9ed18038c721c6a"
integrity sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
Expand Down Expand Up @@ -561,10 +561,10 @@ chalk@^5.0.0:
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.0.tgz#bd96c6bb8e02b96e08c0c3ee2a9d90e050c7b832"
integrity sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ==

cocoa-discord-utils@^1.1.0-rc.1:
version "1.1.0-rc.1"
resolved "https://registry.yarnpkg.com/cocoa-discord-utils/-/cocoa-discord-utils-1.1.0-rc.1.tgz#f2871f4e4eb3e31bc5074e43c1c7b965caa4b360"
integrity sha512-suWLc9HYgItxUaVHNpuc+q2kt3CJXQW7MDHGJXpjoE6xQSY01VC8iGrBkczrhZDAVZ6Y8e5fmrerN2KunjEF8w==
cocoa-discord-utils@^1.1.0-rc.2:
version "1.1.0-rc.2"
resolved "https://registry.yarnpkg.com/cocoa-discord-utils/-/cocoa-discord-utils-1.1.0-rc.2.tgz#e575af174c270e8f44e07662520101ebc31039e0"
integrity sha512-2hoY71DXy+mCNucb1KgAtPr9SxRXQHITJvCJBIpDMJPQspg8Wijp3PFL1NE6ZpjIDCTn9LkdmHYu0xiaJNxYtA==
dependencies:
"@discordjs/builders" "^0.12.0"
chalk "4.1.2"
Expand Down Expand Up @@ -747,12 +747,12 @@ eslint-visitor-keys@^3.3.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==

eslint@^8.9.0:
version "8.9.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.9.0.tgz#a2a8227a99599adc4342fd9b854cb8d8d6412fdb"
integrity sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q==
eslint@^8.10.0:
version "8.10.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.10.0.tgz#931be395eb60f900c01658b278e05b6dae47199d"
integrity sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw==
dependencies:
"@eslint/eslintrc" "^1.1.0"
"@eslint/eslintrc" "^1.2.0"
"@humanwhocodes/config-array" "^0.9.2"
ajv "^6.10.0"
chalk "^4.0.0"
Expand Down

0 comments on commit 89edc6f

Please sign in to comment.