у кого то % побед есть выше 40% после 100+ попыток?))) надо создать текстовый документ, вставить код, сохранить, и изменить окончание документа на html, и запустить в браузере
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Игра: 3 ящика — найди приз | Смена выбора</title>
<style>
* {
box-sizing: border-box;
user-select: none;
}
body {
background: linear-gradient(145deg, #1a472a 0%, #0e2a1a 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Segoe UI', 'Poppins', 'Roboto', system-ui, sans-serif;
margin: 0;
padding: 20px;
}
/* главная карточка игры */
.game-container {
max-width: 1100px;
width: 100%;
background: rgba(255, 248, 225, 0.9);
backdrop-filter: blur(3px);
border-radius: 4rem 2rem 4rem 2rem;
box-shadow: 0 25px 45px rgba(0, 0, 0, 0.5), inset 0 1px 2px rgba(255,255,240,0.6);
padding: 1.8rem 1.5rem 2rem;
transition: all 0.2s;
}
h1 {
text-align: center;
font-size: 2rem;
margin: 0 0 0.25rem 0;
color: #f7b42c;
text-shadow: 3px 3px 0 #7a2e00;
letter-spacing: 2px;
word-break: keep-all;
}
.sub {
text-align: center;
font-weight: 500;
color: #2c3e2f;
background: #fef1cf;
display: inline-block;
width: auto;
margin: 0 auto 1.5rem;
padding: 0.3rem 1.6rem;
border-radius: 40px;
font-size: 1rem;
box-shadow: inset 0 0 3px #b87c2e, 0 2px 5px rgba(0,0,0,0.1);
}
/* статистика — две кнопки-карточки */
.stats-panel {
display: flex;
justify-content: center;
gap: 2rem;
margin-bottom: 2rem;
flex-wrap: wrap;
}
.stat-card {
background: #2d2b26;
border-radius: 2rem;
padding: 0.8rem 1.8rem;
min-width: 160px;
text-align: center;
box-shadow: 0 8px 0 #0f0e0c;
color: #f9e2a1;
}
.stat-card span:first-child {
font-size: 1.2rem;
font-weight: 600;
letter-spacing: 1px;
display: block;
}
.stat-number {
font-size: 2.8rem;
font-weight: 800;
line-height: 1;
color: #ffd966;
text-shadow: 0 2px 0 #5a3e1a;
font-family: monospace;
}
.accuracy {
font-size: 1rem;
background: #00000066;
border-radius: 40px;
padding: 0.2rem 0.8rem;
display: inline-block;
margin-top: 6px;
}
/* блок ящиков — сетка */
.boxes-area {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 1.8rem;
margin: 2rem 0 1.5rem;
}
/* карточка ящика */
.box {
background: #d9ae6c;
background-image: radial-gradient(circle at 35% 25%, rgba(255,215,140,0.6) 2%, transparent 2.5%);
background-size: 20px 20px;
width: 160px;
height: 170px;
border-radius: 24px;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: 0.2s ease;
box-shadow: 0 12px 0 #7a4a1e;
border: 1px solid #ffeaac;
position: relative;
}
.box:hover:not(.disabled-box) {
transform: translateY(-6px);
box-shadow: 0 16px 0 #7a4a1e;
background-color: #e7bc7c;
}
/* выбранный ящик до подтверждения */
.box.selected {
background: #f5cd94;
box-shadow: 0 0 0 4px #ffdd88, 0 12px 0 #7a4a1e;
transform: scale(0.98);
}
/* блокировка после выбора финала / открытия */
.disabled-box {
cursor: default;
opacity: 0.75;
filter: grayscale(0.1);
transform: none;
}
.box-icon {
font-size: 4rem;
filter: drop-shadow(4px 6px 0 rgba(0,0,0,0.3));
transition: 0.1s;
}
.box-label {
font-size: 1.5rem;
font-weight: bold;
background: #492d14;
color: #ffeaac;
padding: 0.2rem 1rem;
border-radius: 40px;
margin-top: 8px;
font-family: monospace;
}
/* отображение приза при открытии */
.box.revealed-prize {
background: radial-gradient(circle at 30% 20%, #ffcf4a, #c27e2e);
box-shadow: 0 6px 0 #5a3a18;
}
.prize-badge {
font-size: 3rem;
display: block;
margin-top: 5px;
}
/* кнопки управления */
.action-buttons {
display: flex;
justify-content: center;
gap: 1.5rem;
flex-wrap: wrap;
margin: 20px 0 20px;
}
button {
font-size: 1.2rem;
font-weight: bold;
border: none;
background: #f5bc70;
padding: 0.8rem 1.9rem;
border-radius: 60px;
cursor: pointer;
transition: 0.1s linear;
box-shadow: 0 5px 0 #8b5a2b;
color: #2c1a0b;
font-family: inherit;
}
button:active {
transform: translateY(2px);
box-shadow: 0 2px 0 #8b5a2b;
}
button:disabled {
opacity: 0.55;
transform: none;
cursor: not-allowed;
filter: grayscale(0.1);
}
.reset-btn {
background: #3c6e47;
color: #ffefc0;
box-shadow: 0 5px 0 #1c3a1e;
}
.game-message {
background: #1f2a17c9;
backdrop-filter: blur(8px);
border-radius: 60px;
text-align: center;
padding: 12px;
margin-top: 20px;
font-weight: bold;
font-size: 1.2rem;
color: #ffefb9;
letter-spacing: 0.5px;
}
footer {
text-align: center;
margin-top: 1rem;
font-size: 0.7rem;
color: #442f18;
font-weight: 500;
}
@media (max-width: 580px) {
.box {
width: 100px;
height: 115px;
}
.box-icon {
font-size: 2.4rem;
}
.box-label {
font-size: 1rem;
}
.stat-number {
font-size: 2rem;
}
button {
padding: 0.5rem 1.2rem;
font-size: 1rem;
}
}
</style>
</head>
<body>
<div class="game-container">
<h1>🎁 ТАИНСТВЕННЫЙ ЯЩИК 🎁</h1>
<div style="display: flex; justify-content: center;">
<div class="sub">Один ящик — сюрприз! Выбирай, меняй решение или открывай</div>
</div>
<!-- Статистика побед/поражений -->
<div class="stats-panel">
<div class="stat-card">
<span>🏆 УГАДАНО</span>
<div class="stat-number" id="winCount">0</div>
</div>
<div class="stat-card">
<span>❌ НЕ УГАДАНО</span>
<div class="stat-number" id="loseCount">0</div>
</div>
<div class="stat-card">
<span>📊 ТОЧНОСТЬ</span>
<div class="stat-number" id="accuracy">0%</div>
<div class="accuracy">всего игр</div>
</div>
</div>
<!-- 3 ящика -->
<div class="boxes-area" id="boxesContainer">
<!-- динамически через js создадим 3 ящика, но можно и разметка, но для наглядности сгенерим скриптом -->
</div>
<!-- Панель действий -->
<div class="action-buttons">
<button id="confirmBtn" disabled>✅ Подтвердить и открыть</button>
<button id="changeBtn" disabled>🔄 Изменить выбор → открыть другой</button>
<button id="resetBtn" class="reset-btn">🎲 Новая игра / Сброс</button>
</div>
<div class="game-message" id="gameMessage">
✨ Выберите один из ящиков, чтобы начать ✨
</div>
<footer>⚡ Приз случайный каждый раунд. Выберите ящик → подтвердите или смените выбор → статистика обновится.</footer>
</div>
<script>
// --- СОСТОЯНИЕ ИГРЫ ---
let currentPrizeBox = null; // индекс ящика с призом (0,1,2)
let selectedBoxIndex = null; // какой ящик выбрал игрок (после клика)
let gameActive = true; // игра активна? (пока не подтвержден финальный выбор)
let roundFinished = false; // после того как открыли результат (пока не сбросим)
let pendingDecision = false; // выбрал ящик, но еще не подтвердил/сменил (индикатор фазы выбора)
// Статистика
let winTotal = 0;
let loseTotal = 0;
// DOM элементы
const boxesContainer = document.getElementById('boxesContainer');
const confirmBtn = document.getElementById('confirmBtn');
const changeBtn = document.getElementById('changeBtn');
const resetBtn = document.getElementById('resetBtn');
const gameMessageDiv = document.getElementById('gameMessage');
const winSpan = document.getElementById('winCount');
const loseSpan = document.getElementById('loseCount');
const accuracySpan = document.getElementById('accuracy');
// Вспомогательные функции обновления UI статистики
function updateStatsUI() {
winSpan.innerText = winTotal;
loseSpan.innerText = loseTotal;
let total = winTotal + loseTotal;
if (total === 0) {
accuracySpan.innerText = '0%';
} else {
let percent = Math.round((winTotal / total) * 100);
accuracySpan.innerText = `${percent}%`;
}
}
// Генератор случайного приза (честный, непредсказуемый)
function generateRandomPrize() {
return Math.floor(Math.random() * 3); // 0,1,2 равновероятно
}
// Сброс / новая игра: генерируем новый приз, очищаем выборы, возвращаем активное состояние
function resetGame() {
// генерируем новый тайный приз
currentPrizeBox = generateRandomPrize();
selectedBoxIndex = null;
gameActive = true;
roundFinished = false;
pendingDecision = false;
// разблокируем все ящики визуально, убираем состояния
renderBoxes();
// управление кнопками: после сброса ящики активны, но подтверждение и смена выключены (пока нет выбора)
confirmBtn.disabled = true;
changeBtn.disabled = true;
// сообщение
gameMessageDiv.innerHTML = '🎲 Новый раунд! В одном из ящиков спрятан приз. Сделайте выбор 🎲';
// снимаем любые дополнительные флаги
}
// Рендер ящиков на основе текущего состояния (selectedBoxIndex, roundFinished, currentPrizeBox и т.д.)
// Если игра закончена (roundFinished == true) показываем содержимое: где был приз, а также если выбранный ящик не приз — показываем пустышку.
// По условию: после финального открытия показываем правду: ящик с призом открыт и показывает приз, другие либо пусты.
// Для эстетики: когда игра не закончена, ящики закрыты, и только выделяем выбранный.
function renderBoxes() {
if (!boxesContainer) return;
// Создаем массив ящиков
let boxesHtml = '';
for (let i = 0; i < 3; i++) {
let isSelected = (selectedBoxIndex === i);
let isRevealed = roundFinished; // если раунд завершен, показываем содержимое всех или только призового?
// Дизайн: после подтверждения выбора показываем на всех ящиках правду: приз открыт на том, где приз, а на остальных - "пусто"
// но если игрок не угадал, то на его выбранном показываем пусто и на призовом - приз
let additionalClass = '';
let contentIcon = '📦'; // закрытый вид
let labelText = `Ящик ${i+1}`;
if (!roundFinished) {
// ИГРА НЕ ЗАВЕРШЕНА: все ящики закрытые, но выбранный имеет выделение
if (isSelected) {
additionalClass = 'selected';
}
contentIcon = '🎁?';
labelText = `Ящик ${i+1}`;
} else {
// РАУНД ЗАВЕРШЕН: показываем правду, все открыто
additionalClass = 'disabled-box revealed-prize';
if (i === currentPrizeBox) {
contentIcon = '🏆✨'; // приз
labelText = `ПРИЗ! 🎉`;
} else {
contentIcon = '🍂❌';
labelText = `Пусто`;
}
// если завершено, то дополнительно блокируем клики через pointer-events? но проще через CSS и отключение обработчиков
// добавим класс disabled-box для всего
}
// при завершении игры добавим эффект отличия (уже добавили)
let additionalClasses = `box ${additionalClass}`;
if (roundFinished) additionalClasses += ' disabled-box';
// Если раунд не завершен и игру не заблокировали (ящики кликабельны, кроме случаев если roundFinished)
let clickHandler = !roundFinished ? `onclick="selectBox(${i})"` : '';
boxesHtml += `
<div class="${additionalClasses}" ${clickHandler} style="cursor: ${!roundFinished ? 'pointer' : 'default'}">
<div class="box-icon">${contentIcon}</div>
<div class="box-label">${labelText}</div>
</div>
`;
}
boxesContainer.innerHTML = boxesHtml;
// если игра активна, но уже выбран ящик (pending) — делаем кнопки активными
if (!roundFinished && selectedBoxIndex !== null && gameActive && !pendingDecision === false) {
// по факту pendingDecision — флаг что игрок выбрал ящик, но не завершил игру. confirm/change доступны
// лучше явно:
}
// синхронизация кнопок отдельно
}
// обработчик выбора ящика (только когда игра активна и раунд не завершен и нет финального решения)
function selectBox(index) {
// проверки: нельзя выбирать, если игра не активна, или раунд завершен, либо уже есть финальный выбор (roundFinished)
if (roundFinished) {
gameMessageDiv.innerHTML = '🎮 Игра уже завершена, нажмите "Новая игра" для следующего раунда.';
return;
}
if (!gameActive) return;
// если уже выбран ящик и игра не закончена, можно сменить выбор? по классике можно перевыбрать до подтверждения
// реализуем: повторный клик меняет выбранный ящик
if (selectedBoxIndex === index) {
gameMessageDiv.innerHTML = `📦 Вы снова выбрали ящик ${index+1}. Подтвердите или смените выбор.`;
} else {
gameMessageDiv.innerHTML = `🧐 Вы выбрали ящик №${index+1}. Теперь подтвердите открытие, либо нажмите "Изменить выбор" для открытия другого случайного (кроме текущего).`;
}
selectedBoxIndex = index;
pendingDecision = true; // фаза ожидания финального решения
// сделать активными кнопки "подтвердить" и "сменить выбор"
confirmBtn.disabled = false;
changeBtn.disabled = false;
// перерисовать ящики с выделением
renderBoxes();
}
// Функция которая завершает игру, принимая финальный ящик (который в итоге открывает игрок)
// finalBoxIndex — ящик, который будет открыт (либо текущий выбранный, либо измененный)
// mode: 'confirm' или 'change'
function finishGame(finalBoxIndex, mode) {
if (roundFinished) {
gameMessageDiv.innerHTML = 'Раунд уже завершен, начните новую игру.';
return;
}
if (!gameActive) return;
if (finalBoxIndex === undefined || finalBoxIndex === null) return;
// определяем победа или поражение
const isWin = (finalBoxIndex === currentPrizeBox);
// обновляем статистику
if (isWin) {
winTotal++;
gameMessageDiv.innerHTML = `🎉 ПОБЕДА! 🎉 Ящик №${finalBoxIndex+1} содержал приз! ${mode === 'confirm' ? 'Вы подтвердили свой выбор.' : 'Вы сменили выбор и угадали!'} 🎉`;
} else {
loseTotal++;
gameMessageDiv.innerHTML = `😭 ПРОИГРЫШ... В ящике №${finalBoxIndex+1} оказалось пусто. Приз был в ящике №${currentPrizeBox+1}. ${mode === 'confirm' ? 'Вы подтвердили неудачный выбор.' : 'Вы изменили выбор, но не угадали.'}`;
}
// игра завершена, раунд финиширован
roundFinished = true;
gameActive = false; // больше нельзя выбирать до ресета
pendingDecision = false;
// отключаем кнопки действий
confirmBtn.disabled = true;
changeBtn.disabled = true;
// перерисовываем ящики в открытом режиме (показать все содержимое)
renderBoxes();
updateStatsUI();
}
// Подтверждение: открыть выбранный ящик
function confirmChoice() {
if (roundFinished) {
gameMessageDiv.innerHTML = 'Игра уже окончена, сбросьте для новой.';
return;
}
if (selectedBoxIndex === null) {
gameMessageDiv.innerHTML = 'Сначала выберите ящик!';
return;
}
// финальный выбор — текущий выбранный ящик
finishGame(selectedBoxIndex, 'confirm');
}
// Сменить выбор: открыть другой ящик (не тот, который выбрал игрок). Выбираем случайный из оставшихся двух.
function changeAndOpen() {
if (roundFinished) {
gameMessageDiv.innerHTML = 'Игра окончена, начните заново.';
return;
}
if (selectedBoxIndex === null) {
gameMessageDiv.innerHTML = 'Вы не выбрали ящик! Сначала кликните на ящик.';
return;
}
// алгоритм смены: из двух оставшихся ящиков выбираем случайный (это честно, без обмана)
const remaining = [];
for (let i = 0; i < 3; i++) {
if (i !== selectedBoxIndex) remaining.push(i);
}
if (remaining.length !== 2) {
// подстраховка
const alternative = (selectedBoxIndex + 1) % 3;
const finalBox = alternative;
finishGame(finalBox, 'change');
return;
}
// выбираем случайный из двух оставшихся
const randomIndex = Math.floor(Math.random() * remaining.length);
const newBox = remaining[randomIndex];
finishGame(newBox, 'change');
}
// Инициализация игры + события кнопок
function initGame() {
// генерируем первоначальный приз
currentPrizeBox = generateRandomPrize();
selectedBoxIndex = null;
gameActive = true;
roundFinished = false;
pendingDecision = false;
confirmBtn.disabled = true;
changeBtn.disabled = true;
renderBoxes();
updateStatsUI();
gameMessageDiv.innerHTML = '✨ Выберите ящик, чтобы начать игру ✨';
}
// связываем глобальные функции для onclick из HTML (чтобы работало в рендере)
window.selectBox = selectBox;
window.confirmChoice = confirmChoice;
window.changeAndOpen = changeAndOpen;
// назначим обработчики кнопок
confirmBtn.onclick = () => confirmChoice();
changeBtn.onclick = () => changeAndOpen();
resetBtn.onclick = () => {
resetGame();
// Дополнительно гарантируем генерацию приза
currentPrizeBox = generateRandomPrize();
selectedBoxIndex = null;
gameActive = true;
roundFinished = false;
pendingDecision = false;
confirmBtn.disabled = true;
changeBtn.disabled = true;
renderBoxes();
gameMessageDiv.innerHTML = '🔁 Новая игра! Приз перемешан. Удачи! 🔁';
// статистика не сбрасывается по условию — ведется общая статистика за все попытки
// только ресет раунда, но статистика побед/поражений сохраняется
};
// начальный запуск
initGame();
// синхронная безопасная проверка при любом рендере дополнительно
// также после сброса, если надо сохранить статы без изменений
</script>
</body>
</html>
ну и попутно парадокс Монти Холла можете опробовать
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Парадокс Монти Холла | 3 ящика — ведущий открывает пустой</title>
<style>
* {
box-sizing: border-box;
user-select: none;
}
body {
background: linear-gradient(135deg, #0b2b1f 0%, #1a3f2a 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Segoe UI', 'Poppins', system-ui, sans-serif;
margin: 0;
padding: 20px;
}
.game-container {
max-width: 1200px;
width: 100%;
background: rgba(253, 245, 220, 0.95);
border-radius: 3rem 2rem 3rem 2rem;
box-shadow: 0 30px 40px rgba(0, 0, 0, 0.4), inset 0 1px 3px rgba(255, 250, 210, 0.8);
padding: 1.8rem 1.8rem 2rem;
transition: all 0.2s;
}
h1 {
text-align: center;
font-size: 1.9rem;
margin: 0;
color: #c97e2a;
text-shadow: 2px 2px 0 #412a0e;
letter-spacing: 1px;
}
.paradox-badge {
text-align: center;
background: #f3cf7a;
display: inline-block;
width: auto;
margin: 0 auto 1rem;
padding: 0.3rem 1.8rem;
border-radius: 60px;
font-weight: bold;
font-size: 0.9rem;
color: #2c4727;
box-shadow: inset 0 0 2px #aa7733, 0 2px 6px rgba(0,0,0,0.2);
}
.stats-panel {
display: flex;
justify-content: center;
gap: 2rem;
margin: 1rem 0 1.5rem;
flex-wrap: wrap;
}
.stat-card {
background: #2a2b26;
border-radius: 2rem;
padding: 0.6rem 1.6rem;
min-width: 140px;
text-align: center;
box-shadow: 0 7px 0 #131210;
color: #fae67a;
}
.stat-card span:first-child {
font-size: 1rem;
font-weight: 600;
display: block;
}
.stat-number {
font-size: 2.5rem;
font-weight: 800;
line-height: 1;
color: #ffd966;
text-shadow: 0 2px 0 #5a3e1a;
font-family: monospace;
}
.prob-hint {
font-size: 0.7rem;
background: #00000066;
border-radius: 20px;
padding: 0.2rem 0.6rem;
margin-top: 5px;
}
.boxes-area {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 1.8rem;
margin: 2rem 0 1rem;
}
.box {
background: linear-gradient(145deg, #cb9e6b, #b87a3a);
width: 170px;
height: 180px;
border-radius: 28px;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: 0.2s ease;
box-shadow: 0 12px 0 #6a3f18;
border: 1px solid #ffdd99;
position: relative;
}
.box:hover:not(.disabled-box):not(.opened-empty) {
transform: translateY(-5px);
box-shadow: 0 15px 0 #6a3f18;
background: linear-gradient(145deg, #dbb17a, #c58a48);
}
.box.selected {
background: #fad893;
box-shadow: 0 0 0 4px #ffedb0, 0 12px 0 #6a3f18;
transform: scale(0.98);
}
.box.opened-empty {
background: #8b6946;
filter: grayscale(0.2);
box-shadow: 0 5px 0 #4c3219;
cursor: default;
}
.disabled-box {
cursor: default;
opacity: 0.85;
}
.box-icon {
font-size: 4rem;
filter: drop-shadow(3px 5px 0 rgba(0,0,0,0.3));
}
.box-label {
font-size: 1.3rem;
font-weight: bold;
background: #3a2612;
color: #ffecb3;
padding: 0.2rem 1rem;
border-radius: 40px;
margin-top: 8px;
}
.revealed-prize {
background: radial-gradient(circle at 30% 25%, #ffdd88, #da942a);
box-shadow: 0 5px 0 #784d1c;
}
.action-buttons {
display: flex;
justify-content: center;
gap: 1.4rem;
flex-wrap: wrap;
margin: 20px 0 15px;
}
button {
font-size: 1.15rem;
font-weight: bold;
border: none;
background: #efb76b;
padding: 0.7rem 1.7rem;
border-radius: 60px;
cursor: pointer;
transition: 0.08s linear;
box-shadow: 0 5px 0 #8b5528;
color: #2c1a0b;
font-family: inherit;
}
button:active {
transform: translateY(2px);
box-shadow: 0 2px 0 #8b5528;
}
button:disabled {
opacity: 0.5;
transform: none;
cursor: not-allowed;
}
.reset-btn {
background: #3f6b4a;
color: #ffefc0;
box-shadow: 0 5px 0 #21482a;
}
.game-message {
background: #1a2f1ad9;
backdrop-filter: blur(8px);
border-radius: 56px;
text-align: center;
padding: 12px;
margin-top: 15px;
font-weight: bold;
font-size: 1.1rem;
color: #fff0c0;
}
.theory-note {
text-align: center;
font-size: 0.7rem;
margin-top: 18px;
background: #e9dbc6;
width: fit-content;
margin-left: auto;
margin-right: auto;
padding: 5px 15px;
border-radius: 50px;
color: #4c3a24;
font-weight: 500;
}
@media (max-width: 620px) {
.box {
width: 100px;
height: 115px;
}
.box-icon {
font-size: 2.4rem;
}
.box-label {
font-size: 0.9rem;
}
.stat-number {
font-size: 1.8rem;
}
button {
padding: 0.5rem 1rem;
font-size: 0.9rem;
}
}
</style>
</head>
<body>
<div class="game-container">
<h1>🎩 ПАРАДОКС МОНТИ ХОЛЛА 🎩</h1>
<div style="display: flex; justify-content: center;">
<div class="paradox-badge">📐 Ведущий ЗНАЕТ где приз и открывает ПУСТОЙ ящик</div>
</div>
<div class="stats-panel">
<div class="stat-card">
<span>🏆 ПОБЕД (угадал)</span>
<div class="stat-number" id="winCount">0</div>
<div class="prob-hint">⭐ итог</div>
</div>
<div class="stat-card">
<span>❌ ПОРАЖЕНИЙ</span>
<div class="stat-number" id="loseCount">0</div>
</div>
<div class="stat-card">
<span>📊 УСПЕХ</span>
<div class="stat-number" id="accuracy">0%</div>
<div class="prob-hint">всего партий</div>
</div>
</div>
<!-- три ящика динамически -->
<div class="boxes-area" id="boxesContainer"></div>
<div class="action-buttons">
<button id="stayBtn" disabled>🔒 ОСТАТЬСЯ ПРИ СВОЁМ</button>
<button id="switchBtn" disabled>🔄 СМЕНИТЬ ВЫБОР (рекомендуется!)</button>
<button id="resetBtn" class="reset-btn">🎲 НОВАЯ ИГРА</button>
</div>
<div class="game-message" id="gameMessage">
🧠 Выберите ящик. Ведущий откроет пустой, после чего вы сможете остаться или сменить выбор.
</div>
<div class="theory-note">
📐 Математика: Изначальный шанс 33% — после открытия пустого ящика смена выбора даёт 66.7% победы!
</div>
</div>
<script>
// ---------- СОСТОЯНИЕ ИГРЫ (МОНТИ ХОЛЛ) ----------
let prizeBox = null; // индекс ящика с призом (0,1,2)
let playerFirstChoice = null; // первый выбор игрока
let openedEmptyBox = null; // какой ящик открыл ведущий (пустой, не приз, не выбор игрока)
let gamePhase = "selection"; // 'selection' -> игрок выбирает первый ящик
// 'offer' -> ведущий открыл пустой, предлагает выбор: остаться или сменить
// 'finished' -> раунд завершён, результат показан
let finalDecisionMade = false; // финальное решение принято (остался/сменил)
// Статистика побед / поражений
let totalWins = 0;
let totalLosses = 0;
// DOM элементы
const boxesContainer = document.getElementById('boxesContainer');
const stayBtn = document.getElementById('stayBtn');
const switchBtn = document.getElementById('switchBtn');
const resetBtn = document.getElementById('resetBtn');
const gameMessageDiv = document.getElementById('gameMessage');
const winSpan = document.getElementById('winCount');
const loseSpan = document.getElementById('loseCount');
const accuracySpan = document.getElementById('accuracy');
// ----- Вспомогательные функции -----
function updateStatsUI() {
winSpan.innerText = totalWins;
loseSpan.innerText = totalLosses;
const totalGames = totalWins + totalLosses;
if (totalGames === 0) {
accuracySpan.innerText = '0%';
} else {
const percent = Math.round((totalWins / totalGames) * 100);
accuracySpan.innerText = `${percent}%`;
}
}
// Генерация случайного приза (абсолютно случайно)
function randomPrizeBox() {
return Math.floor(Math.random() * 3);
}
// Логика ведущего: открывает пустой ящик из оставшихся (не приз и не первый выбор игрока)
// возвращает индекс открытого ящика
function getHostOpenedBox(prizeIdx, firstChoiceIdx) {
const candidates = [];
for (let i = 0; i < 3; i++) {
if (i !== prizeIdx && i !== firstChoiceIdx) {
candidates.push(i);
}
}
// всегда есть хотя бы один, в классическом парадоксе — 1 или 2 варианта
// если candidates.length === 1 (игрок не угадал приз первым ходом), то открывается единственный.
// если candidates.length === 2 (игрок угадал приз первым ходом), то ведущий случайно выбирает любой из двух пустых.
if (candidates.length === 0) {
// на всякий случай (не может быть)
return (prizeIdx === 0 ? 1 : 0);
}
const randomIndex = Math.floor(Math.random() * candidates.length);
return candidates[randomIndex];
}
// Начать новый раунд (сброс всех состояний, генерация приза)
function newRound() {
prizeBox = randomPrizeBox();
playerFirstChoice = null;
openedEmptyBox = null;
gamePhase = "selection";
finalDecisionMade = false;
// кнопки управления в начальной фазе
stayBtn.disabled = true;
switchBtn.disabled = true;
// отрисовать интерфейс ящиков (закрытые, без выделений)
renderBoxes();
gameMessageDiv.innerHTML = "🎁 Выберите первый ящик. Ведущий затем откроет пустой и предложит выбор.";
}
// Рендер ящиков в зависимости от фазы игры:
// - selection: все закрыты, возможен клик (выбор первого ящика)
// - offer: ведущий уже открыл пустой ящик (openedEmptyBox показывается как открытый пустой)
// выбранный игроком первый ящик выделяется, но уже заблокирован для кликов
// два неоткрытых ящика (первый выбор игрока + второй неоткрытый) выглядят целыми.
// - finished: показываем результат: приз открыт на prizeBox, остальные открыты (пусто)
function renderBoxes() {
if (!boxesContainer) return;
let html = '';
for (let i = 0; i < 3; i++) {
let additionalClasses = "box";
let icon = "🎁";
let label = `Ящик ${i+1}`;
let clickable = false;
let clickHandler = "";
// --- ФАЗА ВЫБОРА ПЕРВОГО ЯЩИКА (selection) ---
if (gamePhase === "selection") {
clickable = true;
if (playerFirstChoice === i) {
additionalClasses += " selected";
}
icon = "❓";
label = `Ящик ${i+1}`;
}
// --- ФАЗА ПРЕДЛОЖЕНИЯ (offer) ведущий уже открыл пустой ящик ---
else if (gamePhase === "offer") {
// ящик, который открыл ведущий (пустой) показываем как открытый "пусто"
if (openedEmptyBox === i) {
additionalClasses += " opened-empty disabled-box";
icon = "🍂";
label = "Пусто";
clickable = false;
}
// первый выбор игрока (ещё закрыт, но выделен)
else if (playerFirstChoice === i) {
additionalClasses += " selected";
icon = "❓";
label = `Ваш выбор → ${i+1}`;
clickable = false; // в фазе offer клики на ящики не меняют решение
}
// третий ящик (тот, который не выбрал игрок и не открыт ведущим) — альтернатива для смены
else {
icon = "❓";
label = `Ящик ${i+1}`;
clickable = false;
}
}
// --- ФАЗА ЗАВЕРШЕНА (finished) ---
else if (gamePhase === "finished") {
additionalClasses += " disabled-box";
if (i === prizeBox) {
additionalClasses += " revealed-prize";
icon = "🏆✨";
label = "ПРИЗ!";
} else {
additionalClasses += " opened-empty";
icon = "🍂";
label = "Пусто";
}
clickable = false;
}
// Добавляем обработчик клика, если кликабельно
if (clickable && gamePhase === "selection") {
clickHandler = `onclick="selectFirstBox(${i})"`;
} else {
clickHandler = "";
}
html += `<div class="${additionalClasses}" style="cursor: ${clickable ? 'pointer' : 'default'}" ${clickHandler}>
<div class="box-icon">${icon}</div>
<div class="box-label">${label}</div>
</div>`;
}
boxesContainer.innerHTML = html;
}
// ------ 1. Игрок выбирает первый ящик ------
window.selectFirstBox = function(boxIndex) {
if (gamePhase !== "selection") {
gameMessageDiv.innerHTML = "Сейчас нельзя выбрать, игра уже на стадии предложения или завершена. Нажмите 'Новая игра'.";
return;
}
if (playerFirstChoice !== null) {
// на всякий случай, но по логике интерфейса вы можете перевыбрать до того как ведущий сработает?
// по классике: игрок делает единственный первый выбор, но добавим свободу перевыбора до перехода
playerFirstChoice = boxIndex;
renderBoxes();
gameMessageDiv.innerHTML = `Вы выбрали ящик №${boxIndex+1}. Теперь нажмите «Ведущий открывает пустой ящик» (кнопка ниже), чтобы продолжить.`;
return;
}
playerFirstChoice = boxIndex;
renderBoxes();
// После выбора первого ящика предлагаем следующий шаг: ведущий открывает пустой.
// В интерфейсе сделаем кнопку "Открыть пустой ящик" — но по правилам парадокса ведущий открывает сразу.
// Чтобы не усложнять, сделаем автоматический переход после выбора? Нет: удобнее кнопка "Раунд: Ведущий открывает пустой"
// Добавим скрытую логику: после выбора игроком, появляется кнопка "Ведущий открывает пустой"?
// Но по UI правильнее добавить новую кнопку? Либо автоматически вызвать открытие. Сделаем автоматически через 0.1с для плавности, но управление через кнопку "Далее".
// Для чистоты парадокса добавим кнопку "🎭 Ведущий, открой пустой ящик", которая появляется после выбора. Но чтобы не засорять, превратим одну из кнопок.
// Лучше сделаем третью кнопку "Ведущий открывает пустой" временную? Упростим: после выбора первого ящика автоматически вызываем открытие.
// Так игроку не нужно лишних нажатий.
gameMessageDiv.innerHTML = `✅ Вы выбрали ящик №${boxIndex+1}. Ведущий (который знает где приз) открывает заведомо пустой ящик...`;
// Автоматический вызов открытия ведущим (через микро-задержку для анимации)
setTimeout(() => {
if (gamePhase === "selection" && playerFirstChoice !== null) {
hostOpensEmpty();
}
}, 80);
};
// 2. Ведущий открывает пустой ящик (классический шаг)
function hostOpensEmpty() {
if (gamePhase !== "selection" || playerFirstChoice === null) {
// неверное состояние
if (playerFirstChoice === null) gameMessageDiv.innerHTML = "Сначала выберите ящик!";
return;
}
// Вычисляем, какой ящик должен открыть ведущий
openedEmptyBox = getHostOpenedBox(prizeBox, playerFirstChoice);
// переключаем фазу игры на "предложение"
gamePhase = "offer";
// делаем кнопки "Остаться" и "Сменить" активными
stayBtn.disabled = false;
switchBtn.disabled = false;
// отрисовать ящики: открытый пустой показывается, остальные два закрыты (выбор игрока и альтернатива)
renderBoxes();
gameMessageDiv.innerHTML = `🎤 Ведущий открыл ящик №${openedEmptyBox+1} — там пусто! Теперь решайте: остаться при своём ящике №${playerFirstChoice+1} или сменить выбор на другой закрытый ящик? (шанс победы при смене = 66.7%)`;
}
// 3. Игрок решает: остаться при своём первом выборе
function stayWithChoice() {
if (gamePhase !== "offer") {
gameMessageDiv.innerHTML = "Сейчас нельзя принять решение — игра не в фазе предложения. Начните новый раунд.";
return;
}
const finalBox = playerFirstChoice;
const isWin = (finalBox === prizeBox);
finishRound(isWin, "stay");
}
// 4. Игрок решает сменить выбор (на другой закрытый ящик, который не открывал ведущий и не его первый выбор)
function switchChoice() {
if (gamePhase !== "offer") {
gameMessageDiv.innerHTML = "Невозможно сменить выбор сейчас. Начните новый раунд.";
return;
}
// Находим оставшийся ящик: ни первый выбор игрока, ни открытый ведущим
let switchedBox = null;
for (let i = 0; i < 3; i++) {
if (i !== playerFirstChoice && i !== openedEmptyBox) {
switchedBox = i;
break;
}
}
if (switchedBox === null) {
// fallback (ошибка)
switchedBox = (playerFirstChoice === 0 ? 1 : 0);
}
const isWin = (switchedBox === prizeBox);
finishRound(isWin, "switch");
}
// 5. Завершение раунда: обновить статистику, показать результат, заблокировать кнопки выбора
function finishRound(isWin, decisionType) {
if (gamePhase === "finished") return;
if (isWin) {
totalWins++;
gameMessageDiv.innerHTML = `🎉 ПОБЕДА! 🎉 Вы ${decisionType === "stay" ? "остались при своём выборе" : "сменили выбор"} и выиграли приз! (${decisionType === "switch" ? "Правильная стратегия: смена даёт 66.7%" : "Везение!"})`;
} else {
totalLosses++;
gameMessageDiv.innerHTML = `💔 ПОРАЖЕНИЕ. Приз был в ящике №${prizeBox+1}. ${decisionType === "stay" ? "Вы остались при своём первом выборе" : "Вы сменили выбор, но не угадали"}. Попробуйте снова.`;
}
gamePhase = "finished";
finalDecisionMade = true;
// отключаем кнопки выбора в завершённой игре
stayBtn.disabled = true;
switchBtn.disabled = true;
// отобразить все ящики открытыми
renderBoxes();
updateStatsUI();
}
// Полный сброс игры (новая игра)
function resetFullGame() {
// Не сбрасываем статистику! По условию задачи статистика ведется за всё время
// Очищаем состояние раунда
prizeBox = randomPrizeBox();
playerFirstChoice = null;
openedEmptyBox = null;
gamePhase = "selection";
finalDecisionMade = false;
stayBtn.disabled = true;
switchBtn.disabled = true;
renderBoxes();
gameMessageDiv.innerHTML = "🔄 Новая игра! Выберите любой ящик первым шагом. Ведущий откроет пустой, и вы сможете изменить выбор или остаться.";
// статистика UI уже актуальна
updateStatsUI();
}
// Назначение событий и инициализация
function init() {
// глобальные функции для onclick
window.selectFirstBox = selectFirstBox;
window.hostOpensEmpty = hostOpensEmpty;
window.stayWithChoice = stayWithChoice;
window.switchChoice = switchChoice;
stayBtn.onclick = () => stayWithChoice();
switchBtn.onclick = () => switchChoice();
resetBtn.onclick = () => resetFullGame();
// старт первого раунда
prizeBox = randomPrizeBox();
playerFirstChoice = null;
gamePhase = "selection";
finalDecisionMade = false;
stayBtn.disabled = true;
switchBtn.disabled = true;
renderBoxes();
gameMessageDiv.innerHTML = "✨ Выберите ящик — ведущий затем откроет пустой и предложит выбор. (Смена выбора даёт 66% успеха!) ✨";
updateStatsUI();
}
init();
</script>
</body>
</html>
если вы считаете что я занимаюсь ерундой, так поделитесь каким то своим проектом! - посмотреть, почитать код, а то фантазия что сделать у меня иссякла)))

