From bc5e6c9b7df92dcf3aa46b70b55c2428ee4b710a Mon Sep 17 00:00:00 2001 From: him6794 <105898333+him6794@users.noreply.github.com> Date: Sun, 16 Mar 2025 01:56:08 +0800 Subject: [PATCH] Add files via upload --- __pycache__/back.cpython-312.pyc | Bin 0 -> 14053 bytes app2.py | 160 +++++++------ back.py | 382 +++++++++++++++---------------- requirements.txt | 4 + static/css/styles.css | 176 ++++++++++++++ static/js/script.js | 240 +++++++++++++++++++ templates/index2.html | 98 ++++++++ 7 files changed, 803 insertions(+), 257 deletions(-) create mode 100644 __pycache__/back.cpython-312.pyc create mode 100644 requirements.txt create mode 100644 static/css/styles.css create mode 100644 static/js/script.js create mode 100644 templates/index2.html diff --git a/__pycache__/back.cpython-312.pyc b/__pycache__/back.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..85c08c1e2ef671de72ffa048f9af546741b3cdcc GIT binary patch literal 14053 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 literal 0 HcmV?d00001 diff --git a/app2.py b/app2.py index df942c8..db491ea 100644 --- a/app2.py +++ b/app2.py @@ -1,112 +1,142 @@ -import sys -import back -from flask import Flask, request, jsonify, send_from_directory +from flask import Flask, request, jsonify, send_from_directory, render_template from io import StringIO from multiprocessing import Process, Queue +import sys +import back import time - -app = Flask(__name__, template_folder='templates') +from threading import Thread +app = Flask(__name__) sessions = {} # 存放執行中的程式狀態 - class InputNeeded(Exception): - """ 自定義異常,用於標記需要輸入的情況 """ pass +class OutputWrapper: + def __init__(self, output_queue): + self.output_queue = output_queue + + def write(self, text): + if text.strip(): # 避免空內容 + self.output_queue.put({"output": text}) + + def flush(self): + pass + class InputMock: - """ 模擬 input() 來攔截 back.py 的輸入 """ def __init__(self, input_queue, output_queue): - self.input_queue = input_queue # 用於接收主進程的輸入 - self.output_queue = output_queue # 用於通知主進程需要輸入 + self.input_queue = input_queue + self.output_queue = output_queue def readline(self): - """ 模擬 input(),若無輸入則通知主進程並等待 """ self.output_queue.put({"needsInput": True}) - user_input = self.input_queue.get() # 等待主進程提供輸入 - return user_input + '\n' + return self.input_queue.get() + '\n' def run_in_process(session_id, code, input_queue, output_queue): - """ 在子進程中執行程式碼 """ sys.stdin = InputMock(input_queue, output_queue) - sys.stdout = StringIO() + sys.stdout = OutputWrapper(output_queue) try: executor = back.Executor() executor.execute(code) - output = sys.stdout.getvalue() - output_queue.put({"output": output, "completed": True}) + output_queue.put({"completed": True}) except InputNeeded: - output = sys.stdout.getvalue() - output_queue.put({"output": output, "needsInput": True}) + pass except Exception as e: output_queue.put({"output": str(e), "completed": True}) finally: sys.stdout = sys.__stdout__ sys.stdin = sys.__stdin__ +def output_listener(session_id, output_queue): + session = sessions[session_id] + while True: + try: + msg = output_queue.get(timeout=0.1) + if 'output' in msg: + session["output_buffer"] += msg["output"] + if 'needsInput' in msg: + print("needsInput", msg) + session["needs_input"] = True + # 這裡不跳出循環,繼續監聽 + if 'completed' in msg: + session["completed"] = True + break + except Exception as e: + if session['process'].exitcode is not None: + break + # 這裡加入一個小延遲,避免過度消耗CPU + time.sleep(0.01) + @app.route('/') def serve_index(): - return send_from_directory('templates', 'index2.html') + return render_template('index2.html') @app.route('/run', methods=['POST']) def run_code(): - """ 開始執行程式 """ - session_id = str(len(sessions)) # 產生唯一的 session ID - input_queue = Queue() # 子進程接收輸入的隊列 - output_queue = Queue() # 子進程發送結果的隊列 + session_id = str(len(sessions)) + input_queue = Queue() + output_queue = Queue() - # 儲存會話資訊 sessions[session_id] = { - "code": request.json['code'], - "output": "", + "output_buffer": "", # 用於儲存輸出內容 "input_queue": input_queue, "output_queue": output_queue, - "completed": False + "process": None, + "completed": False, + "needs_input": False } - # 啟動子進程 - process = Process(target=run_in_process, args=(session_id, sessions[session_id]["code"], input_queue, output_queue)) - sessions[session_id]["process"] = process - process.start() - - # 等待子進程的初步結果 - result = output_queue.get() - sessions[session_id]["output"] += result.get("output", "") - if result.get("completed", False): - sessions[session_id]["completed"] = True - process.join() # 清理已完成的進程 - del sessions[session_id]["process"] - - return jsonify({ - "sessionId": session_id, - "output": sessions[session_id]["output"], - "needsInput": result.get("needsInput", False) - }) + p = Process(target=run_in_process, args=(session_id, request.json['code'], input_queue, output_queue)) + sessions[session_id]["process"] = p + p.start() + + # 啟動輸出監聽線程 + listener_thread = Thread(target=output_listener, args=(session_id, output_queue)) + listener_thread.daemon = True # 設置為daemon thread,主程序結束時會自動終止 + listener_thread.start() + sessions[session_id]["listener_thread"] = listener_thread # 保存線程引用以便後續管理 + + return jsonify({"sessionId": session_id}) + +@app.route('/status/') +def get_status(session_id): + session = sessions.get(session_id) + if not session: + return jsonify({"error": "Session not found"}), 404 + + response = { + "output": session["output_buffer"], + "needsInput": session["needs_input"], + "completed": session["completed"] + } + + session["output_buffer"] = "" # 清空緩衝 + + return jsonify(response) @app.route('/submit_input', methods=['POST']) def submit_input(): - """ 接收使用者的輸入並繼續執行 """ - session_id = request.json['sessionId'] - user_input = request.json['input'] + data = request.get_json() + print("Received input data:", data) + if not data or 'sessionId' not in data or 'input' not in data: + return jsonify({"error": "無效的請求格式"}), 400 + + session_id = data['sessionId'] + user_input = data['input'] if session_id not in sessions: - return jsonify({"error": "Session not found"}), 400 + return jsonify({"error": "Session 不存在"}), 404 session = sessions[session_id] - session["input_queue"].put(user_input) # 將輸入發送到子進程 - - # 等待子進程的結果 - result = session["output_queue"].get() - session["output"] += result.get("output", "") + + # 檢查session是否真的需要輸入 + if not session.get("needs_input", False): + print("Session doesn't need input currently") + return jsonify({"error": "當前不需要輸入"}), 401 - if result.get("completed", False): - session["completed"] = True - session["process"].join() # 清理進程 - del session["process"] + print("Submitting input:", user_input) + session["input_queue"].put(user_input) # 將輸入發送到子進程 + session["needs_input"] = False # 標記輸入已完成 - return jsonify({ - "sessionId": session_id, - "output": session["output"], - "needsInput": result.get("needsInput", False) - }) + return jsonify({"message": "輸入已提交"}) if __name__ == '__main__': - app.run(debug=True, host='0.0.0.0', port=5000, threaded=False) # 使用多進程時不需要 threaded=True + app.run(debug=True, host='0.0.0.0', port=5000, threaded=True) # 使用threaded模式以提高並發能力 \ No newline at end of file diff --git a/back.py b/back.py index 533b27c..cf00f34 100644 --- a/back.py +++ b/back.py @@ -1,58 +1,10 @@ KEYWORDS = {'加上', '減去', '乘以', '除以', '取模', '等於', '大於', '小於', '轉型'} -COMMANDS = {'要求在終端機(或控制台)輸出': (lambda x: print(evaluate(x))), - '設定一指定名稱變數的值,名稱與值分別為': (lambda x: assign_variable(x)), - '初始化一個指定名稱和長度的陣列,名稱和長度分別為': (lambda x: init_array(x)), - '設定指定名稱陣列其中一項的值,名稱、項數與值分別為': (lambda x: assign_array(x)), - '讀取使用者輸入字串,並儲存至變數': (lambda x: get_user_input(x))} IF = '如果右方判斷式結果為真,執行以下特定操作' WHILE = '重複並持續驗證右方表達式之真實性,條件滿足時持續執行特定操作' BREAK = '無視迴圈判斷式要求,直接跳脫迴圈' CONTINUE = '捨棄以下迴圈內容,直接繼續下一輪迴圈' EXIT = '無視所有指令,直接退出程式' -variables = {} -arrays = {} - -def assign_variable(expression: str): - global variables - split_result = expression.split(',') - if split_result[0][0] != '「' or split_result[0][-1] != '」' or len(split_result[0]) == 2: - raise ValueError('變數名稱有誤:'+split_result[0]) - variables[split_result[0][1:-1]] = evaluate(split_result[1]) - -def init_array(expression: str): - global arrays - split_result = expression.split(',') - if split_result[0][0] != '「' or split_result[0][-1] != '」' or len(split_result[0]) == 2: - raise ValueError('陣列名稱有誤:' + split_result[0]) - arrays[split_result[0][1:-1]] = [None for _ in range(evaluate(split_result[1]))] - - -def assign_array(expression: str): - global arrays - split_result = expression.split(',') - if split_result[0][0] != '「' or split_result[0][-1] != '」' or len(split_result[0]) == 2: - raise ValueError('陣列名稱有誤:'+split_result[0]) - arrays[split_result[0][1:-1]][int(evaluate(split_result[1]))] = evaluate(split_result[2]) - - -def get_user_input(variable: str): - global variables - if variable[0] != '「' or variable[-1] != '」' or len(variable) == 2: - raise ValueError('變數名稱有誤:'+variable) - variables[variable[1:-1]] = input('') - -def precedence(op): - if op == '等於' or op == '大於' or op == '小於': - return 1 - if op == '加上' or op == '減去': - return 2 - if op == '乘以' or op == '除以' or op == '取模': - return 3 - if op == '轉型': - return 4 - return 0 - def apply(a, b, op): if op == '加上': @@ -75,102 +27,23 @@ def apply(a, b, op): return int(a < b) if op == '轉型': if b == '數字': - return int(a) + return float(a) elif b == '字串': return str(a) else: - raise ValueError('未知型態:'+b) - - -def evaluate(expression: str): - ops = [] - values = [] - i = 0 - while i < len(expression): - if expression[i] == ' ' or expression[i] == ' ': - pass - elif expression[i] == '(': - ops.append(expression[i]) - elif expression[i] == ')': - while len(ops) != 0 and ops[-1] != '(': - val2 = values.pop() - val1 = values.pop() - op = ops.pop() - values.append(apply(val1, val2, op)) - ops.pop() - elif expression[i].isdigit() or expression[i] == '.' or expression[i] == '-': - val = '' - while i < len(expression) and (expression[i].isdigit() or expression[i] == '.' or expression[i] == '-'): - val += expression[i] - i += 1 - i -= 1 - values.append(float(val)) - elif expression[i] == '「': - token = '' - i += 1 - while expression[i] != '」': - token += expression[i] - i += 1 - values.append(token) - elif expression[i:i + 3] == '變數「': - token = '' - i += 3 - while expression[i] != '」': - token += expression[i] - i += 1 - values.append(variables[token]) + raise ValueError('未知型態:' + b) - elif expression[i:i + 3] == '陣列「': - token = '' - i += 3 - while expression[i] != '」': - token += expression[i] - i += 1 - i += 1 - if expression[i:i + 4] != '的索引(': - raise ValueError('未知的算式:' + expression) - i += 4 - tmp_exp = '' - stk = 1 - while i < len(expression): - if expression[i] == '(': - stk += 1 - elif expression[i] == ')': - stk -= 1 - tmp_exp += expression[i] - i += 1 - if stk == 0: - break - i -= 1 - values.append(arrays[token][int(evaluate(tmp_exp[:-1]))]) - else: - if expression[i:i + 2] not in KEYWORDS: - raise ValueError('未知的運算子:' + expression[i]) - while len(ops) != 0 and precedence(ops[-1]) >= precedence(expression[i:i + 2]): - val2 = values.pop() - val1 = values.pop() - op = ops.pop() - values.append(apply(val1, val2, op)) - ops.append(expression[i:i + 2]) - i += 1 - i += 1 - while len(ops) != 0: - val2 = values.pop() - val1 = values.pop() - op = ops.pop() - values.append(apply(val1, val2, op)) - final = values[-1] - if type(final) == type(1.0) and final % 1.0 == 0: - return int(final) - return final - - -def run_command(command: str): - for i in COMMANDS.keys(): - if command[:len(i)] == i: - COMMANDS[i](command[len(i):]) - return - raise ValueError('未知指令:'+command) + +def precedence(op): + if op == '等於' or op == '大於' or op == '小於': + return 1 + if op == '加上' or op == '減去': + return 2 + if op == '乘以' or op == '除以' or op == '取模': + return 3 + if op == '轉型': + return 4 + return 0 def get_clause(lines: list[str], start_line: int): @@ -185,55 +58,180 @@ def get_clause(lines: list[str], start_line: int): return j -def exec_separate_lines(lines: list[str]): - i = 0 - while i < len(lines): - if lines[i] == BREAK: - return -1 - if lines[i] == CONTINUE: - return -2 - if lines[i] == EXIT: - return 0 - if lines[i][:len(IF)] == IF: - j = get_clause(lines, i) - if evaluate(lines[i][len(IF):]): - ret = exec_separate_lines(lines[i+1:j]) - if ret is not None: - return ret - i = j - elif lines[i][:len(WHILE)] == WHILE: - j = get_clause(lines, i) - while evaluate(lines[i][len(WHILE):]): - ret = exec_separate_lines(lines[i+1:j]) - if ret == -1: - break - if ret == 0: - return 0 - i = j - else: - run_command(lines[i]) - i += 1 - - -def execute(lines: str): - split_lines = lines.split('\n') - split_code = [] - for i in split_lines: - stripped = i.strip() - if stripped == '': - continue - if stripped[-1] != '。': - raise ValueError('你忘了加句點。') - split_code.append(stripped[:-1]) - exec_separate_lines(split_code) - -if __name__ == '__main__': - code = ''' -設定一指定名稱變數的值,名稱與值分別為「i」,0。 -重複並持續驗證右方表達式之真實性,條件滿足時持續執行特定操作(變數「i」小於10)。 -要求在終端機(或控制台)輸出「執行第 」加上變數「i」轉型「字串」加上「 次」。 -設定一指定名稱變數的值,名稱與值分別為「i」,變數「i」加上1。 -結束以上判斷式或迴圈。 - ''' - - execute(code) \ No newline at end of file +class Executor: + + def __init__(self): + self.COMMANDS = {'要求在終端機(或控制台)輸出': (lambda x: print(self.evaluate(x))), + '設定一指定名稱變數的值,名稱與值分別為': (lambda x: self.assign_variable(x)), + '初始化一個指定名稱和長度的陣列,名稱和長度分別為': (lambda x: self.init_array(x)), + '設定指定名稱陣列其中一項的值,名稱、項數與值分別為': (lambda x: self.assign_array(x)), + '讀取使用者輸入字串,並儲存至變數': (lambda x: self.get_user_input(x)), + '將一字串拆分成字元陣列,並將結果儲存至指定名稱的陣列,字串和陣列分別為': (lambda x: self.split_array(x))} + + self.variables = {} + self.arrays = {} + + def run_command(self, command: str): + for i in self.COMMANDS.keys(): + if command[:len(i)] == i: + self.COMMANDS[i](command[len(i):]) + return + raise ValueError('未知指令:' + command) + + def evaluate(self, expression: str): + ops = [] + values = [] + i = 0 + while i < len(expression): + if expression[i] == ' ' or expression[i] == ' ': + pass + elif expression[i] == '(': + ops.append(expression[i]) + elif expression[i] == ')': + while len(ops) != 0 and ops[-1] != '(': + val2 = values.pop() + val1 = values.pop() + op = ops.pop() + values.append(apply(val1, val2, op)) + ops.pop() + elif expression[i].isdigit() or expression[i] == '.' or expression[i] == '-': + val = '' + while i < len(expression) and (expression[i].isdigit() or expression[i] == '.' or expression[i] == '-'): + val += expression[i] + i += 1 + i -= 1 + values.append(float(val)) + elif expression[i] == '「': + token = '' + i += 1 + while expression[i] != '」': + token += expression[i] + i += 1 + values.append(token) + elif expression[i:i + 3] == '變數「': + token = '' + i += 3 + while expression[i] != '」': + token += expression[i] + i += 1 + values.append(self.variables[token]) + + elif expression[i:i + 3] == '陣列「': + token = '' + i += 3 + while expression[i] != '」': + token += expression[i] + i += 1 + i += 1 + if expression[i:i + 4] == '的索引(': + i += 4 + tmp_exp = '' + stk = 1 + while i < len(expression): + if expression[i] == '(': + stk += 1 + elif expression[i] == ')': + stk -= 1 + tmp_exp += expression[i] + i += 1 + if stk == 0: + break + i -= 1 + values.append(self.arrays[token][int(self.evaluate(tmp_exp[:-1]))]) + elif expression[i:i + 3] == '的長度': + i += 2 + values.append(len(self.arrays[token])) + else: + raise ValueError('未知的算式:' + expression) + else: + if expression[i:i + 2] not in KEYWORDS: + raise ValueError('未知的運算子:' + expression[i]) + while len(ops) != 0 and precedence(ops[-1]) >= precedence(expression[i:i + 2]): + val2 = values.pop() + val1 = values.pop() + op = ops.pop() + values.append(apply(val1, val2, op)) + ops.append(expression[i:i + 2]) + i += 1 + i += 1 + while len(ops) != 0: + val2 = values.pop() + val1 = values.pop() + op = ops.pop() + values.append(apply(val1, val2, op)) + final = values[-1] + if type(final) == type(1.0) and final % 1.0 == 0: + return int(final) + return final + + def assign_variable(self, expression: str): + split_result = expression.split(',') + if split_result[0][0] != '「' or split_result[0][-1] != '」' or len(split_result[0]) == 2: + raise ValueError('變數名稱有誤:' + split_result[0]) + self.variables[split_result[0][1:-1]] = self.evaluate(split_result[1]) + + def init_array(self, expression: str): + split_result = expression.split(',') + if split_result[0][0] != '「' or split_result[0][-1] != '」' or len(split_result[0]) == 2: + raise ValueError('陣列名稱有誤:' + split_result[0]) + self.arrays[split_result[0][1:-1]] = [None for _ in range(self.evaluate(split_result[1]))] + + def assign_array(self, expression: str): + split_result = expression.split(',') + if split_result[0][0] != '「' or split_result[0][-1] != '」' or len(split_result[0]) == 2: + raise ValueError('陣列名稱有誤:' + split_result[0]) + self.arrays[split_result[0][1:-1]][int(self.evaluate(split_result[1]))] = self.evaluate(split_result[2]) + + def get_user_input(self, variable: str): + if variable[0] != '「' or variable[-1] != '」' or len(variable) == 2: + raise ValueError('變數名稱有誤:' + variable) + self.variables[variable[1:-1]] = input('') + + def split_array(self, expression: str): + split_result = expression.split(',') + if split_result[1][0] != '「' or split_result[1][-1] != '」' or len(split_result[1]) == 2: + raise ValueError('陣列名稱有誤:' + split_result[1]) + self.arrays[split_result[1][1:-1]] = list(str(self.evaluate(split_result[0]))) + + def exec_separate_lines(self, lines: list[str]): + i = 0 + while i < len(lines): + if lines[i] == BREAK: + return -1 + if lines[i] == CONTINUE: + return -2 + if lines[i] == EXIT: + return 0 + if lines[i][:len(IF)] == IF: + j = get_clause(lines, i) + if self.evaluate(lines[i][len(IF):]): + ret = self.exec_separate_lines(lines[i + 1:j]) + if ret is not None: + return ret + i = j + elif lines[i][:len(WHILE)] == WHILE: + j = get_clause(lines, i) + while self.evaluate(lines[i][len(WHILE):]): + ret = self.exec_separate_lines(lines[i + 1:j]) + if ret == -1: + break + if ret == 0: + return 0 + i = j + else: + self.run_command(lines[i]) + i += 1 + + def execute(self, lines: str): + self.variables = {} + self.arrays = {} + split_lines = lines.split('\n') + split_code = [] + for i in split_lines: + stripped = i.strip() + if stripped == '': + continue + if stripped[-1] != '。': + raise ValueError('你忘了加句點。') + split_code.append(stripped[:-1]) + self.exec_separate_lines(split_code) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f52ba16 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +flask +io +multiprocessing +threading \ No newline at end of file diff --git a/static/css/styles.css b/static/css/styles.css new file mode 100644 index 0000000..44da57f --- /dev/null +++ b/static/css/styles.css @@ -0,0 +1,176 @@ +body { + font-family: 'Microsoft JhengHei', Arial, sans-serif; + line-height: 1.6; + margin: 0; + padding: 20px; + background-color: #f5f5f5; +} + +.container { + max-width: 1000px; + margin: 0 auto; + background-color: white; + padding: 30px; + border-radius: 10px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +h2 { + color: #2c3e50; + margin-bottom: 25px; + text-align: center; + font-size: 28px; +} + +#codeEditor { + width: 100%; + height: 300px; + padding: 15px; + border: 2px solid #e0e0e0; + border-radius: 8px; + font-family: 'Consolas', monospace; + font-size: 14px; + resize: vertical; + background-color: #f8f9fa; + transition: border-color 0.3s; +} + +#codeEditor:focus { + outline: none; + border-color: #4CAF50; + box-shadow: 0 0 5px rgba(76, 175, 80, 0.2); +} + +#runCodeButton { + background-color: #4CAF50; + color: white; + border: none; + padding: 12px 25px; + border-radius: 5px; + cursor: pointer; + font-size: 16px; + transition: background-color 0.3s; + margin: 20px 10px 20px 0; +} + +#runCodeButton:hover { + background-color: #45a049; +} + +#triangleExampleButton { + background-color: #3498db; + color: white; + border: none; + padding: 12px 25px; + border-radius: 5px; + cursor: pointer; + font-size: 16px; + transition: background-color 0.3s; + margin: 20px 10px; +} + +#triangleExampleButton:hover { + background-color: #2980b9; +} + +#quadraticExampleButton { + background-color: #e67e22; + color: white; + border: none; + padding: 12px 25px; + border-radius: 5px; + cursor: pointer; + font-size: 16px; + transition: background-color 0.3s; + margin: 20px 0; +} + +#quadraticExampleButton:hover { + background-color: #d35400; +} + +#executionResult { + background: #2c3e50; + color: #ecf0f1; + padding: 20px; + border-radius: 8px; + margin-top: 20px; + white-space: pre-wrap; + text-align: left; + font-family: 'Consolas', monospace; + font-size: 14px; + min-height: 100px; +} + +.loading { + opacity: 0.7; + pointer-events: none; +} + +.intro-section { + margin-bottom: 30px; + padding: 20px; + background-color: #f8f9fa; + border-radius: 8px; +} + +.syntax-table { + width: 100%; + border-collapse: collapse; + margin-top: 30px; +} + +.syntax-table th, +.syntax-table td { + border: 1px solid #e0e0e0; + padding: 10px; + text-align: left; +} + +.syntax-table th { + background-color: #2c3e50; + color: white; +} + +#inputSection { + margin-top: 10px; + display: none; +} + +#userInput { + width: 70%; + padding: 8px; + border: 2px solid #e0e0e0; + border-radius: 5px; + font-family: 'Consolas', monospace; +} + +#submitInput { + background-color: #4CAF50; + color: white; + border: none; + padding: 8px 15px; + border-radius: 5px; + cursor: pointer; + margin-left: 10px; +} + +#submitInput:hover { + background-color: #45a049; +} + +#twentyOneExampleButton { + background-color: #e4e412; + color: white; + border: none; + padding: 12px 25px; + border-radius: 5px; + cursor: pointer; + font-size: 16px; + transition: background-color 0.3s; + margin: 20px 10px; +} + +#twentyOneExampleButton:hover { + background-color: #d6d612; +} \ No newline at end of file diff --git a/static/js/script.js b/static/js/script.js new file mode 100644 index 0000000..825f1b2 --- /dev/null +++ b/static/js/script.js @@ -0,0 +1,240 @@ +const runButton = document.getElementById('runCodeButton'); +const triangleExampleButton = document.getElementById('triangleExampleButton'); +const quadraticExampleButton = document.getElementById('quadraticExampleButton'); +const twentyOneExampleButton = document.getElementById('twentyOneExampleButton'); // 新增按鈕 +const editor = document.getElementById('codeEditor'); +const result = document.getElementById('executionResult'); +const inputSection = document.getElementById('inputSection'); +const userInput = document.getElementById('userInput'); +const submitInput = document.getElementById('submitInput'); +const API_BASE_URL = "http://10.219.58.131:5000"; // 指定 API 伺服器的 IP 和端口 +let sessionId = null; +// 三角形範例程式碼 +const triangleExampleCode = ` +要求在終端機(或控制台)輸出「輸入三角形的三邊長(以換行隔開):」。 +讀取使用者輸入字串,並儲存至變數「a」。 +設定一指定名稱變數的值,名稱與值分別為「a」,變數「a」轉型「數字」。 +讀取使用者輸入字串,並儲存至變數「b」。 +設定一指定名稱變數的值,名稱與值分別為「b」,變數「b」轉型「數字」。 +讀取使用者輸入字串,並儲存至變數「c」。 +設定一指定名稱變數的值,名稱與值分別為「c」,變數「c」轉型「數字」。 +設定一指定名稱變數的值,名稱與值分別為「i」,0。 +重複並持續驗證右方表達式之真實性,條件滿足時持續執行特定操作(1)。 +如果右方判斷式結果為真,執行以下特定操作(變數「a」大於變數「b」)。 +設定一指定名稱變數的值,名稱與值分別為「t」,變數「a」。 +設定一指定名稱變數的值,名稱與值分別為「a」,變數「b」。 +設定一指定名稱變數的值,名稱與值分別為「b」,變數「t」。 +結束以上判斷式或迴圈。 +如果右方判斷式結果為真,執行以下特定操作(變數「i」大於1)。 +無視迴圈判斷式要求,直接跳脫迴圈。 +結束以上判斷式或迴圈。 +如果右方判斷式結果為真,執行以下特定操作(變數「b」大於變數「c」)。 +設定一指定名稱變數的值,名稱與值分別為「t」,變數「b」。 +設定一指定名稱變數的值,名稱與值分別為「b」,變數「c」。 +設定一指定名稱變數的值,名稱與值分別為「c」,變數「t」。 +結束以上判斷式或迴圈。 +設定一指定名稱變數的值,名稱與值分別為「i」,變數「i」加上1。 +結束以上判斷式或迴圈。 +要求在終端機(或控制台)輸出「排序後的三邊長:」。 +要求在終端機(或控制台)輸出變數「a」轉型「字串」加上「 」加上變數「b」轉型「字串」加上「 」加上變數「c」轉型「字串」加上「 」。 +如果右方判斷式結果為真,執行以下特定操作 1 減去(變數「a」加上變數「b」大於變數「c」)。 +要求在終端機(或控制台)輸出「不構成三角形。」。 +無視所有指令,直接退出程式。 +結束以上判斷式或迴圈。 +如果右方判斷式結果為真,執行以下特定操作(變數「a」乘以變數「a」加上變數「b」乘以變數「b」等於變數「c」乘以變數「c」)。 +要求在終端機(或控制台)輸出「直角三角形。」。 +結束以上判斷式或迴圈。 +如果右方判斷式結果為真,執行以下特定操作(變數「a」乘以變數「a」加上變數「b」乘以變數「b」小於變數「c」乘以變數「c」)。 +要求在終端機(或控制台)輸出「鈍角三角形。」。 +結束以上判斷式或迴圈。 +如果右方判斷式結果為真,執行以下特定操作(變數「a」乘以變數「a」加上變數「b」乘以變數「b」大於變數「c」乘以變數「c」)。 +要求在終端機(或控制台)輸出「銳角三角形。」。 +結束以上判斷式或迴圈。 +`.trim(); + +// 一元二次方程式範例程式碼 +const quadraticExampleCode = ` +要求在終端機(或控制台)輸出「請輸入 x^2 項係數 ,此項必須不為 0」。 +讀取使用者輸入字串,並儲存至變數「a」。 +設定一指定名稱變數的值,名稱與值分別為「a」,變數「a」轉型「數字」。 +如果右方判斷式結果為真,執行以下特定操作(變數「a」等於 0)。 +要求在終端機(或控制台)輸出「使用者輸入錯誤,導致 RE 」。 +無視所有指令,直接退出程式。 +結束以上判斷式或迴圈。 +要求在終端機(或控制台)輸出「請輸入 x 項係數」。 +讀取使用者輸入字串,並儲存至變數「b」。 +設定一指定名稱變數的值,名稱與值分別為「b」,變數「b」轉型「數字」。 +要求在終端機(或控制台)輸出「請輸入常數項係數」。 +讀取使用者輸入字串,並儲存至變數「c」。 +設定一指定名稱變數的值,名稱與值分別為「c」,變數「c」轉型「數字」。 +如果右方判斷式結果為真,執行以下特定操作 (變數「b」 乘以 變數「b」 大於 4 乘以 變數「a」 乘以 變數「c」)。 +要求在終端機(或控制台)輸出「方程式有兩個相異的實數解」。 +結束以上判斷式或迴圈。 +如果右方判斷式結果為真,執行以下特定操作 (變數「b」 乘以 變數「b」 等於 4 乘以 變數「a」 乘以 變數「c」)。 +要求在終端機(或控制台)輸出「方程式有兩個一樣的實數解」。 +結束以上判斷式或迴圈。 +如果右方判斷式結果為真,執行以下特定操作 (變數「b」 乘以 變數「b」 小於 4 乘以 變數「a」 乘以 變數「c」)。 +要求在終端機(或控制台)輸出「方程式有兩個虛數解」。 +結束以上判斷式或迴圈。 +`.trim(); + +// 搶21點範例程式碼 +const twentyOneExampleCode = ` +要求在終端機(或控制台)輸出「搶 21 遊戲,玩家先手,每次可選擇 1~3」。 +要求在終端機(或控制台)輸出「輪到玩家,目前剩下 21 」。 +設定一指定名稱變數的值,名稱與值分別為「x」,21。 +讀取使用者輸入字串,並儲存至變數「a」。 +設定一指定名稱變數的值,名稱與值分別為「a」,變數「a」轉型「數字」。 +重複並持續驗證右方表達式之真實性,條件滿足時持續執行特定操作((變數「a」小於 4)加上(變數「a」大於 0)加上 (變數「x」減去 變數「a」加上 1 大於 0)小於 3)。 +要求在終端機(或控制台)輸出「輸入無效,請重新輸入」。 +讀取使用者輸入字串,並儲存至變數「a」。 +設定一指定名稱變數的值,名稱與值分別為「a」,變數「a」轉型「數字」。 +結束以上判斷式或迴圈。 +設定一指定名稱變數的值,名稱與值分別為「x」,變數「x」減去 變數「a」。 +設定一指定名稱變數的值,名稱與值分別為「p」,1。 + +重複並持續驗證右方表達式之真實性,條件滿足時持續執行特定操作(變數「x」大於 0)。 +設定一指定名稱變數的值,名稱與值分別為「e」,0。 +如果右方判斷式結果為真,執行以下特定操作(變數「x」取模 4 等於 0)。 +要求在終端機(或控制台)輸出「電腦選擇 2 」。 +設定一指定名稱變數的值,名稱與值分別為「x」,變數「x」減去 2。 +設定一指定名稱變數的值,名稱與值分別為「e」,1。 +結束以上判斷式或迴圈。 +如果右方判斷式結果為真,執行以下特定操作(變數「e」等於 0)。 +設定一指定名稱變數的值,名稱與值分別為「c」,變數「x」取模 4。 +要求在終端機(或控制台)輸出(「電腦選擇 」加上(變數「c」轉型 「字串」))。 +設定一指定名稱變數的值,名稱與值分別為「x」,變數「x」減去 變數「c」。 +設定一指定名稱變數的值,名稱與值分別為「p」,0。 +結束以上判斷式或迴圈。 +如果右方判斷式結果為真,執行以下特定操作(變數「x」等於 0)。 +要求在終端機(或控制台)輸出「電腦獲勝」。 +無視所有指令,直接退出程式。 +結束以上判斷式或迴圈。 +要求在終端機(或控制台)輸出(「輪到玩家,目前剩下 」加上(變數「x」轉型「字串」))。 +讀取使用者輸入字串,並儲存至變數「a」。 +設定一指定名稱變數的值,名稱與值分別為「a」,變數「a」轉型「數字」。 +重複並持續驗證右方表達式之真實性,條件滿足時持續執行特定操作((變數「a」小於 4)加上(變數「a」大於 0)加上 (變數「x」減去 變數「a」加上 1 大於 0)小於 3)。 +要求在終端機(或控制台)輸出「輸入無效,請重新輸入」。 +讀取使用者輸入字串,並儲存至變數「a」。 +設定一指定名稱變數的值,名稱與值分別為「a」,變數「a」轉型「數字」。 +結束以上判斷式或迴圈。 +設定一指定名稱變數的值,名稱與值分別為「x」,變數「x」減去 變數「a」。 +設定一指定名稱變數的值,名稱與值分別為「p」,1。 +如果右方判斷式結果為真,執行以下特定操作(變數「x」等於 0)。 +要求在終端機(或控制台)輸出「玩家獲勝」。 +無視所有指令,直接退出程式。 +結束以上判斷式或迴圈。 +結束以上判斷式或迴圈。 +`.trim(); + +// 執行按鈕事件 +runButton.addEventListener('click', async () => { + const code = editor.value; + runButton.disabled = true; + runButton.textContent = '執行中...'; + result.textContent = '處理中...'; + inputSection.style.display = 'none'; + + try { + const response = await fetch('/run', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ code }) + }); + + const resultData = await response.json(); + sessionId = resultData.sessionId; + + // 開始輪詢狀態 + pollStatus(); + } catch (error) { + result.textContent = '前端請求錯誤或連線失敗。'; + resetButton(); + } +}); + +// 輪詢狀態 +const pollStatus = async () => { + if (!sessionId) return; + + try { + const response = await fetch(`/status/${sessionId}`); + const data = await response.json(); + + if (data.error) { + result.textContent = data.error; + resetButton(); + return; + } + + if (data.output) { + result.textContent += data.output; + } + + if (data.needsInput) { + inputSection.style.display = 'block'; + userInput.focus(); + } else if (data.completed) { + resetButton(); + } else { + setTimeout(pollStatus, 300); // 繼續輪詢 + } + } catch (error) { + result.textContent = '狀態輪詢失敗。'; + resetButton(); + } +}; + +// 提交輸入事件 +submitInput.addEventListener('click', async () => { + const inputValue = userInput.value.trim(); + if (!inputValue || !sessionId) { + alert('請輸入內容或確保 sessionId 存在'); + return; + } + + try { + const response = await fetch('/submit_input', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ sessionId, input: inputValue }) + }); + + if (!response.ok) { + throw new Error('提交輸入失敗'); + } + + userInput.value = ''; // 清空輸入框 + pollStatus(); // 繼續輪詢狀態 + } catch (error) { + result.textContent += '\n輸入處理失敗:' + error.message; + } +}); + +// 三角形範例按鈕事件 +triangleExampleButton.addEventListener('click', () => { + editor.value = triangleExampleCode; + result.textContent = '已載入三角形範例程式,請點擊「執行程式碼」運行。'; + editor.focus(); +}); + +// 一元二次方程式範例按鈕事件 +quadraticExampleButton.addEventListener('click', () => { + editor.value = quadraticExampleCode; + result.textContent = '已載入一元二次方程式範例程式,請點擊「執行程式碼」運行。'; + editor.focus(); +}); + +// 搶21點範例按鈕事件 +twentyOneExampleButton.addEventListener('click', () => { + editor.value = twentyOneExampleCode; + result.textContent = '已載入搶21點範例程式,請點擊「執行程式碼」運行。'; + editor.focus(); +}); + +// 重置按鈕狀態 +const resetButton = () => { + runButton.disabled = false; + runButton.textContent = '執行程式碼 ▶'; + sessionId = null; +}; \ No newline at end of file diff --git a/templates/index2.html b/templates/index2.html new file mode 100644 index 0000000..69452b0 --- /dev/null +++ b/templates/index2.html @@ -0,0 +1,98 @@ + + + + + + ACcode線上直譯器 + + + + +
+
+

基本介紹

+

這裡是基於python開發的直譯器。

+

如果有任何問題請看下方的對照表。

+
+ +

ACcode線上直譯器

+ + + + + +
執行結果將顯示在這裡...
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Python語法ACcode語法
print(...)要求在終端機(或控制台)輸出 ... 。
... = input()讀取使用者輸入字串,並儲存至變數「...」
... = ....設定一指定名稱變數的值,名稱與值分別為 ... , ....
... = [None for _ in range(....)]初始化一個指定名稱和長度的陣列,名稱和長度分別為 ... , ....
if ... :如果右方判斷式結果為真,執行以下特定操作
while ... :重複並持續驗證右方表達式之真實性,條件滿足時持續執行特定操作 ...
取消縮排結束以上判斷式或迴圈
break無視迴圈判斷式要求,直接跳脫迴圈
continue捨棄以下迴圈內容,直接繼續下一輪迴圈
exit()無視所有指令,直接退出程式
+, -, *, /, %加上, 減去, 乘以, 除以, 取模
=, >, <等於, 大於, 小於
float(...), str(...)... 轉型 「數字」, ... 轉型 「字串」
... (變數), ...[....](清單)變數「...」, 陣列「...」的索引(....)
+
+ + \ No newline at end of file