Глава руководства рядом с программой, свои программы, переключатели и кнопка
- глава из руководства показывается под ответом машины для выбранной программы, на телефоне выше списка программ; блок игр внизу убран - свои программы сохраняются в localStorage, их можно удалять - переключатель: красный диск с белыми буквами, поворот на 90 градусов - кнопка на схеме обозначена по ГОСТ, а не ключом Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f4c22f36de
commit
5c28814b3e
+89
-50
@@ -59,7 +59,7 @@ h1 { font-family: var(--font-display); font-weight: 800; font-size: clamp(28px,
|
|||||||
@media (max-width: 1100px) { .bench { grid-template-columns: minmax(0, 1fr); } }
|
@media (max-width: 1100px) { .bench { grid-template-columns: minmax(0, 1fr); } }
|
||||||
.pane { display: grid; gap: 10px; min-width: 0; }
|
.pane { display: grid; gap: 10px; min-width: 0; }
|
||||||
.pane-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 6px 16px; }
|
.pane-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 6px 16px; }
|
||||||
.pane h2, .lower h2, .book h2 { font-family: var(--font-display); font-weight: 700; font-size: 13px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin: 0; }
|
.pane h2, .lower h2 { font-family: var(--font-display); font-weight: 700; font-size: 13px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin: 0; }
|
||||||
svg.view { width: 100%; height: auto; display: block; user-select: none; -webkit-user-select: none; touch-action: manipulation; }
|
svg.view { width: 100%; height: auto; display: block; user-select: none; -webkit-user-select: none; touch-action: manipulation; }
|
||||||
svg#dlm { filter: drop-shadow(0 14px 22px rgba(10, 20, 50, .22)); }
|
svg#dlm { filter: drop-shadow(0 14px 22px rgba(10, 20, 50, .22)); }
|
||||||
svg#inside { border-radius: 14px; background: var(--bp-bg); }
|
svg#inside { border-radius: 14px; background: var(--bp-bg); }
|
||||||
@@ -93,8 +93,9 @@ svg .hit:focus-visible .focusring { stroke: var(--blue); stroke-width: 4; }
|
|||||||
@keyframes run { to { stroke-dashoffset: -18; } }
|
@keyframes run { to { stroke-dashoffset: -18; } }
|
||||||
@media (prefers-reduced-motion: reduce) { #inside .flow { animation: none; stroke-dasharray: none; } * { transition: none !important; } }
|
@media (prefers-reduced-motion: reduce) { #inside .flow { animation: none; stroke-dasharray: none; } * { transition: none !important; } }
|
||||||
|
|
||||||
.lower { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) minmax(0, 1fr); gap: 24px; align-items: start; }
|
.lower { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) minmax(0, 1fr); grid-template-rows: auto 1fr; grid-template-areas: "progs tt cols" "progs book book"; gap: 24px; align-items: start; }
|
||||||
@media (max-width: 1100px) { .lower { grid-template-columns: minmax(0, 1fr); } }
|
.progs-box { grid-area: progs; } .tt-box { grid-area: tt; } .cols-box { grid-area: cols; } .lower > .book { grid-area: book; }
|
||||||
|
@media (max-width: 1100px) { .lower { grid-template-columns: minmax(0, 1fr); grid-template-areas: "book" "progs" "tt" "cols"; } }
|
||||||
.lower > div { display: grid; gap: 10px; min-width: 0; }
|
.lower > div { display: grid; gap: 10px; min-width: 0; }
|
||||||
.programs { display: grid; gap: 6px; }
|
.programs { display: grid; gap: 6px; }
|
||||||
.prog { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; text-align: left; width: 100%; padding: 9px 12px; border-radius: 10px;
|
.prog { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; text-align: left; width: 100%; padding: 9px 12px; border-radius: 10px;
|
||||||
@@ -105,6 +106,7 @@ svg .hit:focus-visible .focusring { stroke: var(--blue); stroke-width: 4; }
|
|||||||
.prog .t { font-weight: 700; }
|
.prog .t { font-weight: 700; }
|
||||||
.prog .src { font-size: 12px; color: var(--muted); align-self: center; white-space: nowrap; }
|
.prog .src { font-size: 12px; color: var(--muted); align-self: center; white-space: nowrap; }
|
||||||
.prog .d { grid-column: 1 / -1; font-size: 13px; color: var(--muted); }
|
.prog .d { grid-column: 1 / -1; font-size: 13px; color: var(--muted); }
|
||||||
|
.prog-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px; align-items: stretch; }
|
||||||
.group-label { font-size: 12px; color: var(--muted); margin: 8px 0 2px; }
|
.group-label { font-size: 12px; color: var(--muted); margin: 8px 0 2px; }
|
||||||
.tt-wrap { overflow-x: auto; }
|
.tt-wrap { overflow-x: auto; }
|
||||||
table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size: 14px; width: 100%; font-variant-numeric: tabular-nums; }
|
table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size: 14px; width: 100%; font-variant-numeric: tabular-nums; }
|
||||||
@@ -121,17 +123,13 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
.exprs .n, .exprs .to { color: var(--muted); }
|
.exprs .n, .exprs .to { color: var(--muted); }
|
||||||
.exprs .dead { color: var(--muted); font-style: italic; font-family: var(--font-body); }
|
.exprs .dead { color: var(--muted); font-style: italic; font-family: var(--font-body); }
|
||||||
|
|
||||||
.book { background: var(--surface); border: 1px solid var(--line); border-radius: 6px; padding-block: 36px 40px; padding-inline: clamp(18px, 5vw, 64px); display: grid; gap: 34px; }
|
.book { background: var(--surface); border: 1px solid var(--line); border-radius: 6px; padding: 24px clamp(16px, 3vw, 36px); display: grid; gap: 16px; }
|
||||||
.book-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px 24px; align-items: baseline; }
|
|
||||||
.book-head p { margin: 0; color: var(--muted); max-width: 60ch; }
|
|
||||||
.page { font-family: var(--font-book); max-width: 68ch; display: grid; gap: 12px; }
|
.page { font-family: var(--font-book); max-width: 68ch; display: grid; gap: 12px; }
|
||||||
.page h3 { font-family: var(--font-book); font-size: 20px; margin: 0; letter-spacing: .04em; }
|
.page h3 { font-family: var(--font-book); font-size: 20px; margin: 0; letter-spacing: .04em; }
|
||||||
.page h3 .gn { letter-spacing: .3em; font-weight: 400; }
|
.page h3 .gn { letter-spacing: .3em; font-weight: 400; }
|
||||||
.page p { margin: 0; text-indent: 1.6em; hyphens: auto; }
|
.page p { margin: 0; text-indent: 1.6em; hyphens: auto; }
|
||||||
.page p.noind { text-indent: 0; }
|
.page p.noind { text-indent: 0; }
|
||||||
.note { font-family: var(--font-body); font-size: 14px; color: var(--muted); border-left: 3px solid var(--line); padding-left: 12px; max-width: 68ch; margin: 0; }
|
.note { font-family: var(--font-body); font-size: 14px; color: var(--muted); border-left: 3px solid var(--line); padding-left: 12px; max-width: 68ch; margin: 0; }
|
||||||
.btn { display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px; border-radius: 999px; background: var(--accent); color: var(--accent-ink); border: 0; font: 700 14px var(--font-body); cursor: pointer; justify-self: start; }
|
|
||||||
.btn:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
|
|
||||||
.sources { font-size: 14px; color: var(--muted); }
|
.sources { font-size: 14px; color: var(--muted); }
|
||||||
.sources a { color: var(--blue); }
|
.sources a { color: var(--blue); }
|
||||||
</style>
|
</style>
|
||||||
@@ -159,8 +157,9 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
<label><input type="checkbox" id="latch"> Держать кнопку нажатой</label>
|
<label><input type="checkbox" id="latch"> Держать кнопку нажатой</label>
|
||||||
<button class="ghost" type="button" id="mid">Переключатели в среднее положение</button>
|
<button class="ghost" type="button" id="mid">Переключатели в среднее положение</button>
|
||||||
<button class="ghost" type="button" id="clear">Снять всё</button>
|
<button class="ghost" type="button" id="clear">Снять всё</button>
|
||||||
|
<button class="ghost" type="button" id="save">Сохранить программу</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="explain">Гнездо: вставить или вынуть штеккер. Пружина, затем вторая пружина: поставить перемычку. Перемычка: снять. Переключатель: щелчок по ручке или по «0» и «1».</p>
|
<p class="explain">Гнездо: вставить или вынуть штеккер. Пружина, затем вторая пружина: поставить перемычку. Перемычка: снять. Переключатель: щелчок по ручке или по «0» и «1». Свою программу можно сохранить: она останется в этом браузере.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pane">
|
<div class="pane">
|
||||||
@@ -173,80 +172,67 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="lower">
|
<section class="lower">
|
||||||
<div>
|
<div class="progs-box">
|
||||||
<h2>Программы</h2>
|
<h2>Программы</h2>
|
||||||
<div class="programs" id="programs"></div>
|
<div class="programs" id="programs"></div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="tt-box">
|
||||||
<h2>Что ответит машина</h2>
|
<h2>Что ответит машина</h2>
|
||||||
<div class="tt-wrap"><table class="tt" id="tt"></table></div>
|
<div class="tt-wrap"><table class="tt" id="tt"></table></div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="cols-box">
|
||||||
<h2>Столбцы программирования</h2>
|
<h2>Столбцы программирования</h2>
|
||||||
<ul class="exprs" id="exprs"></ul>
|
<ul class="exprs" id="exprs"></ul>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
<article class="book" id="book">
|
||||||
|
<h2 id="book-h">О программе</h2>
|
||||||
<article class="book" id="book">
|
<section class="page" id="ch-other">
|
||||||
<div class="book-head">
|
<h3 id="ch-title"></h3>
|
||||||
<h2>Игры из руководства 1987 года</h2>
|
<p class="noind" id="ch-desc"></p>
|
||||||
<p>Правила сокращены по оригинальной брошюре. Кнопка под каждой игрой набирает программу с её рисунка: штеккеры и перемычки ставятся точно как на рисунке.</p>
|
|
||||||
</div>
|
|
||||||
<section class="page">
|
|
||||||
<h3>Как читать ответ</h3>
|
|
||||||
<p>Ввод — переключатели А (4), Б (2), В (1): числа от 0 до 7. Вывод — лампы V (8), X (4), Y (2), Z (1): горящая лампа означает «1», «Да», «Правильно». Сумма чисел над горящими лампами даёт ответ от 0 до 15.</p>
|
<p>Ввод — переключатели А (4), Б (2), В (1): числа от 0 до 7. Вывод — лампы V (8), X (4), Y (2), Z (1): горящая лампа означает «1», «Да», «Правильно». Сумма чисел над горящими лампами даёт ответ от 0 до 15.</p>
|
||||||
<p>Штеккер в левом гнезде замыкает звено столбца, когда переключатель стоит на «1», в правом — на «0». Столбец срабатывает, если замкнуты все три его звена. Перемычки соединяют столбцы с лампами.</p>
|
<p>Штеккер в левом гнезде замыкает звено столбца, когда переключатель стоит на «1», в правом — на «0». Столбец срабатывает, если замкнуты все три его звена. Перемычки соединяют столбцы с лампами.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="page" id="game1">
|
<section class="page" id="game1">
|
||||||
<h3><span class="gn">Игра 1.</span> Какое число задумано?</h3>
|
<h3><span class="gn">Игра 1.</span> Какое число задумано?</h3>
|
||||||
<p>Играющий задумывает число от 0 до 7 и отвечает на три вопроса. «Да» — переключатель в «1», «Нет» — в «0».</p>
|
<p>Играющий задумывает число от 0 до 7 и отвечает на три вопроса. «Да» — переключатель в «1», «Нет» — в «0».</p>
|
||||||
<p class="noind">А: Задуманное число чётное? (Ноль — чётное.)<br>Б: Сумма задуманного числа и следующего за ним меньше восьми?<br>В: К задуманному числу прибавьте 10 и разделите на 6. Остаток 4 или 5?</p>
|
<p class="noind">А: Задуманное число чётное? (Ноль — чётное.)<br>Б: Сумма задуманного числа и следующего за ним меньше восьми?<br>В: К задуманному числу прибавьте 10 и разделите на 6. Остаток 4 или 5?</p>
|
||||||
<p>Лампы X, Y, Z показывают задуманное число. Пример: для 5 все ответы «Нет», горят X и Z: 101 = 5.</p>
|
<p>Лампы X, Y, Z показывают задуманное число. Пример: для 5 все ответы «Нет», горят X и Z: 101 = 5.</p>
|
||||||
<button class="btn" type="button" data-load="game1">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="page" id="game2">
|
<section class="page" id="game2">
|
||||||
<h3><span class="gn">Игра 2.</span> Честные и лгуны</h3>
|
<h3><span class="gn">Игра 2.</span> Честные и лгуны</h3>
|
||||||
<p>В стране живут честные (всегда говорят правду) и лгуны (всегда лгут). На вопрос «Вы честный или лгун?» житель x отвечает на непонятном языке.</p>
|
<p>В стране живут честные (всегда говорят правду) и лгуны (всегда лгут). На вопрос «Вы честный или лгун?» житель x отвечает на непонятном языке.</p>
|
||||||
<p class="noind">А: житель y: «Он сказал, что он честный» — «1», «…что он лгун» — «0».<br>Б: житель z о жителе x: «честный» — «1», «лгун» — «0».<br>В: житель z о жителе y: «честный» — «1», «лгун» — «0».</p>
|
<p class="noind">А: житель y: «Он сказал, что он честный» — «1», «…что он лгун» — «0».<br>Б: житель z о жителе x: «честный» — «1», «лгун» — «0».<br>В: житель z о жителе y: «честный» — «1», «лгун» — «0».</p>
|
||||||
<p>Горящие X, Y, Z означают, что x, y, z честные. Пример: Дима (x) честный, Витя (y) и Коля (z) лгуны. Ответы 0, 0, 1 — горит только X.</p>
|
<p>Горящие X, Y, Z означают, что x, y, z честные. Пример: Дима (x) честный, Витя (y) и Коля (z) лгуны. Ответы 0, 0, 1 — горит только X.</p>
|
||||||
<button class="btn" type="button" data-load="game2">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="page" id="game3">
|
<section class="page" id="game3">
|
||||||
<h3><span class="gn">Игра 3.</span> Сумма трёх чисел</h3>
|
<h3><span class="gn">Игра 3.</span> Сумма трёх чисел</h3>
|
||||||
<p>Играющий тайком бросает кубик и запоминает число. Его ответы на вопросы игры 1 фиксируются планками А, Б, В. Затем он бросает ещё раз, запоминает верхнее число и число на противоположной грани и складывает все три.</p>
|
<p>Играющий тайком бросает кубик и запоминает число. Его ответы на вопросы игры 1 фиксируются планками А, Б, В. Затем он бросает ещё раз, запоминает верхнее число и число на противоположной грани и складывает все три.</p>
|
||||||
<p>Нажмите кнопку: лампы покажут сумму. Пример: 5, затем 4 и 3, сумма 12. Ответы «Нет, Нет, Нет», горят V и X: 1100 = 12.</p>
|
<p>Нажмите кнопку: лампы покажут сумму. Пример: 5, затем 4 и 3, сумма 12. Ответы «Нет, Нет, Нет», горят V и X: 1100 = 12.</p>
|
||||||
<button class="btn" type="button" data-load="game3">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="page" id="game4">
|
<section class="page" id="game4">
|
||||||
<h3><span class="gn">Игра 4.</span> Двенадцать — выигрыш!</h3>
|
<h3><span class="gn">Игра 4.</span> Двенадцать — выигрыш!</h3>
|
||||||
<p>Противник бросает кубик первым. Дальше игроки по очереди поворачивают кубик на одну из боковых граней и прибавляют её число к сумме. Кто первым наберёт ровно 12, тот выиграл.</p>
|
<p>Противник бросает кубик первым. Дальше игроки по очереди поворачивают кубик на одну из боковых граней и прибавляют её число к сумме. Кто первым наберёт ровно 12, тот выиграл.</p>
|
||||||
<p>Введите текущую сумму (если она больше 7, вычтите 8). Лампы X, Y, Z покажут число, которое нужно поставить наверх. Если такой грани сбоку нет, берите ближайшее меньшее. Пример: выпало 2, машина говорит 2, но двойка сверху, ставим 1 (сумма 3). Противник делает 5, машина 4 (сумма 9). Противник делает 10, вводим 2, машина 2, сумма 12.</p>
|
<p>Введите текущую сумму (если она больше 7, вычтите 8). Лампы X, Y, Z покажут число, которое нужно поставить наверх. Если такой грани сбоку нет, берите ближайшее меньшее. Пример: выпало 2, машина говорит 2, но двойка сверху, ставим 1 (сумма 3). Противник делает 5, машина 4 (сумма 9). Противник делает 10, вводим 2, машина 2, сумма 12.</p>
|
||||||
<button class="btn" type="button" data-load="game4">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="page" id="game5">
|
<section class="page" id="game5">
|
||||||
<h3><span class="gn">Игра 5.</span> Какой предмет выбран?</h3>
|
<h3><span class="gn">Игра 5.</span> Какой предмет выбран?</h3>
|
||||||
<p>Возьмите 24 спички. Игроки № 1, 2, 3 берут 1, 2 и 3 спички и тайком делят фишки А, Б, В. Затем владелец А добирает столько же, сколько взял, владелец Б — вдвое больше, владелец В — вчетверо.</p>
|
<p>Возьмите 24 спички. Игроки № 1, 2, 3 берут 1, 2 и 3 спички и тайком делят фишки А, Б, В. Затем владелец А добирает столько же, сколько взял, владелец Б — вдвое больше, владелец В — вчетверо.</p>
|
||||||
<p>Введите число оставшихся спичек. Пара V X — игрок № 1, пара Y Z — игрок № 2. Код: 00 — фишка А, 01 — Б, 10 — В. Если все лампы погашены, правила нарушены. Пример: осталось 5, горят X и Y. Игрок № 1 — Б, игрок № 2 — В, игроку № 3 досталась А.</p>
|
<p>Введите число оставшихся спичек. Пара V X — игрок № 1, пара Y Z — игрок № 2. Код: 00 — фишка А, 01 — Б, 10 — В. Если все лампы погашены, правила нарушены. Пример: осталось 5, горят X и Y. Игрок № 1 — Б, игрок № 2 — В, игроку № 3 досталась А.</p>
|
||||||
<button class="btn" type="button" data-load="game5">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="page" id="game6">
|
<section class="page" id="game6">
|
||||||
<h3><span class="gn">Игра 6.</span> ДЛМ превосходит себя!</h3>
|
<h3><span class="gn">Игра 6.</span> ДЛМ превосходит себя!</h3>
|
||||||
<p>Всё как в игре 5, но оператор не узнаёт, сколько спичек осталось. Он задаёт одному из игроков вопросы игры 1 про это число и читает ответ по коду игры 5.</p>
|
<p>Всё как в игре 5, но оператор не узнаёт, сколько спичек осталось. Он задаёт одному из игроков вопросы игры 1 про это число и читает ответ по коду игры 5.</p>
|
||||||
<button class="btn" type="button" data-load="game6">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="page" id="game7">
|
<section class="page" id="game7">
|
||||||
<h3><span class="gn">Игра 7.</span> Семь спичек</h3>
|
<h3><span class="gn">Игра 7.</span> Семь спичек</h3>
|
||||||
<p>Двое по очереди берут со стола одну или две спички в «общий котёл», пока стол не опустеет. Потом в том же порядке возвращают по одной-две. Выигрывает тот, кто положит седьмую. Противник ходит первым.</p>
|
<p>Двое по очереди берут со стола одну или две спички в «общий котёл», пока стол не опустеет. Потом в том же порядке возвращают по одной-две. Выигрывает тот, кто положит седьмую. Противник ходит первым.</p>
|
||||||
<p>Вводите число спичек, уже взятых (во второй половине — уже положенных). Лампы покажут, сколько их должно стать после вашего хода. Во второй половине вместо 2 вводите 111, вместо 5 — 110.</p>
|
<p>Вводите число спичек, уже взятых (во второй половине — уже положенных). Лампы покажут, сколько их должно стать после вашего хода. Во второй половине вместо 2 вводите 111, вместо 5 — 110.</p>
|
||||||
<button class="btn" type="button" data-load="game7">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="page" id="game8">
|
<section class="page" id="game8">
|
||||||
<h3><span class="gn">Игра 8.</span> Зоологические карточки</h3>
|
<h3><span class="gn">Игра 8.</span> Зоологические карточки</h3>
|
||||||
<p>Двенадцать карточек (по 4 птицы, зверя, насекомых) лежат тремя стопками рубашкой вверх, возле стопок в любом порядке — надписи. Берите верхнюю карточку стопки «Птицы» и кладите к нужной надписи. Затем берите карточку из той стопки, куда положили, и так далее.</p>
|
<p>Двенадцать карточек (по 4 птицы, зверя, насекомых) лежат тремя стопками рубашкой вверх, возле стопок в любом порядке — надписи. Берите верхнюю карточку стопки «Птицы» и кладите к нужной надписи. Затем берите карточку из той стопки, куда положили, и так далее.</p>
|
||||||
<p class="noind">А: нижняя карточка у надписи «Насекомые» — насекомое?<br>Б: нижняя карточка у надписи «Звери» — зверь?<br>В: среди двух просмотренных карточек есть птица?</p>
|
<p class="noind">А: нижняя карточка у надписи «Насекомые» — насекомое?<br>Б: нижняя карточка у надписи «Звери» — зверь?<br>В: среди двух просмотренных карточек есть птица?</p>
|
||||||
<p>V, X, Y — возможен полный успех. Только X — сойдутся птицы или насекомые. Только Y — птицы или звери. Только Z — птицы, вероятно, и остальные. Ничего не горит — сойдутся только птицы.</p>
|
<p>V, X, Y — возможен полный успех. Только X — сойдутся птицы или насекомые. Только Y — птицы или звери. Только Z — птицы, вероятно, и остальные. Ничего не горит — сойдутся только птицы.</p>
|
||||||
<button class="btn" type="button" data-load="game8">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="page" id="game9">
|
<section class="page" id="game9">
|
||||||
<h3><span class="gn">Игра 9.</span> ДЛМ — экзаменатор</h3>
|
<h3><span class="gn">Игра 9.</span> ДЛМ — экзаменатор</h3>
|
||||||
@@ -256,7 +242,6 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
<b>3.</b> В каком виде идёт обработка? 100 — в двоичном коде; 101 — на языке программирования.<br>
|
<b>3.</b> В каком виде идёт обработка? 100 — в двоичном коде; 101 — на языке программирования.<br>
|
||||||
<b>4.</b> Почему ВМ и считает, и выполняет логические операции? 110 — она обрабатывает аналоговые данные; 111 — она построена на логических схемах, имитирующих алгебру Буля.</p>
|
<b>4.</b> Почему ВМ и считает, и выполняет логические операции? 110 — она обрабатывает аналоговые данные; 111 — она построена на логических схемах, имитирующих алгебру Буля.</p>
|
||||||
<p class="noind">Комментарии: 000 — Да (алгебра Буля); 001 — Нет (нужна программа); 010 — Нет (обработка цифровая); 011 — Да (ВМ работает по программе); 100 — Да (двоичный код); 101 — Нет (это внешние устройства); 110 — Нет (язык программирования нужен для общения с машиной); 111 — Да (центральный блок и внешние устройства).</p>
|
<p class="noind">Комментарии: 000 — Да (алгебра Буля); 001 — Нет (нужна программа); 010 — Нет (обработка цифровая); 011 — Да (ВМ работает по программе); 100 — Да (двоичный код); 101 — Нет (это внешние устройства); 110 — Нет (язык программирования нужен для общения с машиной); 111 — Да (центральный блок и внешние устройства).</p>
|
||||||
<button class="btn" type="button" data-load="game9">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="page" id="game10">
|
<section class="page" id="game10">
|
||||||
<h3><span class="gn">Игра 10.</span> Ваш характер</h3>
|
<h3><span class="gn">Игра 10.</span> Ваш характер</h3>
|
||||||
@@ -266,18 +251,17 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
III. Нравится ли тебе, когда тебя хвалят? Доволен ли ты собой? Любишь ли ты говорить о себе?<br>
|
III. Нравится ли тебе, когда тебя хвалят? Доволен ли ты собой? Любишь ли ты говорить о себе?<br>
|
||||||
IV. Доводишь ли ты начатое дело до конца? Настойчиво ли ты добиваешься своей цели? Проявляешь ли ты инициативу в работе?</p>
|
IV. Доводишь ли ты начатое дело до конца? Настойчиво ли ты добиваешься своей цели? Проявляешь ли ты инициативу в работе?</p>
|
||||||
<p class="note">Шестнадцать характеристик, от «0000 — замкнутый, скромный, целеустремлённый, но ленивый» до «1111 — деятельный, откровенный, но беспринципный и себялюбивый», приведены в полном тексте руководства.</p>
|
<p class="note">Шестнадцать характеристик, от «0000 — замкнутый, скромный, целеустремлённый, но ленивый» до «1111 — деятельный, откровенный, но беспринципный и себялюбивый», приведены в полном тексте руководства.</p>
|
||||||
<button class="btn" type="button" data-load="game10">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="page" id="game11">
|
<section class="page" id="game11">
|
||||||
<h3><span class="gn">Игра 11.</span> Автоматическое управление лифтом</h3>
|
<h3><span class="gn">Игра 11.</span> Автоматическое управление лифтом</h3>
|
||||||
<p>А — направление до вызова (1 — вверх). Б — вызов вверх. В — вызов вниз.</p>
|
<p>А — направление до вызова (1 — вверх). Б — вызов вверх. В — вызов вниз.</p>
|
||||||
<p>X — дверь разблокирована. Y — мотор работает. Z — лифт поедет вверх. При двух вызовах сразу лифт сохраняет прежнее направление.</p>
|
<p>X — дверь разблокирована. Y — мотор работает. Z — лифт поедет вверх. При двух вызовах сразу лифт сохраняет прежнее направление.</p>
|
||||||
<button class="btn" type="button" data-load="game11">Набрать программу на машине ↑</button>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="sources">
|
<section class="sources">
|
||||||
<div>Источник: «Игрушка Детская логическая машина ДЛМ. Руководство по эксплуатации». ВНИИ «Электронстандарт», Гатчина, 1987 — <a href="DLM_rukovodstvo_1987.pdf">скачать PDF</a> (сканы, набранный текст и расшифровка рисунков программ). Логические элементы взяты из статьи <a href="https://habr.com/ru/articles/807187/" target="_blank" rel="noopener">«Криптография и другие вычисления на детских логических машинах»</a> (Хабр).</div>
|
<div>Источник: «Игрушка Детская логическая машина ДЛМ. Руководство по эксплуатации». ВНИИ «Электронстандарт», Гатчина, 1987 — <a href="DLM_rukovodstvo_1987.pdf">скачать PDF</a> (сканы, набранный текст и расшифровка рисунков программ). Логические элементы взяты из статьи <a href="https://habr.com/ru/articles/807187/" target="_blank" rel="noopener">«Криптография и другие вычисления на детских логических машинах»</a> (Хабр).</div>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -352,8 +336,15 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
// inp[r]: 1, 0 or null (middle position: every contact of that plank is open)
|
// inp[r]: 1, 0 or null (middle position: every contact of that plank is open)
|
||||||
const S = { pins: [], wires: [], inp: [null, null, null], pressed: false, latch: false, sel: null, prog: null };
|
const S = { pins: [], wires: [], inp: [null, null, null], pressed: false, latch: false, sel: null, prog: null };
|
||||||
|
|
||||||
|
// own programs: same shape as PROGRAMS, no group
|
||||||
|
const UKEY = 'dlm-user-programs';
|
||||||
|
let userProgs = [];
|
||||||
|
try { userProgs = JSON.parse(localStorage.getItem(UKEY)) || []; } catch (e) {}
|
||||||
|
const saveUser = () => { try { localStorage.setItem(UKEY, JSON.stringify(userProgs)); } catch (e) {} };
|
||||||
|
const allProgs = () => PROGRAMS.concat(userProgs);
|
||||||
|
|
||||||
function loadProgram(id) {
|
function loadProgram(id) {
|
||||||
const p = PROGRAMS.find(x => x.id === id);
|
const p = allProgs().find(x => x.id === id);
|
||||||
S.pins = p.rows.map(r => [...r].map(ch => [ch === 'L' || ch === 'B', ch === 'R' || ch === 'B']));
|
S.pins = p.rows.map(r => [...r].map(ch => [ch === 'L' || ch === 'B', ch === 'R' || ch === 'B']));
|
||||||
S.wires = p.wires.map(w => [...w]);
|
S.wires = p.wires.map(w => [...w]);
|
||||||
S.inp = [null, null, null]; // the booklet: set the switches to the middle before placing pins
|
S.inp = [null, null, null]; // the booklet: set the switches to the middle before placing pins
|
||||||
@@ -413,7 +404,6 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
const LSPR_Y = 182, CSPR_LOW = 268, CSPR_HIGH = 226;
|
const LSPR_Y = 182, CSPR_LOW = 268, CSPR_HIGH = 226;
|
||||||
const colSprY = c => c % 2 ? CSPR_HIGH : CSPR_LOW; // springs of columns 2, 4, 6 sit higher
|
const colSprY = c => c % 2 ? CSPR_HIGH : CSPR_LOW; // springs of columns 2, 4, 6 sit higher
|
||||||
const SW_Y = ROW_Y.map(y => y + PLANK_H / 2);
|
const SW_Y = ROW_Y.map(y => y + PLANK_H / 2);
|
||||||
const INK = '#2a2d33';
|
|
||||||
|
|
||||||
E('defs').innerHTML = `
|
E('defs').innerHTML = `
|
||||||
<filter id="glow" x="-80%" y="-80%" width="260%" height="260%"><feGaussianBlur stdDeviation="9"/></filter>
|
<filter id="glow" x="-80%" y="-80%" width="260%" height="260%"><feGaussianBlur stdDeviation="9"/></filter>
|
||||||
@@ -512,10 +502,12 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
const g = E('g', { class: 'hit', tabindex: 0, role: 'switch' });
|
const g = E('g', { class: 'hit', tabindex: 0, role: 'switch' });
|
||||||
E('circle', { cx: 896, cy, r: 40, fill: '#efede6', stroke: '#b7b3a7', 'stroke-width': 3, class: 'focusring' }, g);
|
E('circle', { cx: 896, cy, r: 40, fill: '#efede6', stroke: '#b7b3a7', 'stroke-width': 3, class: 'focusring' }, g);
|
||||||
const knob = E('g', { style: `transition: transform .18s ease; transform-origin: 896px ${cy}px` }, g);
|
const knob = E('g', { style: `transition: transform .18s ease; transform-origin: 896px ${cy}px` }, g);
|
||||||
E('rect', { x: 881, y: cy - 40, width: 30, height: 80, rx: 4, fill: '#f8f7f2', stroke: INK, 'stroke-width': 2 }, knob);
|
// red disc with a bar handle, as on the real machine; white marks show which way it is turned
|
||||||
E('line', { x1: 896, y1: cy - 12, x2: 896, y2: cy + 12, stroke: INK, 'stroke-width': 2 }, knob);
|
E('circle', { cx: 896, cy, r: 31, fill: '#c8222c', stroke: '#8f141d', 'stroke-width': 2 }, knob);
|
||||||
E('text', { x: 896, y: cy - 18, 'text-anchor': 'middle', 'font-family': 'PT Sans, sans-serif', 'font-style': 'italic', 'font-size': 18, fill: INK }, knob).textContent = name;
|
E('rect', { x: 882, y: cy - 38, width: 28, height: 76, rx: 5, fill: '#d42a35', stroke: '#8f141d', 'stroke-width': 2 }, knob);
|
||||||
E('text', { x: 896, y: cy + 33, 'text-anchor': 'middle', 'font-family': 'PT Sans, sans-serif', 'font-style': 'italic', 'font-size': 18, fill: INK }, knob).textContent = [4, 2, 1][r];
|
E('line', { x1: 896, y1: cy - 10, x2: 896, y2: cy + 10, stroke: '#fff', 'stroke-width': 2.5 }, knob);
|
||||||
|
E('text', { x: 896, y: cy - 17, 'text-anchor': 'middle', 'font-family': 'PT Sans, sans-serif', 'font-weight': 700, 'font-size': 18, fill: '#fff' }, knob).textContent = name;
|
||||||
|
E('text', { x: 896, y: cy + 31, 'text-anchor': 'middle', 'font-family': 'PT Sans, sans-serif', 'font-weight': 700, 'font-size': 18, fill: '#fff' }, knob).textContent = [4, 2, 1][r];
|
||||||
g.addEventListener('click', () => setSwitch(r, S.inp[r] === null ? 1 : 1 - S.inp[r]));
|
g.addEventListener('click', () => setSwitch(r, S.inp[r] === null ? 1 : 1 - S.inp[r]));
|
||||||
return { g, knob };
|
return { g, knob };
|
||||||
});
|
});
|
||||||
@@ -563,8 +555,12 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
T(64, 201, '4,5 В', { 'font-size': 12 });
|
T(64, 201, '4,5 В', { 'font-size': 12 });
|
||||||
I('circle', { cx: 96, cy: BUS_Y, r: 4, fill: BP.txt });
|
I('circle', { cx: 96, cy: BUS_Y, r: 4, fill: BP.txt });
|
||||||
I('circle', { cx: 150, cy: BUS_Y, r: 4, fill: BP.txt });
|
I('circle', { cx: 150, cy: BUS_Y, r: 4, fill: BP.txt });
|
||||||
const btnBlade = I('line', { x1: 96, y1: BUS_Y, x2: 146, y2: BUS_Y - 24, stroke: BP.txt, 'stroke-width': 3, 'stroke-linecap': 'round' });
|
// push button, normally open: a bridge over the two contacts, a stem and a pusher; pressing drops the bridge
|
||||||
T(123, BUS_Y - 28, 'кнопка', { 'text-anchor': 'middle', 'font-size': 12 });
|
const btnBlade = I('g', { style: 'transition: transform .12s ease' });
|
||||||
|
I('line', { x1: 90, y1: BUS_Y - 10, x2: 156, y2: BUS_Y - 10, stroke: BP.txt, 'stroke-width': 3, 'stroke-linecap': 'round' }, btnBlade);
|
||||||
|
I('line', { x1: 123, y1: BUS_Y - 10, x2: 123, y2: BUS_Y - 28, stroke: BP.txt, 'stroke-width': 2 }, btnBlade);
|
||||||
|
I('line', { x1: 113, y1: BUS_Y - 28, x2: 133, y2: BUS_Y - 28, stroke: BP.txt, 'stroke-width': 3, 'stroke-linecap': 'round' }, btnBlade);
|
||||||
|
T(123, BUS_Y - 36, 'кнопка', { 'text-anchor': 'middle', 'font-size': 12 });
|
||||||
T(IX(6) + 8, BUS_Y + 5, 'шина +', { 'font-size': 12 });
|
T(IX(6) + 8, BUS_Y + 5, 'шина +', { 'font-size': 12 });
|
||||||
T(ILX(3) + 8, NEG_Y + 5, 'шина −', { 'font-size': 12 });
|
T(ILX(3) + 8, NEG_Y + 5, 'шина −', { 'font-size': 12 });
|
||||||
|
|
||||||
@@ -673,22 +669,65 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
document.getElementById('mid').addEventListener('click', () => { S.inp = [null, null, null]; update(); save(); });
|
document.getElementById('mid').addEventListener('click', () => { S.inp = [null, null, null]; update(); save(); });
|
||||||
document.getElementById('clear').addEventListener('click', () => loadProgram('empty'));
|
document.getElementById('clear').addEventListener('click', () => loadProgram('empty'));
|
||||||
|
|
||||||
|
// ---- own programs, kept in this browser ----
|
||||||
|
document.getElementById('save').addEventListener('click', () => {
|
||||||
|
const cur = userProgs.find(p => p.id === S.prog);
|
||||||
|
const name = prompt('Название программы', cur ? cur.t : 'Моя программа')?.trim();
|
||||||
|
if (!name) return;
|
||||||
|
const p = {
|
||||||
|
id: 'u' + Date.now(), t: name, src: '', d: `Штеккеров: ${pinCount()}, перемычек: ${S.wires.length}.`,
|
||||||
|
rows: S.pins.map(row => row.map(([l, r]) => l && r ? 'B' : l ? 'L' : r ? 'R' : '.').join('')), wires: S.wires.map(w => [...w])
|
||||||
|
};
|
||||||
|
userProgs = userProgs.filter(x => x.t !== name).concat(p); // the same name overwrites
|
||||||
|
saveUser(); S.prog = p.id; renderPrograms(); update(); save();
|
||||||
|
});
|
||||||
|
function deleteUser(p) {
|
||||||
|
if (!confirm(`Удалить программу «${p.t}»?`)) return;
|
||||||
|
userProgs = userProgs.filter(x => x !== p);
|
||||||
|
if (S.prog === p.id) S.prog = null;
|
||||||
|
saveUser(); renderPrograms(); update(); save();
|
||||||
|
}
|
||||||
|
|
||||||
// ---- lower panels ----
|
// ---- lower panels ----
|
||||||
const progBox = document.getElementById('programs');
|
const progBox = document.getElementById('programs');
|
||||||
|
let progBtns = [];
|
||||||
|
function renderPrograms() {
|
||||||
|
progBox.innerHTML = '';
|
||||||
let lastGroup = null;
|
let lastGroup = null;
|
||||||
const progBtns = PROGRAMS.map(p => {
|
progBtns = allProgs().map(p => {
|
||||||
if (p.group !== lastGroup) { lastGroup = p.group; const d = document.createElement('div'); d.className = 'group-label'; d.textContent = p.group; progBox.appendChild(d); }
|
const group = p.group || 'Мои программы';
|
||||||
|
if (group !== lastGroup) { lastGroup = group; const d = document.createElement('div'); d.className = 'group-label'; d.textContent = group; progBox.appendChild(d); }
|
||||||
const b = document.createElement('button');
|
const b = document.createElement('button');
|
||||||
b.type = 'button'; b.className = 'prog'; b.id = 'prog-' + p.id;
|
b.type = 'button'; b.className = 'prog';
|
||||||
b.innerHTML = `<span class="t"></span><span class="src"></span><span class="d"></span>`;
|
b.innerHTML = `<span class="t"></span><span class="src"></span><span class="d"></span>`;
|
||||||
b.querySelector('.t').textContent = p.t; b.querySelector('.src').textContent = p.src; b.querySelector('.d').textContent = p.d;
|
b.querySelector('.t').textContent = p.t; b.querySelector('.src').textContent = p.src; b.querySelector('.d').textContent = p.d;
|
||||||
b.addEventListener('click', () => loadProgram(p.id));
|
b.addEventListener('click', () => loadProgram(p.id));
|
||||||
progBox.appendChild(b);
|
if (p.group) progBox.appendChild(b);
|
||||||
|
else {
|
||||||
|
const row = document.createElement('div'), del = document.createElement('button');
|
||||||
|
row.className = 'prog-row';
|
||||||
|
del.type = 'button'; del.className = 'ghost'; del.textContent = '×'; del.title = 'Удалить';
|
||||||
|
del.setAttribute('aria-label', `Удалить программу «${p.t}»`);
|
||||||
|
del.addEventListener('click', () => deleteUser(p));
|
||||||
|
row.append(b, del); progBox.appendChild(row);
|
||||||
|
}
|
||||||
return [p.id, b];
|
return [p.id, b];
|
||||||
});
|
});
|
||||||
document.querySelectorAll('[data-load]').forEach(b => b.addEventListener('click', () => {
|
}
|
||||||
loadProgram(b.dataset.load); svg.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
renderPrograms();
|
||||||
}));
|
|
||||||
|
// the chapter of the booklet for the chosen program, or a note on it
|
||||||
|
const book = document.getElementById('book'), chOther = document.getElementById('ch-other');
|
||||||
|
const OWN_HINT = 'Программа набрана вручную. Поставьте переключатели в среднее положение и щёлкайте по гнёздам, чтобы ставить и снимать штеккеры, и по двум пружинам подряд, чтобы соединить их перемычкой. Готовую программу сохраните кнопкой «Сохранить программу»: она останется в этом браузере.';
|
||||||
|
function renderChapter() {
|
||||||
|
const prog = allProgs().find(p => p.id === S.prog);
|
||||||
|
const chap = prog && book.querySelector('section.page#' + CSS.escape(prog.id));
|
||||||
|
book.querySelectorAll('section.page').forEach(s => { s.hidden = s !== (chap || chOther); });
|
||||||
|
document.getElementById('book-h').textContent = chap ? 'Из руководства 1987 года' : 'О программе';
|
||||||
|
if (chap) return;
|
||||||
|
document.getElementById('ch-title').textContent = prog ? prog.t : 'Своя программа';
|
||||||
|
document.getElementById('ch-desc').textContent = prog ? prog.d : OWN_HINT;
|
||||||
|
}
|
||||||
|
|
||||||
const tt = document.getElementById('tt');
|
const tt = document.getElementById('tt');
|
||||||
function renderTable() {
|
function renderTable() {
|
||||||
@@ -792,8 +831,7 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
renderFrontWires();
|
renderFrontWires();
|
||||||
|
|
||||||
// inside view
|
// inside view
|
||||||
btnBlade.setAttribute('x2', power ? 150 : 146);
|
btnBlade.style.transform = `translateY(${power ? 7 : 0}px)`;
|
||||||
btnBlade.setAttribute('y2', power ? BUS_Y : BUS_Y - 24);
|
|
||||||
const supply = !power ? 'dead' : anyFlow ? 'flow' : 'live';
|
const supply = !power ? 'dead' : anyFlow ? 'flow' : 'live';
|
||||||
setCls(segBatPos, supply); setCls(segBus, supply);
|
setCls(segBatPos, supply); setCls(segBus, supply);
|
||||||
setCls(segBatNeg, anyFlow ? 'flow' : 'dead');
|
setCls(segBatNeg, anyFlow ? 'flow' : 'dead');
|
||||||
@@ -828,6 +866,7 @@ table.tt { border-collapse: collapse; font-family: var(--font-mono); font-size:
|
|||||||
|
|
||||||
renderTable();
|
renderTable();
|
||||||
renderExprs();
|
renderExprs();
|
||||||
|
renderChapter();
|
||||||
progBtns.forEach(([id, b]) => b.setAttribute('aria-pressed', S.prog === id ? 'true' : 'false'));
|
progBtns.forEach(([id, b]) => b.setAttribute('aria-pressed', S.prog === id ? 'true' : 'false'));
|
||||||
|
|
||||||
const n = pinCount(), chip = document.getElementById('pincount');
|
const n = pinCount(), chip = document.getElementById('pincount');
|
||||||
|
|||||||
Reference in New Issue
Block a user