13 KiB
id, title, challengeType, forumTopicId, dashedName
id | title | challengeType | forumTopicId | dashedName |
---|---|---|---|---|
5900f3c11000cf542c50fed3 | Завдання 84: Шанси Монополії | 5 | 302198 | problem-84-monopoly-odds |
--description--
У грі, Монополія, стандартна плата встановлюється наступним чином:
ВПЕРЕД | А1 | CC1 | А2 | Т1 | Р1 | В1 | CH1 | В2 | B3 | ТЮРМА |
H2 | С1 | |||||||||
Т2 | U1 | |||||||||
H1 | C2 | |||||||||
CH3 | C3 | |||||||||
R4 | R2 | |||||||||
G3 | D1 | |||||||||
CC3 | CC2 | |||||||||
G2 | D2 | |||||||||
G1 | D3 | |||||||||
G2J | F3 | U2 | F2 | F1 | R3 | E3 | E2 | CH2 | E1 | FP |
Гравець стартує зі стартової площадки і додає очки з 6-бічних кубиків для визначення кількості квадратів, за якими просувається за годинниковою стрілкою. Без будь-яких подальших правил ми очікуємо відвідати кожен квадрат з рівною ймовірністю: 2,5%. Однак, кроки на G2J (прямуйте до тюрми), CC (скриня спільноти), і CH (шанс) змінює цей розподіл.
На додачу до G2J, є ще одна карта з CC і CH, що наказує гравцю іти безпосередньо до в'язниці, якщо гравець викидає три парні поспіль, то вони не підвищує результат свого третього кидка. Але вони потрапляють безпосередньо до тюрми.
На початку гри CC та CH картки змішані. Коли гравець опиняється на CC або CH він бере карту зверху відповідної купи і, після виконання інструкцій, повертає картку донизу купи. У кожній стопці по шістнадцять карт, але для цілей цієї задачі ми матимемо справу лише з картками, які вказують рух; будь-яка інструкція, яка не стосується руху буде проігнорована, і гравець залишиться на полі CC/CH.
- Скриня спільноти (2/16 карт):
- Перейти на початок
- Перейти до ТЮРМИ
- Шанс (10/16 карт):
- Перейти на початок
- Перейти до ТЮРМИ
- Перейти до C1
- Перейти до E3
- Перейти до H2
- Перейти до C1
- Перейти до наступної R (залізнична компанія)
- Перейти до наступної R
- Перейти до наступного U (комунальна компанія)
- Назад на 3 ходи.
Корінь цієї проблеми стосується ймовірності відвідання певного квадрату. Тобто ймовірність закінчити на цьому квадраті після виконання ходу. З цієї причини слід розуміти, що, за винятком G2J, при якому ймовірність фінішу на цьому кроці дорівнює нулю, квадрати CH матимуть найнижчі ймовірності, як 5/8 запит руху на інший квадрат, а ми зацікавленні саме на фінальному квадраті, де гравець закінчує після кожного кидку. Ми не будемо розрізняти "Просто відвідування" та відправлення до ТЮРЬМИ, також ми ігноруватимемо правило щодо вимагання подвійної плати щоб "вийти з в'язниці", припустивши, що гравці платять за те, щоб вийти на свій наступний хід.
Починаючи з кроку GO та послідовно нумеруючи квадрати з 00 до 39, ми можемо об'єднати ці двоцифрові числа для отримання рядків, що відповідають наборам квадратів.
Статистично можна показати, що три найпопулярніші квадрати, по порядку, це ТЮРМА (6.24%) = Квадрат 10, Е3 (3.18%) = Квадрат 24, і GO (3.09%) = Квадрат 00. Отож, ці три найпопулярніші квадрати можна перелічити шестизначним модальним рядком 102400
.
Якщо замість 6-гранного кубика використовується двоn
-гранний кубик, знайдіть шестизначний модальний рядок.
--hints--
monopolyOdds(8)
має вивести рядок.
assert(typeof monopolyOdds(8) === 'string');
monopolyOdds(8)
має вивести рядок 102400
.
assert.strictEqual(monopolyOdds(8), '102400');
monopolyOdds(10)
має вивести рядок 100024
.
assert.strictEqual(monopolyOdds(10), '100024');
monopolyOdds(20)
має вивести рядок 100005
.
assert.strictEqual(monopolyOdds(20), '100005');
monopolyOdds(4)
має вивести рядок 101524
.
assert.strictEqual(monopolyOdds(4), '101524');
--seed--
--seed-contents--
function monopolyOdds(n) {
return true;
}
monopolyOdds(8);
--solutions--
function monopolyOdds(n) {
function chanceCard(position, chanceCardPosition) {
chanceCardPosition = (chanceCardPosition + 1) % 16;
if (chanceCardPosition < 6) {
position = chanceCardsMoves[chanceCardPosition];
} else if (chanceCardPosition === 6 || chanceCardPosition === 7) {
position = nextMovesFromR[position];
} else if (chanceCardPosition === 8) {
position = nextMovesFromU[position];
} else if (chanceCardPosition === 9) {
position -= 3;
}
return [position, chanceCardPosition];
}
function chestCard(position, chestPosition) {
chestPosition = (chestPosition + 1) % 16;
if (chestPosition < 2) {
position = chestCardsMoves[chestPosition];
}
return [position, chestPosition];
}
function isChest(position) {
return position === 2 || position === 17 || position === 33;
}
function isChance(position) {
return position === 7 || position === 22 || position === 36;
}
function isJail(position) {
return position === 30;
}
function roll(dice) {
return Math.floor(Math.random() * dice) + 1;
}
function getTopThree(board) {
return sortByVisits(board)
.slice(0, 3)
.map(elem => elem[0].toString().padStart(2, '0'))
.join('');
}
function sortByVisits(board) {
return board
.map((element, index) => [index, element])
.sort((a, b) => a[1] - b[1])
.reverse();
}
const rounds = 2000000;
const chestCardsMoves = [0, 10];
const chanceCardsMoves = [0, 10, 11, 24, 39, 5];
const nextMovesFromR = { 7: 15, 22: 25, 36: 5 };
const nextMovesFromU = { 7: 12, 36: 12, 22: 28 };
const board = new Array(40).fill(0);
let doubleCount = 0;
let curPosition = 0;
let curChestCard = 0;
let curChanceCard = 0;
for (let i = 0; i < rounds; i++) {
const dice1 = roll(n);
const dice2 = roll(n);
if (dice1 === dice2) {
doubleCount++;
} else {
doubleCount = 0;
}
if (doubleCount > 2) {
curPosition = 10;
doubleCount = 0;
} else {
curPosition = (curPosition + dice1 + dice2) % 40;
if (isChance(curPosition)) {
[curPosition, curChanceCard] = chanceCard(curPosition, curChanceCard);
} else if (isChest(curPosition)) {
[curPosition, curChestCard] = chestCard(curPosition, curChestCard);
} else if (isJail(curPosition)) {
curPosition = 10;
}
}
board[curPosition]++;
}
return getTopThree(board);
}