8.8. Демонстрация - Симуляция игры
Шаг 1
Идея решения этой задачи довольно проста: представим наших игроков как очередь. Чтобы «исключить» очередного игрока, сначала отсчитаем от начала очереди нужное количество «невылетающих» игроков, по мере отсчёта перекладывая их в конец очереди. А затем просто исключим первого игрока в очереди за ними.
import {eliminate} from "./logger";
const players = ['GottaSaiyan', 'Mountaintrid', 'Rectionom', 'JoshChase', 'DreamLess', 'BlondiePlanet', 'Breakingbing', 'Goldenelox'];
function play(players) {
return [];
}
eliminate(players, play(players));
Шаг 2
Чтобы убедиться в правильности нашей логики исключения, сначала прогоним наш алгоритм на фиксированном шаге. Например, зафиксируем его в двойке. Как мы видим, из-за того, что в нашей функции мы модифицируем массив игроков, оставляя там только победителя, список до демонстрации не долетает. Будьте осторожнее с мутированием данных внутри своей функции. Лучше хотя бы сохранять их локальную копию, что мы и сделаем.
import {eliminate} from "./logger";
const players = ['GottaSaiyan', 'Mountaintrid', 'Rectionom', 'JoshChase', 'DreamLess', 'BlondiePlanet', 'Breakingbing', 'Goldenelox'];
function play(players) {
const step = 2
const eliminated = [];
// пока у нас нет победителя
while (players.length !== 1) {
let remove = step;
// пока не дошли до вылетающего человека
while (remove) {
// берём человека, первого в очереди на удаление
const first = players.shift();
// и кладём его в конец ожидающих удаления...
players.push(first);
remove--;
}
// как только дошли до удаляемого — удаляем его из очереди и кладём в наш массив результатов игры
const eliminatedLogin = players.shift();
eliminated.push({
login: eliminatedLogin,
step,
})
}
return eliminated;
}
eliminate(players, play(players));
Шаг 3
Теперь всё работает как надо! Допишем небольшую функцию, которая будет возвращать случайный шаг для передвижения по очереди.
import {eliminate} from "./logger";
const players = ['GottaSaiyan', 'Mountaintrid', 'Rectionom', 'JoshChase', 'DreamLess', 'BlondiePlanet', 'Breakingbing', 'Goldenelox'];
function play(players) {
players = [...players];
const step = 2
const eliminated = [];
// пока у нас нет победителя
while (players.length !== 1) {
let remove = step;
// пока не дошли до вылетающего человека
while (remove) {
// берём человека, первого в очереди на удаление
const first = players.shift();
// и кладём его в конец ожидающих удаления...
players.push(first);
remove--;
}
// как только дошли до удаляемого — удаляем его из очереди и кладём в наш массив результатов игры
const eliminatedLogin = players.shift();
eliminated.push({
login: eliminatedLogin,
step,
})
}
return eliminated;
}
eliminate(players, play(players));
Шаг 4
Несмотря на не совсем простую логику, с помощью очереди мы смогли описать поведение нашей игры. Теперь можете делать ставки на игроков и переживать за них, кликая по кнопке над демонстрацией.
import {eliminate} from "./logger";
const MAX_STEP = 3;
const players = ['GottaSaiyan', 'Mountaintrid', 'Rectionom', 'JoshChase', 'DreamLess', 'BlondiePlanet', 'Breakingbing', 'Goldenelox'];
function randomStep() {
return Math.floor(Math.random() * MAX_STEP + 1);
}
function play(players) {
players = [...players];
const eliminated = [];
// пока у нас нет победителя
while (players.length !== 1) {
const step = randomStep();
let remove = step;
// пока не дошли до вылетающего человека
while (remove) {
// берём человека, первого в очереди на удаление
const first = players.shift();
// и кладём его в конец ожидающих удаления...
players.push(first);
remove--;
}
// как только дошли до удаляемого — удаляем его из очереди и кладём в наш массив результатов игры
const eliminatedLogin = players.shift();
eliminated.push({
login: eliminatedLogin,
step,
})
}
return eliminated;
}
eliminate(players, play(players));
const playButton = document.getElementById('play-button');
playButton.addEventListener('click', () => eliminate(players, play(players)));
File logger.js
const playersList = document.getElementById('players');
export function eliminate(players, eliminated) {
playersList.innerHTML = '';
const playersElements = players.map(login => {
const element = document.createElement('li');
element.innerText = login;
return element;
});
playersElements.forEach(element => {
playersList.appendChild(element);
});
eliminated.forEach(({login}, index) => {
const eliminationTiming = (index + 1) * 1000;
const eliminatedPlayerIndex = players.findIndex(playerLogin => playerLogin === login);
const eliminatedElement = playersElements[eliminatedPlayerIndex];
setTimeout(() => {
eliminatedElement.style.textDecoration = 'line-through';
eliminatedElement.style.color = 'gray';
}, eliminationTiming)
})
}
}