// Code will appear here...+
diff --git a/README.md b/README.md index 18e2c75..a42f57e 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,8 @@ JavaScript ports of the examples in David Kopec's "Classic Computer Science Prob ## Running Examples On console: Type `node {filename}.js` -In a web browser: Open `index.html` from the example root directory and click the links to run the various examples +In a web browser (Modern UI): +To run the Single Page Application dashboard and avoid CORS security blocks when reading local files, you should run a local server. +1. Open your terminal in this directory. +2. Run `npx serve .` (requires Node.js). +3. Open `http://localhost:3000` in your browser. diff --git a/app.js b/app.js new file mode 100644 index 0000000..5777a59 --- /dev/null +++ b/app.js @@ -0,0 +1,194 @@ +const i18n = { + en: { + title: "Classic CS Problems (JS)", + toggleLang: "PT-BR", + codeTitle: "Source Code", + consoleTitle: "Console Output", + selectProblem: "Select a problem from the sidebar to view its code and output.", + chapters: { + chapter1: "Chapter 1: Small Problems", + chapter2: "Chapter 2: Search Problems", + chapter3: "Chapter 3: Constraint-satisfaction", + chapter4: "Chapter 4: Graph Problems", + chapter5: "Chapter 5: Genetic Algorithms", + chapter6: "Chapter 6: kMeans Clustering", + chapter7: "Chapter 7: Neural Networks", + chapter8: "Chapter 8: Adversarial Search", + chapter9: "Chapter 9: Miscellaneous", + }, + problems: { + fib1: "Fibonacci (missing base case)", + fib2: "Fibonacci (recursive)", + fib3: "Fibonacci (memoization)", + fib4: "Fibonacci (iterative)", + fib5: "Fibonacci (generator)", + compression: "Trivial Compression", + encryption: "Unbreakable Encryption", + pi: "Calculating Pi", + hanoi: "Towers of Hanoi", + dna: "DNA Search", + generic_search: "Generic Search Test", + maze: "Maze Solving", + missionaries: "Missionaries & Cannibals", + map_coloring: "Map-coloring Problem", + queens: "Eight Queens Problem", + word_search: "Word Search", + send_more_money: "SEND+MORE=MONEY", + graph: "Graph (shortest path)", + weighted_graph: "Weighted Graph", + mst: "Minimum Spanning Tree", + dijkstra: "Dijkstra's Algorithm", + simple_eq: "Simple Equation", + list_comp: "List Compression", + send_more_money2: "SEND+MORE=MONEY 2", + kmeans_trivial: "kMeans Trivial", + governors: "Governors", + mj: "Michael Jackson Albums", + iris: "Iris Classification", + wine: "Wine Classification", + tictactoe: "Tic Tac Toe", + connectfour: "Connect Four", + knapsack: "The Knapsack Problem", + tsp: "Traveling Salesman Problem", + phone_mnemonics: "Phone Number Mnemonics" + } + }, + pt: { + title: "Problemas Clássicos (JS)", + toggleLang: "EN", + codeTitle: "Código Fonte", + consoleTitle: "Saída do Console", + selectProblem: "Selecione um problema na barra lateral para ver o código e o resultado.", + chapters: { + chapter1: "Capítulo 1: Problemas Pequenos", + chapter2: "Capítulo 2: Problemas de Busca", + chapter3: "Capítulo 3: Satisfação de Restrições", + chapter4: "Capítulo 4: Problemas de Grafos", + chapter5: "Capítulo 5: Algoritmos Genéticos", + chapter6: "Capítulo 6: Clusterização kMeans", + chapter7: "Capítulo 7: Redes Neurais", + chapter8: "Capítulo 8: Busca Adversária", + chapter9: "Capítulo 9: Diversos", + }, + problems: { + fib1: "Fibonacci (sem caso base)", + fib2: "Fibonacci (recursivo)", + fib3: "Fibonacci (memoização)", + fib4: "Fibonacci (iterativo)", + fib5: "Fibonacci (gerador)", + compression: "Compressão Trivial", + encryption: "Criptografia Inquebrável", + pi: "Calculando Pi", + hanoi: "Torres de Hanói", + dna: "Busca em DNA", + generic_search: "Teste Busca Genérica", + maze: "Resolvendo Labirinto", + missionaries: "Missionários e Canibais", + map_coloring: "Coloração de Mapa", + queens: "Problema das 8 Rainhas", + word_search: "Caça Palavras", + send_more_money: "SEND+MORE=MONEY", + graph: "Grafo (caminho curto)", + weighted_graph: "Grafo Ponderado", + mst: "Árvore Geradora Mínima", + dijkstra: "Algoritmo de Dijkstra", + simple_eq: "Equação Simples", + list_comp: "Compressão de Lista", + send_more_money2: "SEND+MORE=MONEY 2", + kmeans_trivial: "kMeans Trivial", + governors: "Governadores", + mj: "Álbuns do Michael Jackson", + iris: "Classificação Iris", + wine: "Classificação de Vinho", + tictactoe: "Jogo da Velha", + connectfour: "Ligue Quatro", + knapsack: "Problema da Mochila", + tsp: "Caixeiro Viajante", + phone_mnemonics: "Mnemônicos de Telefone" + } + } +}; + +let currentLang = 'en'; + +function applyTranslations() { + document.querySelectorAll('[data-i18n]').forEach(el => { + const keyPath = el.getAttribute('data-i18n').split('.'); + let value = i18n[currentLang]; + for (const key of keyPath) { + if (value[key] !== undefined) { + value = value[key]; + } else { + value = null; + break; + } + } + if (value) { + if (el.tagName === 'INPUT' && el.type === 'button') { + el.value = value; + } else { + el.textContent = value; + } + } + }); + + // Update toggle button text specially to show opposite language + document.getElementById('lang-toggle').textContent = i18n[currentLang].toggleLang; +} + +function toggleLanguage() { + currentLang = currentLang === 'en' ? 'pt' : 'en'; + applyTranslations(); + updateCurrentTitle(); +} + +function updateCurrentTitle() { + const activeEl = document.querySelector('.problem.active'); + const titleEl = document.getElementById('current-title'); + if (activeEl) { + titleEl.textContent = activeEl.textContent; + } else { + titleEl.textContent = i18n[currentLang].selectProblem; + } +} + +async function loadProblem(liElement) { + // Update active states + document.querySelectorAll('.problem').forEach(el => el.classList.remove('active')); + liElement.classList.add('active'); + updateCurrentTitle(); + + const jsPath = liElement.getAttribute('data-js'); + const htmlPath = liElement.getAttribute('data-html'); + + // Load code in viewer + if (jsPath) { + try { + const response = await fetch(jsPath); + if (response.ok) { + const code = await response.text(); + document.getElementById('code-viewer').textContent = code; + } else { + document.getElementById('code-viewer').textContent = "// Error loading " + jsPath; + } + } catch (e) { + document.getElementById('code-viewer').textContent = "// Error fetching " + jsPath; + } + } + + // Load HTML in execution frame + if (htmlPath) { + document.getElementById('console-frame').src = htmlPath; + } +} + +document.addEventListener('DOMContentLoaded', () => { + document.getElementById('lang-toggle').addEventListener('click', toggleLanguage); + + document.querySelectorAll('.problem').forEach(el => { + el.addEventListener('click', () => loadProblem(el)); + }); + + applyTranslations(); + updateCurrentTitle(); +}); diff --git a/index.css b/index.css new file mode 100644 index 0000000..14b358c --- /dev/null +++ b/index.css @@ -0,0 +1,190 @@ +:root { + --bg-color: #0d1117; + --sidebar-bg: #161b22; + --text-primary: #c9d1d9; + --text-secondary: #8b949e; + --accent-color: #58a6ff; + --border-color: #30363d; + --panel-bg: #0d1117; + --code-bg: #1f2428; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; + background-color: var(--bg-color); + color: var(--text-primary); + display: flex; + height: 100vh; + overflow: hidden; +} + +/* Sidebar */ +.sidebar { + width: 300px; + background-color: var(--sidebar-bg); + border-right: 1px solid var(--border-color); + display: flex; + flex-direction: column; +} + +.sidebar-header { + padding: 20px; + border-bottom: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; +} + +.sidebar-header h1 { + font-size: 1.2rem; + font-weight: 600; +} + +.lang-toggle { + background: var(--bg-color); + border: 1px solid var(--border-color); + color: var(--text-primary); + padding: 5px 10px; + border-radius: 6px; + cursor: pointer; + font-size: 0.8rem; + font-weight: bold; + transition: all 0.2s; +} + +.lang-toggle:hover { + border-color: var(--accent-color); + color: var(--accent-color); +} + +.sidebar-nav { + flex: 1; + overflow-y: auto; + padding: 10px 0; +} + +.chapter { + margin-bottom: 5px; +} + +.chapter-title { + padding: 8px 20px; + font-size: 0.85rem; + font-weight: 600; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.problem { + padding: 8px 20px 8px 30px; + display: block; + color: var(--text-primary); + text-decoration: none; + font-size: 0.95rem; + cursor: pointer; + transition: background 0.2s; +} + +.problem:hover, .problem.active { + background-color: rgba(88, 166, 255, 0.1); + color: var(--accent-color); + border-left: 3px solid var(--accent-color); + padding-left: 27px; +} + +/* Main Content area */ +.main-content { + flex: 1; + display: flex; + flex-direction: column; +} + +.top-bar { + height: 50px; + border-bottom: 1px solid var(--border-color); + display: flex; + align-items: center; + padding: 0 20px; + background-color: var(--sidebar-bg); +} + +.current-problem-title { + font-weight: 600; + font-size: 1.1rem; +} + +.split-view { + flex: 1; + display: flex; + overflow: hidden; +} + +/* Code Panel */ +.panel { + flex: 1; + display: flex; + flex-direction: column; + border-right: 1px solid var(--border-color); + background-color: var(--panel-bg); +} + +.panel:last-child { + border-right: none; +} + +.panel-header { + padding: 10px 20px; + font-size: 0.85rem; + font-weight: 600; + color: var(--text-secondary); + border-bottom: 1px solid var(--border-color); + background-color: var(--sidebar-bg); + display: flex; + align-items: center; +} + +.panel-content { + flex: 1; + overflow: auto; + position: relative; +} + +pre#code-viewer { + margin: 0; + padding: 20px; + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; + font-size: 0.9rem; + line-height: 1.5; + background-color: var(--code-bg); + min-height: 100%; +} + +.execution-frame { + width: 100%; + height: 100%; + border: none; + background-color: var(--bg-color); +} + +/* Scrollbar styling */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} +::-webkit-scrollbar-track { + background: transparent; +} +::-webkit-scrollbar-thumb { + background: var(--border-color); + border-radius: 4px; +} +::-webkit-scrollbar-thumb:hover { + background: var(--text-secondary); +} diff --git a/index.html b/index.html index 86d57ae..70bdbd4 100644 --- a/index.html +++ b/index.html @@ -1,71 +1,126 @@ - +
-// Code will appear here...+