Compare commits

...

11 Commits

27 changed files with 616 additions and 18 deletions
Binary file not shown.
Binary file not shown.
+56 -2
View File
@@ -1,3 +1,57 @@
# numnum
# NumNum
тренер систем счисления
Numeral systems trainer PWA
**Demo:** [numnum.atroshin.ru](https://numnum.atroshin.ru)
## Features
- 10 numeral systems: Binary, Ternary, Balanced Ternary, Octal, Hexadecimal, Braille Decimal, Roman, Church Slavonic, Greek, Hebrew
- Two game modes: multiple choice and manual entry (numpad)
- Configurable number range, time limit (1s30s or no limit), question count (5100)
- Installable PWA with full offline support (theory content cached)
- Dark/light theme · Bilingual (English / Русский)
- In-app theory reference for each system
## Usage
Serve the directory with any HTTP server:
```
python3 -m http.server 8080
```
## Project structure
```
index.html — Entry point
app.js — Game logic and UI
numerals.js — Numeral system converters and choice generator
styles.css — Styles, dark/light theme
sw.js — Service worker (PWA caching)
manifest.json — PWA manifest
theory/ — Theory HTML files (10 systems × 2 languages)
```
## Supported systems
| System | Type | Range |
|---|---|---|
| Binary | Positional | 132768 |
| Ternary | Positional | 127 |
| Balanced Ternary | Positional | 2727 |
| Octal | Positional | 14096 |
| Hexadecimal | Positional | 165536 |
| Braille Decimal | Positional | 09999 |
| Roman | Non-positional | 13999 |
| Church Slavonic | Non-positional | 19999 |
| Greek | Non-positional | 19999 |
| Hebrew | Non-positional | 19999 |
## Development
Theory HTML files live in `theory/`. After editing them, bump the version in `sw.js` to refresh the cache on next install.
## License
MIT
+170 -8
View File
@@ -6,6 +6,7 @@ const STRINGS = {
en: {
subtitle: 'Numeral systems trainer',
startGame: 'Start',
theory: 'Theory',
chooseSystem: 'Choose numeral system',
positional: 'Positional',
nonPositional: 'Non-Positional',
@@ -33,6 +34,7 @@ const STRINGS = {
congratulations: 'Congratulations!',
pleaseSelect: 'Please select all options',
installApp: 'Install App',
theoryUnavailable: 'Content unavailable',
sec: 'sec',
chooseAnswer: 'Choose answer',
enterEquivalent: 'Enter equivalent',
@@ -46,6 +48,7 @@ const STRINGS = {
ru: {
subtitle: '\u0422\u0440\u0435\u043D\u0430\u0436\u0435\u0440 \u0441\u0438\u0441\u0442\u0435\u043C \u0441\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u044F',
startGame: 'Начать',
theory: '\u0422\u0435\u043E\u0440\u0438\u044F',
chooseSystem: '\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 \u0441\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u044F',
positional: '\u041F\u043E\u0437\u0438\u0446\u0438\u043E\u043D\u043D\u044B\u0435',
nonPositional: '\u041D\u0435\u043F\u043E\u0437\u0438\u0446\u0438\u043E\u043D\u043D\u044B\u0435',
@@ -73,6 +76,7 @@ const STRINGS = {
congratulations: '\u041F\u043E\u0437\u0434\u0440\u0430\u0432\u043B\u044F\u0435\u043C!',
pleaseSelect: '\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0432\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0432\u0441\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B',
installApp: '\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435',
theoryUnavailable: '\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D',
sec: '\u0441\u0435\u043A',
chooseAnswer: '\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043E\u0442\u0432\u0435\u0442',
enterEquivalent: '\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0447\u0438\u0441\u043B\u043E',
@@ -111,6 +115,55 @@ function applyTranslations() {
});
}
function refreshDynamicText() {
const active = document.querySelector('.screen.active');
if (!active) return;
switch (active.id) {
case 'screen-setup-system':
renderSetupSystem();
break;
case 'screen-setup-range':
renderSetupRange();
break;
case 'screen-setup-options':
document.querySelectorAll('#setup-modes .option-btn').forEach((btn, i) => {
btn.textContent = t(MODES[i].labelKey);
});
[...document.getElementById('setup-timing').options].forEach((opt, i) => {
opt.textContent = TIMINGS[i].value === 0 ? t('noLimit') : TIMINGS[i].value + ' ' + t('sec');
});
break;
case 'screen-theory-system':
renderTheorySystem();
break;
case 'screen-theory-content':
document.getElementById('theory-title').textContent = systemName(lastTheoryKey);
break;
case 'screen-game':
if (game.system && game.range) {
document.getElementById('score-system-range').textContent = systemName(game.system) + ': ' + game.range.label;
}
break;
case 'screen-results': {
const completed = game.currentRound >= game.rounds;
const total = completed ? game.rounds : game.currentRound;
const pct = total > 0 ? Math.round((game.correctCount / total) * 100) : 0;
document.getElementById('results-summary').innerHTML =
'<div class="big-number">' + game.correctCount + '/' + total + '</div>' +
'<div>' + t('pctCorrect', {pct: pct}) + '</div>';
const labelEl = document.getElementById('results-mistakes-label');
if (game.mistakes.length > 0 || labelEl.style.display !== 'none') {
labelEl.textContent = t('mistakes');
}
const congratsEl = document.getElementById('results-congrats');
if (congratsEl.textContent) {
congratsEl.textContent = t('congratulations');
}
break;
}
}
}
const SYSTEM_RANGES = {
binary: [
{ label: '2\u2070 \u2013 2\u00B3', min: 1, max: 8 },
@@ -185,6 +238,9 @@ const SYSTEM_GROUPS = {
nonpos: ['roman', 'greek', 'slavonic', 'hebrew'],
};
const theoryCache = {};
let lastTheoryKey = null;
const MODES = [
{ labelKey: 'choose', value: 'choice' },
{ labelKey: 'type', value: 'manual' },
@@ -217,9 +273,23 @@ let game = {
mistakes: [],
};
let popstateHandled = false;
let navDepth = 0;
function showScreen(id) {
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
document.getElementById('screen-' + id).classList.add('active');
if (id === 'menu') {
if (navDepth > 0) {
const n = navDepth;
navDepth = 0;
history.go(-n);
}
} else if (!popstateHandled) {
navDepth++;
history.pushState({ screen: id }, '');
}
popstateHandled = false;
}
function shuffle(arr) {
@@ -344,7 +414,7 @@ const MARK_INCORRECT = '\u2717 ';
function startGame() {
lastSetupState = { ...setupState };
game.system = setupState.system;
game.range = setupState.rangeData || RANGES[setupState.range];
game.range = setupState.rangeData;
game.mode = MODES[setupState.mode]?.value ?? setupState.mode;
game.timing = TIMINGS[setupState.timing]?.value ?? setupState.timing;
game.rounds = ROUNDS[setupState.rounds];
@@ -700,6 +770,58 @@ function spawnConfetti() {
}
}
// ---- THEORY ----
async function loadTheory(key) {
if (theoryCache[key]) return theoryCache[key];
try {
const resp = await fetch(`theory/${key}.${LANG}.html`);
if (!resp.ok) throw new Error(resp.status);
const html = await resp.text();
theoryCache[key] = html;
return html;
} catch {
if (LANG !== 'en') {
try {
const resp = await fetch(`theory/${key}.en.html`);
const html = await resp.text();
theoryCache[key] = html;
return html;
} catch { return null; }
}
return null;
}
}
function renderTheorySystem() {
const posDiv = document.getElementById('theory-systems-pos');
const nonposDiv = document.getElementById('theory-systems-nonpos');
posDiv.innerHTML = '';
nonposDiv.innerHTML = '';
for (const [group, keys] of Object.entries(SYSTEM_GROUPS)) {
const target = group === 'pos' ? posDiv : nonposDiv;
keys.forEach(key => {
const btn = document.createElement('button');
btn.className = 'option-btn';
btn.textContent = systemName(key);
btn.addEventListener('click', () => showTheoryContent(key));
target.appendChild(btn);
});
}
showScreen('theory-system');
}
async function showTheoryContent(key) {
lastTheoryKey = key;
const html = await loadTheory(key);
document.getElementById('theory-title').textContent = systemName(key);
document.getElementById('theory-scroll').innerHTML =
html || '<div class="theory-unavailable">' + t('theoryUnavailable') + '</div>';
showScreen('theory-content');
}
// ---- INIT ----
const SUBSCRIPTS = { '0':'\u2080', '1':'\u2081', '2':'\u2082', '3':'\u2083',
@@ -727,9 +849,6 @@ function getPreferredTheme() {
return window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
}
const isLightTheme = getPreferredTheme() === 'light';
const TICKER_COLORS = isLightTheme ? TICKER_COLORS_LIGHT : TICKER_COLORS_DARK;
const TICKER_SYSTEMS = [
{ key: 'binary', min: 1, max: 255, suffix: toSubscript(2) },
{ key: 'base3', min: 1, max: 81, suffix: toSubscript(3) },
@@ -743,6 +862,9 @@ const TICKER_SYSTEMS = [
];
function generateTickerText() {
const palette = document.documentElement.dataset.theme === 'light'
? TICKER_COLORS_LIGHT
: TICKER_COLORS_DARK;
const pairs = [];
let lastKey = null;
let lastColor = null;
@@ -755,7 +877,7 @@ function generateTickerText() {
let color;
do {
color = TICKER_COLORS[Math.floor(Math.random() * TICKER_COLORS.length)];
color = palette[Math.floor(Math.random() * palette.length)];
} while (color === lastColor);
lastColor = color;
const num = sys.min + Math.floor(Math.random() * (sys.max - sys.min + 1));
@@ -771,8 +893,10 @@ function generateTickerText() {
return pairs.join('\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0');
}
const tickerText = generateTickerText();
document.getElementById('ticker').innerHTML = tickerText + '\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0' + tickerText;
function refreshTicker() {
const tickerText = generateTickerText();
document.getElementById('ticker').innerHTML = tickerText + '\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0' + tickerText;
}
const langSelect = document.getElementById('lang-select');
langSelect.value = LANG;
@@ -780,6 +904,7 @@ langSelect.addEventListener('change', () => {
LANG = langSelect.value;
localStorage.setItem('numnum-lang', LANG);
applyTranslations();
refreshDynamicText();
});
applyTranslations();
@@ -787,6 +912,7 @@ applyTranslations();
function applyTheme(theme) {
document.documentElement.dataset.theme = theme;
document.getElementById('theme-toggle').textContent = theme === 'dark' ? '\u2600' : '\u263E';
refreshTicker();
}
applyTheme(getPreferredTheme());
@@ -855,7 +981,8 @@ document.getElementById('btn-options-back').addEventListener('click', () => {
});
document.getElementById('btn-play').addEventListener('click', () => {
if (setupState.mode === undefined || setupState.timing === undefined || setupState.rounds === undefined) {
if (!setupState.system || !setupState.rangeData ||
setupState.mode === undefined || setupState.timing === undefined || setupState.rounds === undefined) {
showSetupMessage(t('pleaseSelect'));
return;
}
@@ -875,6 +1002,18 @@ document.getElementById('btn-results-menu').addEventListener('click', () => {
showScreen('menu');
});
document.getElementById('btn-theory').addEventListener('click', () => {
renderTheorySystem();
});
document.getElementById('btn-theory-back').addEventListener('click', () => {
showScreen('menu');
});
document.getElementById('btn-theory-content-back').addEventListener('click', () => {
renderTheorySystem();
});
document.getElementById('btn-stop').addEventListener('click', () => {
stopTimer();
endGame();
@@ -909,3 +1048,26 @@ document.addEventListener('keydown', (e) => {
}
}
});
// Handle mobile back/cancel button
const BACK_MAP = {
'screen-setup-system': 'btn-system-back',
'screen-setup-range': 'btn-range-back',
'screen-setup-options': 'btn-options-back',
'screen-game': 'btn-stop',
'screen-results': 'btn-results-menu',
'screen-theory-system': 'btn-theory-back',
'screen-theory-content': 'btn-theory-content-back',
};
window.addEventListener('popstate', () => {
navDepth = Math.max(0, navDepth - 1);
const active = document.querySelector('.screen.active');
if (!active) return;
const btnId = BACK_MAP[active.id];
if (btnId) {
popstateHandled = true;
document.getElementById(btnId).click();
}
});
+29 -3
View File
@@ -10,7 +10,7 @@
<link rel="manifest" href="manifest.json">
<link rel="icon" type="image/svg+xml" href="icon.svg">
<link rel="apple-touch-icon" href="icon-192.png">
<link rel="stylesheet" href="styles.css?v=20">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="app">
@@ -24,6 +24,7 @@
<div class="ticker" id="ticker"></div>
</div>
<button class="btn btn-primary btn-large" id="btn-start" data-i18n="startGame">Start Game</button>
<button class="btn btn-secondary btn-large" id="btn-theory" data-i18n="theory">Theory</button>
<div class="menu-controls">
<select id="lang-select" class="lang-select">
<option value="en">English</option>
@@ -165,12 +166,37 @@
</div>
</div>
<!-- THEORY: SYSTEM SELECTION -->
<div id="screen-theory-system" class="screen">
<div class="setup-container">
<h2 data-i18n="chooseSystem">Choose numeral system</h2>
<div class="system-group">
<h3 data-i18n="nonPositional">Non-Positional</h3>
<div id="theory-systems-nonpos" class="option-grid"></div>
</div>
<div class="system-group">
<h3 data-i18n="positional">Positional</h3>
<div id="theory-systems-pos" class="option-grid"></div>
</div>
<button class="btn btn-secondary" id="btn-theory-back" data-i18n="back">Back</button>
</div>
</div>
<!-- THEORY: CONTENT -->
<div id="screen-theory-content" class="screen">
<div class="theory-container">
<h2 id="theory-title"></h2>
<div class="theory-scroll" id="theory-scroll"></div>
<button class="btn btn-secondary" id="btn-theory-content-back" data-i18n="back">Back</button>
</div>
</div>
</div>
<script type="module" src="app.js?v=20"></script>
<script type="module" src="app.js"></script>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js?v=20').catch(() => {});
navigator.serviceWorker.register('/sw.js').catch(() => {});
}
</script>
</body>
+93 -3
View File
@@ -73,13 +73,31 @@ html[data-theme="light"] {
font-display: swap;
}
@font-face {
font-family: 'Noto Sans Symbols 2';
src: url('NotoSansSymbols2-subset.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
unicode-range: U+232B, U+23F1, U+2600, U+2713, U+2717, U+2801, U+2803, U+2809-280B, U+2811, U+2813, U+2819-281B, U+283C, U+2B95;
}
@font-face {
font-family: 'Noto Sans Symbols 2';
src: url('NotoSansMath-subset.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
unicode-range: U+2295-2296, U+263E;
}
html, body {
height: 100%;
overflow: hidden;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans Symbols 2', sans-serif;
background: var(--bg);
color: var(--text);
-webkit-tap-highlight-color: transparent;
@@ -189,7 +207,7 @@ body {
white-space: nowrap;
color: var(--text-dim);
font-size: 1.3rem;
font-family: monospace;
font-family: 'Noto Sans Symbols 2', monospace;
animation: ticker-scroll 40s linear infinite;
}
@@ -455,7 +473,7 @@ body {
}
.number-display.mono {
font-family: monospace;
font-family: 'Noto Sans Symbols 2', monospace;
}
.ticker .slavonic-font {
@@ -748,3 +766,75 @@ body {
opacity: 0;
}
}
/* THEORY */
.theory-container {
display: flex;
flex-direction: column;
height: 100%;
padding: 24px;
padding-top: calc(24px + var(--safe-top));
padding-bottom: calc(24px + var(--safe-bottom));
max-width: 600px;
margin: 0 auto;
width: 100%;
}
.theory-container h2 {
flex-shrink: 0;
margin-bottom: 16px;
}
.theory-scroll {
flex: 1;
overflow-y: auto;
padding-right: 8px;
}
.theory-scroll h3 {
color: var(--accent);
font-size: 1rem;
text-transform: uppercase;
letter-spacing: 1px;
margin: 24px 0 8px;
}
.theory-scroll h3:first-child {
margin-top: 0;
}
.theory-scroll p {
line-height: 1.6;
margin-bottom: 12px;
color: var(--text);
}
.theory-scroll .theory-example {
background: var(--bg-card);
border-radius: 8px;
padding: 16px;
font-family: 'Noto Sans Symbols 2', monospace;
font-size: 1.1rem;
margin: 12px 0;
text-align: center;
letter-spacing: 2px;
}
.theory-unavailable {
text-align: center;
opacity: 0.65;
padding: 24px 0;
}
.theory-scroll .slavonic-font {
font-family: 'Ponomar', serif;
font-size: 1.4rem;
}
#btn-theory-content-back {
flex-shrink: 0;
margin-top: 16px;
max-width: 320px;
margin-left: auto;
margin-right: auto;
}
+33 -2
View File
@@ -1,4 +1,4 @@
const CACHE_NAME = 'numnum-v20';
const CACHE_NAME = 'numnum-v28';
const ASSETS = [
'/',
'/index.html',
@@ -9,11 +9,42 @@ const ASSETS = [
'/icon.svg',
'/icon-192.png',
'/icon-512.png',
'/Ponomar-Regular.woff',
'/NotoSansSymbols2-subset.woff2',
'/NotoSansMath-subset.woff2',
'/theory/base3.en.html',
'/theory/base3.ru.html',
'/theory/binary.en.html',
'/theory/binary.ru.html',
'/theory/braille.en.html',
'/theory/braille.ru.html',
'/theory/greek.en.html',
'/theory/greek.ru.html',
'/theory/hebrew.en.html',
'/theory/hebrew.ru.html',
'/theory/hex.en.html',
'/theory/hex.ru.html',
'/theory/octal.en.html',
'/theory/octal.ru.html',
'/theory/roman.en.html',
'/theory/roman.ru.html',
'/theory/slavonic.en.html',
'/theory/slavonic.ru.html',
'/theory/ternary.en.html',
'/theory/ternary.ru.html',
];
self.addEventListener('install', (e) => {
e.waitUntil(
caches.open(CACHE_NAME).then(cache => cache.addAll(ASSETS))
caches.open(CACHE_NAME).then(cache =>
Promise.allSettled(ASSETS.map(url => cache.add(url)))
).then(results => {
results.forEach((r, i) => {
if (r.status === 'rejected') {
console.warn('SW precache failed:', ASSETS[i], r.reason);
}
});
})
);
self.skipWaiting();
});
+8
View File
@@ -0,0 +1,8 @@
<h3>Base: 3</h3>
<p>The ternary (base-3) numeral system uses three digits: 0, 1, and 2. Each position represents a power of 3.</p>
<h3>How it works</h3>
<div class="theory-example">112 = 1×9 + 1×3 + 2×1 = 14</div>
<h3>Digits</h3>
<div class="theory-example">0 1 2</div>
<h3>Uses</h3>
<p>Ternary systems are used in some specialized computing applications (ternary logic). Some argue that base-3 is the most efficient integer base for computation, as it is the closest to the mathematical constant e ≈ 2.718.</p>
+8
View File
@@ -0,0 +1,8 @@
<h3>Троичная</h3>
<p>Троичная (несимметрично-троичная) система счисления использует три цифры: 0, 1 и 2. Каждая позиция представляет степень тройки.</p>
<h3>Как работает</h3>
<div class="theory-example">112 = 1×9 + 1×3 + 2×1 = 14</div>
<h3>Цифры</h3>
<div class="theory-example">0 1 2</div>
<h3>Применение</h3>
<p>Троичная система используется в некоторых специализированных вычислениях (троичная логика). Некоторые считают, что троичная система является наиболее эффективной для вычислений, поскольку близка к математической константе e ≈ 2,718.</p>
+9
View File
@@ -0,0 +1,9 @@
<h3>Base: 2</h3>
<p>The binary (base-2) numeral system uses only two digits: 0 and 1. It is the fundamental language of digital computers, where each digit represents a single bit — an electrical signal that is either off (0) or on (1).</p>
<h3>How it works</h3>
<p>Each position represents a power of 2, increasing from right to left:</p>
<div class="theory-example">1011 = 1×8 + 0×4 + 1×2 + 1×1 = 11</div>
<h3>Digits</h3>
<div class="theory-example">0 1</div>
<h3>Uses</h3>
<p>Binary is used internally by all modern computers. File storage, memory addresses, and network protocols all rely on binary representation at the lowest level.</p>
+9
View File
@@ -0,0 +1,9 @@
<h3>Двоичная система</h3>
<p>Двоичная система счисления использует только две цифры: 0 и 1. Это основной язык цифровых компьютеров, где каждый бит представляет электрический сигнал — выключен (0) или включен (1).</p>
<h3>Как работает</h3>
<p>Каждая позиция представляет степень двойки, увеличиваясь справа налево:</p>
<div class="theory-example">1011 = 1×8 + 0×4 + 1×2 + 1×1 = 11</div>
<h3>Цифры</h3>
<div class="theory-example">0 1</div>
<h3>Применение</h3>
<p>Двоичная система используется внутри всеми современными компьютерами. Хранение файлов, адреса памяти и сетевые протоколы работают на двоичном представлении на нижнем уровне.</p>
+9
View File
@@ -0,0 +1,9 @@
<h3>Braille Decimal</h3>
<p>Braille is a tactile writing system used by people who are visually impaired. Each digit is represented by a specific pattern of raised dots within a 2×3 cell. In this app, the Braille decimal system encodes digits 09.</p>
<h3>Pattern</h3>
<p>Each digit is preceded by the number indicator (⠼), which signals that the following characters represent numbers rather than letters.</p>
<h3>Digits (09)</h3>
<div class="theory-example">⠼⠚ ⠼⠁ ⠼⠃ ⠼⠉ ⠼⠙ ⠼⠑ ⠼⠋ ⠼⠛ ⠼⠓ ⠼⠊</div>
<p>These correspond to: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9</p>
<h3>Uses</h3>
<p>Braille numerals are used in Braille books, signage, and electronic Braille displays. The number sign distinguishes numeric content from alphabetic text.</p>
+9
View File
@@ -0,0 +1,9 @@
<h3>Десятичная система, шрифт Брайля</h3>
<p>Шрифт Брайля — это тактильная система письма, используемая людьми с нарушениями зрения. Каждая цифра представлена специальным паттерном выпуклых точек в ячейке 2×3. Цифры обозначаются теми же знаками, что и первые десять букв алфавита (A-K), но ей предшествует индикатор номера.</p>
<h3>Структура</h3>
<p>Каждая цифра предварена индикатором номера (⠼), который сигнализирует, что следующие символы являются числами.</p>
<h3>Цифры (09)</h3>
<div class="theory-example">⠼⠚ ⠼⠁ ⠼⠃ ⠼⠉ ⠼⠙ ⠼⠑ ⠼⠋ ⠼⠛ ⠼⠓ ⠼⠊</div>
<p>Соответствуют: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9</p>
<h3>Применение</h3>
<p>Шрифтовые числа используются в книгах и информационных табличках для незрячих, на досках и электронных брайлевских дисплеях.</p>
+15
View File
@@ -0,0 +1,15 @@
<h3>Greek Numerals</h3>
<p>Greek numerals are a decimal system that uses letters of the Greek alphabet to represent numbers. Known as Ionian or alphabetic numerals, this system was adopted around the 4th century BC.</p>
<h3>How it works</h3>
<p>Letters are assigned values from 1 to 9 (units), 10 to 90 (tens), and 100 to 900 (hundreds). A special mark (, keraia) is placed after the number. Thousands are indicated by a subscript mark (͵) before the units letter.</p>
<h3>Units (19)</h3>
<div class="theory-example">α β γ δ ε ϛ ζ η θ</div>
<p>(α=1, β=2, γ=3, δ=4, ε=5, ϛ=6, ζ=7, η=8, θ=9)</p>
<h3>Tens (1090)</h3>
<div class="theory-example">ι κ λ μ ν ξ ο π ϟ</div>
<p>(ι=10, κ=20, λ=30, μ=40, ν=50, ξ=60, ο=70, π=80, ϟ=90)</p>
<h3>Hundreds (100900)</h3>
<div class="theory-example">ρ σ τ υ φ χ ψ ω ϡ</div>
<p>(ρ=100, σ=200, τ=300, υ=400, φ=500, χ=600, ψ=700, ω=800, ϡ=900)</p>
<h3>Example</h3>
<div class="theory-example">ηπε = 8 + 80 + 5 = 93</div>
+18
View File
@@ -0,0 +1,18 @@
<h3>Греческие числа</h3>
<p>Греческие числа — алфавитная система записи десятичных чисел, использующая буквы греческого алфавита. Известна как ионическая или новогреческая, была популярна с IV-III века до н.э. и стала образцом для других алфавитных систем, в частности церковнославянской и еврейской</p>
<h3>Как работает</h3>
<p>Буквам присваиваются значения от 1 до 9 (единицы), 10 до 90 (десятки) и 100 до 900 (сотни). Число завершается символом кераия (´). Тысячи обозначаются индиксом (͵) перед буквой единиц.</p>
<h3>Единицы (19)</h3>
<div class="theory-example">α β γ δ ε ϛ ζ η θ</div>
<p>(α=1, β=2, γ=3, δ=4, ε=5, ϛ=6, ζ=7, η=8, θ=9)</p>
<h3>Десятки (1090)</h3>
<div class="theory-example">ι κ λ μ ν ξ ο π ϟ</div>
<p>(ι=10, κ=20, λ=30, μ=40, ν=50, ξ=60, ο=70, π=80, ϟ=90)</p>
<h3>Сотни (100900)</h3>
<div class="theory-example">ρ σ τ υ φ χ ψ ω ϡ</div>
<p>(ρ=100, σ=200, τ=300, υ=400, φ=500, χ=600, ψ=700, ω=800, ϡ=900)</p>
<h3>Пример</h3>
<div class="theory-example">ηπε = 8 + 80 + 5 = 93</div>
<h3>Применение</h3>
<p>До сих пор иногда используется для записи ординальных чисел в Греции.</p>
+22
View File
@@ -0,0 +1,22 @@
<h3>Hebrew Numerals</h3>
<p>Hebrew numerals are an alphanumeric system where letters of the Hebrew alphabet are assigned numerical values. Known as "gematria," this system has been used for centuries in Jewish tradition.</p>
<h3>How it works</h3>
<p>Letters represent values from 19 (units), 1090 (tens), and 100400 (hundreds). Numbers are written by combining letters, with the larger values first. A single apostrophe (geresh, ׳) follows single-letter numbers, and a double apostrophe (gershayim, ״) is placed before the last letter of multi-letter numbers.</p>
<h3>Special cases</h3>
<p>15 and 16 use טו and טז instead of יה and יו to avoid writing God's name.</p>
<h3>Units (19)</h3>
<div class="theory-example">א ב ג ד ה ו ז ח ט</div>
<p>(א=1, ב=2, ג=3, ד=4, ה=5, ו=6, ז=7, ח=8, ט=9)</p>
<h3>Tens (1090)</h3>
<div class="theory-example">י כ ל מ נ ס ע פ צ</div>
<p>(י=10, כ=20, ל=30, מ=40, נ=50, ס=60, ע=70, פ=80, צ=90)</p>
<h3>Hundreds (100400)</h3>
<div class="theory-example">ק ר ש ת</div>
<p>(ק=100, ר=200, ש=300, ת=400)</p>
<h3>Beyond 400</h3>
<p>Numbers above 400 are written additively by combining tav (400) with hundreds:</p>
<div class="theory-example">500 = ת״ק = 400 + 100<br>900 = תת״ק = 400 + 400 + 100</div>
<p>Thousands are written as the units letter followed by geresh:</p>
<div class="theory-example">1000 = א׳<br>5000 = ה׳</div>
<h3>Example</h3>
<div class="theory-example">5786 = ה׳תשפ״ו = 5000 + 400 + 300 + 80 + 6</div>
+22
View File
@@ -0,0 +1,22 @@
<h3>Еврейские числа</h3>
<p>Еврейские числа — алфавитная система, в которой буквам алфавита присваиваются числовые значения. Известна как гематрия, эта система является адаптацией греческой записи чисел и получила распространение около II в до н.э., заменив более древние системы на базе Арамейского и Финикийского алфаитов.</p>
<h3>Как работает</h3>
<p>Буквы представляют значения 1–9 (единицы), 10–90 (десятки) и 100–400 (сотни). Числа пишутся комбинацией букв, по правилу от больших к меньшим. Однобуквенные числа завершаются герешем (׳), многобуквенные — гершайми (״) перед последней буквой.</p>
<h3>Специальные случаи</h3>
<p>15 и 16 пишутся как טו и טז вместо יה и יו, чтобы не писать имя Б-га.</p>
<h3>Единицы (19)</h3>
<div class="theory-example">א ב ג ד ה ו ז ח ט</div>
<p>(א=1, ב=2, ג=3, ד=4, ה=5, ו=6, ז=7, ח=8, ט=9)</p>
<h3>Десятки (1090)</h3>
<div class="theory-example">י כ ל מ נ ס ע פ צ</div>
<p>(י=10, כ=20, ל=30, מ=40, נ=50, ס=60, ע=70, פ=80, צ=90)</p>
<h3>Сотни (100400)</h3>
<div class="theory-example">ק ר ש ת</div>
<p>(ק=100, ר=200, ש=300, ת=400)</p>
<h3>Свыше 400</h3>
<p>Числа более 400 записываются аддитивно сочетанием ת (400) с сотными:</p>
<div class="theory-example">500 = ת״ק = 400 + 100<br>900 = תת״ק = 400 + 400 + 100</div>
<p>Тысячи обозначаются буквой единиц с герешом:</p>
<div class="theory-example">1000 = א׳<br>5000 = ה׳</div>
<h3>Пример</h3>
<div class="theory-example">5786 = ה׳תשפ״ו = 5000 + 400 + 300 + 80 + 6</div>
+8
View File
@@ -0,0 +1,8 @@
<h3>Base: 16</h3>
<p>The hexadecimal (base-16) numeral system uses sixteen symbols: the digits 09 and the letters AF (representing values 1015).</p>
<h3>How it works</h3>
<div class="theory-example">1A3 = 1×256 + 10×16 + 3×1 = 419</div>
<h3>Digits</h3>
<div class="theory-example">0 1 2 3 4 5 6 7 8 9 A B C D E F</div>
<h3>Uses</h3>
<p>Hexadecimal is ubiquitous in computing. Memory addresses, color codes in CSS (#E94560), MAC addresses, and file hashes all use hex because each hex digit maps to exactly four binary digits, making it a compact and human-readable representation of binary data.</p>
+8
View File
@@ -0,0 +1,8 @@
<h3>Шестнадцатеричная система</h3>
<p>Шестнадцатеричная система счисления использует шестнадцать символов: цифры 0–9 и буквы A–F (значения 10–15).</p>
<h3>Как работает</h3>
<div class="theory-example">1A3 = 1×256 + 10×16 + 3×1 = 419</div>
<h3>Цифры</h3>
<div class="theory-example">0 1 2 3 4 5 6 7 8 9 A B C D E F</div>
<h3>Применение</h3>
<p>Шестнадцатеричная система повсеместно используется в компьютерной технике для компактной записи значений байт, поскольку каждая шестнадцатерная цифра соответствует четырем двоичным или полубайту.</p>
+8
View File
@@ -0,0 +1,8 @@
<h3>Base: 8</h3>
<p>The octal (base-8) numeral system uses eight digits: 0 through 7. Each position represents a power of 8.</p>
<h3>How it works</h3>
<div class="theory-example">177 = 1×64 + 7×8 + 7×1 = 127</div>
<h3>Digits</h3>
<div class="theory-example">0 1 2 3 4 5 6 7</div>
<h3>Uses</h3>
<p>Octal was widely used in early computing (e.g. PDP-8, IBM mainframes) because it provides a compact way to represent binary numbers: each octal digit maps to exactly three binary digits. Today it appears in Unix file permissions (chmod 755) and some legacy systems.</p>
+8
View File
@@ -0,0 +1,8 @@
<h3>Восьмеричная система</h3>
<p>Восьмеричная система счисления использует восемь цифр: 0–7. Каждая позиция представляет степень восьми.</p>
<h3>Как работает</h3>
<div class="theory-example">177 = 1×64 + 7×8 + 7×1 = 127</div>
<h3>Цифры</h3>
<div class="theory-example">0 1 2 3 4 5 6 7</div>
<h3>Применение</h3>
<p>Восьмеричная система была распространена в раннем программировании (например PDP-8, главные ЭВМ IBM), т.к. каждая восьмеричная цифра соответствует трем двоичным. Сейчас встречается в правах доступа к файлам Unix (chmod 755) и некоторых устаревших системах.</p>
+11
View File
@@ -0,0 +1,11 @@
<h3>Roman Numerals</h3>
<p>Roman numerals originated in ancient Rome and remained the standard way of writing numbers throughout Europe well into the Middle Ages. They use combinations of letters from the Latin alphabet.</p>
<h3>Symbols</h3>
<div class="theory-example">I = 1 V = 5 X = 10 L = 50 C = 100 D = 500 M = 1000</div>
<h3>How it works</h3>
<p>Roman numerals are primarily additive: values are summed left to right. However, a smaller value placed before a larger one indicates subtraction:</p>
<div class="theory-example">IV = 5 1 = 4 IX = 10 1 = 9<br>XL = 50 10 = 40 XC = 100 10 = 90 CM = 1000 100 = 900</div>
<h3>Examples</h3>
<div class="theory-example">XLII = 40 + 2 = 42<br><br>MCMXCIV = 1000 + 900 + 90 + 4 = 1994</div>
<h3>Rules</h3>
<p>Roman numerals can represent numbers from 1 to 3999. I, X, C, and M can be repeated up to three times. V, L, and D are never repeated. The subtractive combinations IV, IX, XL, XC, CM, and CD are the only allowed subtractions.</p>
+11
View File
@@ -0,0 +1,11 @@
<h3>Римские числа</h3>
<p>Римские числа возникли в древнем Риме и оставались стандартным способом записи чисел в Европе до Средневековья. Они используют буквы латинского алфавита.</p>
<h3>Символы</h3>
<div class="theory-example">I = 1 V = 5 X = 10 L = 50 C = 100 D = 500 M = 1000</div>
<h3>Как работает</h3>
<p>Римские числа преимущественно аддитивны: значения складываются слева направо. Однако меньшая цифра перед большей означает вычитание:</p>
<div class="theory-example">IV = 5 1 = 4 IX = 10 1 = 9<br>XL = 50 10 = 40 XC = 100 10 = 90 CM = 1000 100 = 900</div>
<h3>Примеры</h3>
<div class="theory-example">XLII = 40 + 2 = 42<br><br>MCMXCIV = 1000 + 900 + 90 + 4 = 1994</div>
<h3>Правила</h3>
<p>Римские числа могут представлять числа от 1 до 3999. I, X, C и M могут повторяться до трех раз. V, L и D никогда не повторяются.</p>
+15
View File
@@ -0,0 +1,15 @@
<h3>Church Slavonic Numerals</h3>
<p>Church Slavonic numerals are a Cyrillic alphanumeric system used historically in Russian and other Slavic Orthodox cultures. Letters of the early Cyrillic alphabet are assigned numerical values.</p>
<h3>How it works</h3>
<p>Like Greek numerals, Church Slavonic uses separate letter groups for units (19), tens (1090), and hundreds (100900). A titlo mark (<span class="slavonic-font"> ҃</span>) is placed above one of the letters to indicate it is a number. Thousands are marked with a special symbol (<span class="slavonic-font">҂</span>) placed before the number. The number ends with a period.</p>
<h3>Units (19)</h3>
<div class="theory-example slavonic-font">а в г д є ѕ з и ѳ</div>
<p>(<span class="slavonic-font">а</span>=1, <span class="slavonic-font">в</span>=2, <span class="slavonic-font">г</span>=3, <span class="slavonic-font">д</span>=4, <span class="slavonic-font">є</span>=5, <span class="slavonic-font">ѕ</span>=6, <span class="slavonic-font">з</span>=7, <span class="slavonic-font">и</span>=8, <span class="slavonic-font">ѳ</span>=9)</p>
<h3>Tens (1090)</h3>
<div class="theory-example slavonic-font">і к л м н ѯ ѻ п ч</div>
<p>(<span class="slavonic-font">і</span>=10, <span class="slavonic-font">к</span>=20, <span class="slavonic-font">л</span>=30, <span class="slavonic-font">м</span>=40, <span class="slavonic-font">н</span>=50, <span class="slavonic-font">ѯ</span>=60, <span class="slavonic-font">ѻ</span>=70, <span class="slavonic-font">п</span>=80, <span class="slavonic-font">ч</span>=90)</p>
<h3>Hundreds (100900)</h3>
<div class="theory-example slavonic-font">р с т у ф х ѱ Ѿ ц</div>
<p>(<span class="slavonic-font">р</span>=100, <span class="slavonic-font">с</span>=200, <span class="slavonic-font">т</span>=300, <span class="slavonic-font">у</span>=400, <span class="slavonic-font">ф</span>=500, <span class="slavonic-font">х</span>=600, <span class="slavonic-font">ѱ</span>=700, <span class="slavonic-font">Ѿ</span>=800, <span class="slavonic-font">ц</span>=900)</p>
<h3>Example</h3>
<div class="theory-example slavonic-font">цп҃з. = 900 + 80 + 3 = 983</div>
+15
View File
@@ -0,0 +1,15 @@
<h3>Церковнославянские числа</h3>
<p>Церковнославянские числа — кириллическая цифровая система, использующаяся в русской и других славянских православных культурах. Буквы древней кириллической азбуки, имеющие греческие аналоги, имеют числовые значения, равные значениям в греческой системе записи.</p>
<h3>Как работает</h3>
<p>Используются отдельные группы букв для единиц (1–9), десятков (10–90) и сотен (100–900). Над буквой ставится титло (<span class="slavonic-font"> ҃</span>). Тысячи обозначаются специальным знаком (<span class="slavonic-font">҂</span>). Число завершается точкой.</p>
<h3>Единицы (19)</h3>
<div class="theory-example slavonic-font">а в г д є ѕ з и ѳ</div>
<p>(<span class="slavonic-font">а</span>=1, <span class="slavonic-font">в</span>=2, <span class="slavonic-font">г</span>=3, <span class="slavonic-font">д</span>=4, <span class="slavonic-font">є</span>=5, <span class="slavonic-font">ѕ</span>=6, <span class="slavonic-font">з</span>=7, <span class="slavonic-font">и</span>=8, <span class="slavonic-font">ѳ</span>=9)</p>
<h3>Десятки (1090)</h3>
<div class="theory-example slavonic-font">і к л м н ѯ ѻ п ч</div>
<p>(<span class="slavonic-font">і</span>=10, <span class="slavonic-font">к</span>=20, <span class="slavonic-font">л</span>=30, <span class="slavonic-font">м</span>=40, <span class="slavonic-font">н</span>=50, <span class="slavonic-font">ѯ</span>=60, <span class="slavonic-font">ѻ</span>=70, <span class="slavonic-font">п</span>=80, <span class="slavonic-font">ч</span>=90)</p>
<h3>Сотни (100900)</h3>
<div class="theory-example slavonic-font">р с т у ф х ѱ Ѿ ц</div>
<p>(<span class="slavonic-font">р</span>=100, <span class="slavonic-font">с</span>=200, <span class="slavonic-font">т</span>=300, <span class="slavonic-font">у</span>=400, <span class="slavonic-font">ф</span>=500, <span class="slavonic-font">х</span>=600, <span class="slavonic-font">ѱ</span>=700, <span class="slavonic-font">Ѿ</span>=800, <span class="slavonic-font">ц</span>=900)</p>
<h3>Пример</h3>
<div class="theory-example slavonic-font">цп҃з. = 900 + 80 + 3 = 983</div>
+11
View File
@@ -0,0 +1,11 @@
<h3>Balanced Ternary: Base 3 with signed digits</h3>
<p>Balanced ternary is a positional Base 3 system where non-zero digits are signed: 1, 0, or +1. Instead of using the digits -1 and +1, any suitable symbols can be used, we use circled - and +:</p>
<h3>Digits</h3>
<div class="theory-example">⊖ = 1, 0 = 0, ⊕ = +1</div>
<p>⊖ (Circled Minus) represents 1, and ⊕ (Circled Plus) represents +1.</p>
<h3>How it works</h3>
<p>Each position represents a power of 3, but positions can be negative:</p>
<div class="theory-example">⊕0⊖ = (+1)×9 + 0×3 + (1)×1 = 8</div>
<div class="theory-example">⊖⊕0 = (-1)×9 + (+1)×3 + 0×1 = -6</div>
<h3>Properties</h3>
<p>Balanced ternary has the unique property that the sign of a number can be determined from its most significant non-zero digit, eliminating the need for a separate sign. For negative numbers, the signs of all non-zero digits are flipped (⊕ ↔ ⊖). The system was studied by Leonardo Pisano (Fibonacci, 11701250) in connection with the weight problem — using weights of powers of 3, any integer mass from 1 can be measured with the fewest weights. In 1958, the Soviet engineer Nikolai Brusentsov built the Setun computer at Moscow State University, which used balanced ternary arithmetic and became one of the most elegant ternary computers.</p>
+11
View File
@@ -0,0 +1,11 @@
<h3>Симметричная троичная система</h3>
<p>Симметричная (уравновешенная) троичная система — это позиционная система по основанию три, использующая цифры со значениями −1, 0 или +1. Значения -1 и +1 для удобства могут обозначаться по-разному, любыми подходящими симполами, стандарта не существует. Мы используем знаки "-" и "+" в окружностях:</p>
<h3>Цифры</h3>
<div class="theory-example">⊖ = 1, 0 = 0, ⊕ = +1</div>
<p>⊖ (Кружок с минусом) обозначает −1, а ⊕ (Кружок с плюсом) — +1.</p>
<h3>Как работает</h3>
<p>Каждая позиция представляет степень тройки, значение в позиции становится отрицательным, если в нем стоит -1:</p>
<div class="theory-example">⊕0⊖ = (+1)×9 + 0×3 + (1)×1 = 8</div>
<div class="theory-example">⊖⊕0 = (-1)×9 + (+1)×3 + 0×1 = -6</div>
<h3>Свойства</h3>
<p>Самая экономичная среди целочисленных позиционных систем. В симметричной троичной системе знак числа определяется по первой ненулевой цифре старшего разряда, что устраняет необходимость использовать отдельный знак для отрицательных чисел. Для смены знака числа ненулевые цифры инвертируются (⊕ ↔ ⊖). Эту систему изучал Леонардо Писано (Фибоначчи, 1170–1250) в связи с задачей о гирях: используя гири массой со степенями тройки, любую целую массу можно отвесить минимальным числом гирь. В 1958 году советский инженер Николай Брусенцов спроектировал ЭВМ Сетунь, который использовал симметрично-троичную арифметику и стал одним из самых элегантных троичных компьютеров.</p>