Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
194 changes: 194 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -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();
});
190 changes: 190 additions & 0 deletions index.css
Original file line number Diff line number Diff line change
@@ -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);
}
Loading