diff --git a/grade.html b/grade.html
new file mode 100644
index 0000000..c7f6701
--- /dev/null
+++ b/grade.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+ flapjs grading
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scripts/compute.js b/scripts/compute.js
index 3b7b6f3..ba0f693 100644
--- a/scripts/compute.js
+++ b/scripts/compute.js
@@ -393,7 +393,7 @@ function* run_input_Moore(graph, input, interactive) {
* @param {string} input - input string
* @param {boolean} interactive - whether to step through and highlight the computation
* @returns {Iterable} return a generator that
- * if noninteractive, evaluates to the final accept/reject immediately in one step
+ * if noninteractive, evaluates to the final accept/reject immediately in one step
* if interactive, evaluates step by step with highlight
*/
export function run_input(graph, machine_type, input, interactive=false) {
diff --git a/scripts/grade.js b/scripts/grade.js
new file mode 100644
index 0000000..414b045
--- /dev/null
+++ b/scripts/grade.js
@@ -0,0 +1,109 @@
+/** @module grade */
+
+import * as compute from './compute.js';
+import * as permalink from './permalink.js';
+
+// if not in browser, don't run
+if (typeof document !== 'undefined') {
+ const cur_file_path = window.location.pathname;
+ if (cur_file_path.includes('grade.html')) {
+ document.addEventListener('DOMContentLoaded', init);
+ }
+}
+
+let test_cases = [];
+let graph = {};
+
+function display_test_cases(test_cases) {
+ const test_cases_display_area = document.getElementById('display_test_cases');
+ while (test_cases_display_area.childElementCount) { // wipe all elements
+ test_cases_display_area.removeChild(test_cases_display_area.firstChild);
+ }
+ for (const [input_string, accepted] of test_cases) {
+ const test_case_div = document.createElement('div');
+ const test_string_span = document.createElement('span');
+ const test_result_span = document.createElement('span');
+ test_result_span.className = 'result_class';
+ test_result_span.id = `${input_string}_result`;
+ test_string_span.innerText = input_string;
+ test_result_span.innerText = accepted ? 'accepted' : 'rejected';
+ test_case_div.appendChild(test_string_span);
+ test_case_div.appendChild(test_result_span);
+ test_cases_display_area.appendChild(test_case_div);
+ }
+}
+
+/**
+ * given test cases as plain text, parse the document and store the results in `test_cases`
+ * @param {string} text - a string consisting of lines of input. every two line specify a test case, with
+ * the first line being the input string and the second line being accept/reject
+ */
+function parse_test_cases(text) {
+ test_cases = []; // clear
+ const lines = text.trimEnd().split('\n') // if the file ends with a new line, remove it
+ if (lines.length & 1) {
+ alert('invalid test file: odd number of lines');
+ return;
+ }
+ for (let i = 0; i < lines.length; i+=2) {
+ let accepted;
+ switch (lines[i+1]) {
+ case 'accepted':
+ accepted = true;
+ break;
+ case 'rejected':
+ accepted = false;
+ break;
+ default:
+ alert('invalid test file: keywords other than "accepted" or "rejected"');
+ return;
+ }
+ test_cases.push([lines[i], accepted]);
+ }
+ display_test_cases(test_cases);
+}
+
+function test_all_cases() {
+ const url_input = document.getElementById('machine_url');
+ const url = url_input.value;
+ const graph_str = url.substring(url.indexOf('#')+1);
+ let type, graph;
+ try {
+ [type, graph] = permalink.deserialize(graph_str);
+ } catch {
+ alert('invalid graph')
+ return;
+ }
+
+ for (const [input_string, expected] of test_cases) {
+ // eslint-disable-next-line no-unused-vars
+ const { value: actual, _ } = compute.run_input(graph, type, input_string).next();
+ const color = (expected == actual) ? 'green' : 'red';
+ const input_string_result = document.getElementById(`${input_string}_result`);
+ input_string_result.style.background = color;
+ }
+}
+
+function upload_test_cases() {
+ const test_case_uploader = document.getElementById('test_cases');
+ const fr = new FileReader();
+ fr.onload = () => parse_test_cases(fr.result);
+ if (test_case_uploader.files.length) {
+ fr.readAsText(test_case_uploader.files[0])
+ }
+}
+
+function init() {
+ const test_case_uploader = document.getElementById('test_cases');
+ test_case_uploader.addEventListener('change', upload_test_cases);
+ const start_test_btn = document.getElementById('start_test');
+ start_test_btn.addEventListener('click', test_all_cases);
+ const url_input = document.getElementById('machine_url');
+ url_input.addEventListener('click', () => {
+ for (const elem of document.getElementsByClassName('result_class')) {
+ if (elem.style.background) {
+ elem.style.background = '';
+ }
+ }
+ });
+}
diff --git a/scripts/index.js b/scripts/index.js
index f89494e..ef1cf0a 100644
--- a/scripts/index.js
+++ b/scripts/index.js
@@ -13,11 +13,15 @@ import * as ui_setup from './ui_setup.js';
// if not in browser, don't run
if (typeof document !== 'undefined') {
- document.addEventListener('DOMContentLoaded', init);
- window.addEventListener('resize', () => drawing.draw(graph));
+ // get current page
+ const cur_file_path = window.location.pathname;
+ if (!cur_file_path.includes('grade.html')) {
+ document.addEventListener('DOMContentLoaded', init);
+ window.addEventListener('resize', () => drawing.draw(graph));
+ }
}
-let graph = {}; // global graph
+let graph = {}; // global graph, initially empty
/** handles double click */
function bind_double_click() {
@@ -415,7 +419,7 @@ function init() {
bind_dd();
bind_permalink();
bind_mousemove();
- ui_setup.bind_plus_minus();
+ ui_setup.bind_plus_minus(``);
ui_setup.add_input_bar(); // called so one input bar appears on opening of homepage
ui_setup.htmlSetUp(); // initiate eventlisteners for sidenavbar, second sidenavbar, and popup tutorial
init_graph(); // leave this last since we want it to override some of the above
diff --git a/styles/grade.css b/styles/grade.css
new file mode 100644
index 0000000..6ddb935
--- /dev/null
+++ b/styles/grade.css
@@ -0,0 +1,4 @@
+#display_test_cases > div {
+ display: flex;
+ justify-content: space-between;
+}
diff --git a/test_cases.txt b/test_cases.txt
new file mode 100644
index 0000000..9f81c38
--- /dev/null
+++ b/test_cases.txt
@@ -0,0 +1,10 @@
+101
+rejected
+01
+accepted
+
+accepted
+0011
+accepted
+00111
+rejected
\ No newline at end of file