// Python Code Tester Application class PythonCodeTester { constructor() { this.tasks = [ { id: 1, title: "Створення змінних", description: "Створіть змінні для збереження вашого імені (рядок), віку (ціле число) та зросту (дійсне число). Виведіть їх на екран.", hint: "Використовуйте змінні name, age, height та функцію print()", solution: "name = \"Іван\"\nage = 20\nheight = 1.75\nprint(\"Ім'я:\", name)\nprint(\"Вік:\", age)\nprint(\"Зріст:\", height)", expected_output: "Ім'я: Іван\nВік: 20\nЗріст: 1.75" }, { id: 2, title: "Арифметичні операції", description: "Обчисліть площу прямокутника зі сторонами 15 та 25. Виведіть результат.", hint: "Площа = довжина × ширина", solution: "length = 15\nwidth = 25\narea = length * width\nprint(\"Площа прямокутника:\", area)", expected_output: "Площа прямокутника: 375" }, { id: 3, title: "Перетворення типів", description: "Перетворіть рядок '42' у ціле число, додайте до нього 8 та виведіть результат.", hint: "Використовуйте функцію int() для перетворення", solution: "number_str = '42'\nnumber = int(number_str)\nresult = number + 8\nprint(\"Результат:\", result)", expected_output: "Результат: 50" }, { id: 4, title: "Робота з булевими значеннями", description: "Створіть дві булеві змінні: is_student=True та has_id=False. Виведіть результат логічного AND та OR для цих змінних.", hint: "Використовуйте оператори and та or", solution: "is_student = True\nhas_id = False\nprint(\"AND результат:\", is_student and has_id)\nprint(\"OR результат:\", is_student or has_id)", expected_output: "AND результат: False\nOR результат: True" }, { id: 5, title: "Простий калькулятор", description: "Створіть програму, яка додає два числа 15.5 та 24.3 та виводить результат з описом.", hint: "Використовуйте оператор + та форматування виводу", solution: "num1 = 15.5\nnum2 = 24.3\nsum_result = num1 + num2\nprint(f\"Сума {num1} + {num2} = {sum_result}\")", expected_output: "Сума 15.5 + 24.3 = 39.8" } ]; this.currentTask = null; this.initializeApp(); } initializeApp() { this.renderTasks(); this.setupEventListeners(); } renderTasks() { const taskList = document.getElementById('taskList'); taskList.innerHTML = ''; this.tasks.forEach((task, index) => { const taskItem = document.createElement('div'); taskItem.className = 'task-item'; taskItem.dataset.taskId = task.id; taskItem.innerHTML = `

${index + 1}. ${task.title}

`; taskItem.addEventListener('click', () => this.selectTask(task)); taskList.appendChild(taskItem); }); } selectTask(task) { this.currentTask = task; // Update active task styling document.querySelectorAll('.task-item').forEach(item => { item.classList.remove('active'); }); document.querySelector(`[data-task-id="${task.id}"]`).classList.add('active'); // Update task display document.getElementById('currentTaskTitle').textContent = task.title; document.getElementById('taskDescription').textContent = task.description; // Show task action buttons document.getElementById('hintBtn').style.display = 'inline-flex'; document.getElementById('solutionBtn').style.display = 'inline-flex'; // Clear previous output document.getElementById('output').textContent = 'Натисніть "Запустити" для виконання коду...'; document.getElementById('outputStatus').textContent = ''; } setupEventListeners() { // Run button document.getElementById('runBtn').addEventListener('click', () => this.runCode()); // Hint button document.getElementById('hintBtn').addEventListener('click', () => this.showHint()); // Solution button document.getElementById('solutionBtn').addEventListener('click', () => this.showSolution()); // Modal close buttons document.getElementById('closeHintModal').addEventListener('click', () => this.closeModal('hintModal')); document.getElementById('closeSolutionModal').addEventListener('click', () => this.closeModal('solutionModal')); // Close modal on backdrop click document.getElementById('hintModal').addEventListener('click', (e) => { if (e.target.id === 'hintModal') this.closeModal('hintModal'); }); document.getElementById('solutionModal').addEventListener('click', (e) => { if (e.target.id === 'solutionModal') this.closeModal('solutionModal'); }); // Code editor enhancements const codeEditor = document.getElementById('codeEditor'); codeEditor.addEventListener('keydown', (e) => this.handleEditorKeydown(e)); // Example code click handlers document.querySelectorAll('.example-section code').forEach(code => { code.addEventListener('click', () => { const codeText = code.textContent; const editor = document.getElementById('codeEditor'); const currentCode = editor.value; if (currentCode.trim() === '' || currentCode === codeEditor.placeholder) { editor.value = codeText; } else { editor.value = currentCode + '\n' + codeText; } editor.focus(); }); }); } handleEditorKeydown(e) { // Handle Tab key for indentation if (e.key === 'Tab') { e.preventDefault(); const editor = e.target; const start = editor.selectionStart; const end = editor.selectionEnd; editor.value = editor.value.substring(0, start) + ' ' + editor.value.substring(end); editor.selectionStart = editor.selectionEnd = start + 4; } } runCode() { const code = document.getElementById('codeEditor').value.trim(); const output = document.getElementById('output'); const outputStatus = document.getElementById('outputStatus'); if (!code) { output.textContent = 'Помилка: Введіть код для виконання'; outputStatus.innerHTML = 'Помилка'; return; } try { const result = this.simulatePythonExecution(code); output.textContent = result.output; if (this.currentTask) { const isCorrect = this.checkSolution(result.output, this.currentTask.expected_output); if (isCorrect) { outputStatus.innerHTML = '✓ Правильно!'; } else { outputStatus.innerHTML = 'Не зовсім правильно'; } } else { outputStatus.innerHTML = 'Виконано'; } } catch (error) { output.textContent = `Помилка: ${error.message}`; outputStatus.innerHTML = 'Помилка виконання'; } } simulatePythonExecution(code) { // Simple Python code simulator let output = ''; let variables = {}; const lines = code.split('\n').filter(line => line.trim() && !line.trim().startsWith('#')); for (let line of lines) { line = line.trim(); try { if (line.includes('print(')) { const result = this.executePrintStatement(line, variables); output += result + '\n'; } else if (line.includes('=') && !line.includes('==')) { this.executeAssignment(line, variables); } } catch (error) { throw new Error(`Помилка в рядку "${line}": ${error.message}`); } } return { output: output.trim() }; } executeAssignment(line, variables) { const parts = line.split('='); if (parts.length !== 2) return; const varName = parts[0].trim(); const value = parts[1].trim(); variables[varName] = this.evaluateExpression(value, variables); } executePrintStatement(line, variables) { const match = line.match(/print\((.*)\)/); if (!match) return ''; const args = this.parseArguments(match[1]); const values = args.map(arg => this.evaluateExpression(arg, variables)); return values.join(' '); } parseArguments(argsString) { const args = []; let current = ''; let inString = false; let stringChar = ''; let depth = 0; for (let i = 0; i < argsString.length; i++) { const char = argsString[i]; if ((char === '"' || char === "'") && !inString) { inString = true; stringChar = char; current += char; } else if (char === stringChar && inString) { inString = false; current += char; } else if (char === '(' && !inString) { depth++; current += char; } else if (char === ')' && !inString) { depth--; current += char; } else if (char === ',' && !inString && depth === 0) { args.push(current.trim()); current = ''; } else { current += char; } } if (current.trim()) { args.push(current.trim()); } return args; } evaluateExpression(expr, variables) { expr = expr.trim(); // String literals if ((expr.startsWith('"') && expr.endsWith('"')) || (expr.startsWith("'") && expr.endsWith("'"))) { return expr.slice(1, -1); } // f-strings (basic support) if (expr.startsWith('f"') || expr.startsWith("f'")) { let result = expr.slice(2, -1); Object.keys(variables).forEach(varName => { const regex = new RegExp(`{${varName}}`, 'g'); result = result.replace(regex, variables[varName]); }); return result; } // Numbers if (!isNaN(expr)) { return expr.includes('.') ? parseFloat(expr) : parseInt(expr); } // Boolean values if (expr === 'True') return true; if (expr === 'False') return false; // Variables if (variables.hasOwnProperty(expr)) { return variables[expr]; } // Simple arithmetic expressions if (expr.includes('+') || expr.includes('-') || expr.includes('*') || expr.includes('/')) { return this.evaluateArithmetic(expr, variables); } // Boolean expressions if (expr.includes(' and ') || expr.includes(' or ')) { return this.evaluateBoolean(expr, variables); } // Type casting functions if (expr.startsWith('int(')) { const inner = expr.slice(4, -1); const value = this.evaluateExpression(inner, variables); return parseInt(value); } if (expr.startsWith('str(')) { const inner = expr.slice(4, -1); const value = this.evaluateExpression(inner, variables); return String(value); } if (expr.startsWith('float(')) { const inner = expr.slice(6, -1); const value = this.evaluateExpression(inner, variables); return parseFloat(value); } return expr; } evaluateArithmetic(expr, variables) { // Simple arithmetic evaluation let result = expr; // Replace variables with their values Object.keys(variables).forEach(varName => { const regex = new RegExp(`\\b${varName}\\b`, 'g'); result = result.replace(regex, variables[varName]); }); try { return eval(result); } catch { return expr; } } evaluateBoolean(expr, variables) { let result = expr; // Replace variables with their values Object.keys(variables).forEach(varName => { const regex = new RegExp(`\\b${varName}\\b`, 'g'); result = result.replace(regex, variables[varName]); }); // Replace Python boolean operators with JavaScript ones result = result.replace(/ and /g, ' && '); result = result.replace(/ or /g, ' || '); result = result.replace(/True/g, 'true'); result = result.replace(/False/g, 'false'); try { return eval(result); } catch { return expr; } } checkSolution(actualOutput, expectedOutput) { const normalize = (str) => str.replace(/\s+/g, ' ').trim().toLowerCase(); return normalize(actualOutput) === normalize(expectedOutput); } showHint() { if (!this.currentTask) return; document.getElementById('hintText').textContent = this.currentTask.hint; document.getElementById('hintModal').classList.remove('hidden'); } showSolution() { if (!this.currentTask) return; document.getElementById('solutionCode').textContent = this.currentTask.solution; document.getElementById('solutionModal').classList.remove('hidden'); } closeModal(modalId) { document.getElementById(modalId).classList.add('hidden'); } } // Initialize the application when the page loads document.addEventListener('DOMContentLoaded', () => { new PythonCodeTester(); });