Як я можу знати, чи завжди завжди можлива моя гра-головоломка?


68

Я створив якусь гру-головоломку, де мета - позбутися всіх білих плиток. Ви можете спробувати в кінці запитання.

Кожен раз, дошка генерується випадковим чином з білими плитками у випадкових місцях на 5 * 5 сітці. Ви можете натиснути будь-яку плитку на цій сітці, і вона змінить колір її та всі плитки, які торкаються її сторін. Моя дилема полягає в тому, що я не знаю, чи це створить неможливу дошку. Який найкращий спосіб перевірити такі речі?

function newgame() {
 moves = 0;
    document.getElementById("moves").innerHTML = "Moves: "+moves;

  for (var i = 0; i < 25; i++) {
   if (Math.random() >= 0.5) {
$(document.getElementsByClassName('block')[i]).toggleClass("b1 b2")
   }
}
}
newgame();
function toggle(a,b) {  
  moves += 1;
  document.getElementById("moves").innerHTML = "Moves: "+moves;
$(document.getElementsByClassName('block')[a+(b*5)]).toggleClass("b1 b2");

if (a<4) {$(document.getElementsByClassName('block')[(a+1)+(b*5)]).toggleClass("b1 b2")}
  
  
if (a>0) {$(document.getElementsByClassName('block')[(a-1)+(b*5)]).toggleClass("b1 b2")}
  
  
if (b<4) {$(document.getElementsByClassName('block')[a+((b+1)*5)]).toggleClass("b1 b2")}
  
if (b>0) {$(document.getElementsByClassName('block')[a+((b-1)*5)]).toggleClass("b1 b2")}
}
body {
  background-color: #000000;
}

.game {
  float: left;
  background-color: #000000;
  width: 300px;
  height: 300px;
  overflow: hidden;
  overflow-x: hidden;
  user-select: none;
  display: inline-block;
}

.container {
  border-color: #ffffff;
  border-width: 5px;
  border-style: solid;
  border-radius: 5px;
  width: 600px;
  height: 300px;
  text-align: center;
}

.side {
  float: left;
  background-color: #000000;
  width: 300px;
  height: 300px;
  overflow: hidden;
  overflow-x: hidden;
  user-select: none;
  display: inline-block;
}

.block {
  transition: background-color 0.2s;
  float: left;
}

.b1:hover {
  background-color: #444444;
  cursor: pointer;
}

.b2:hover {
  background-color: #bbbbbb;
  cursor: pointer;
}

.row {
  width: 300px;
  overflow: auto;
  overflow-x: hidden;
}

.b1 {
  display: inline-block;
  height: 50px;
  width: 50px;
  background-color: #000000;
  border-color: #000000;
  border-width: 5px;
  border-style: solid;
}




.b2 {
  display: inline-block;
  height: 50px;
  width: 50px;
  background-color: #ffffff;
  border-color: #000000;
  border-width: 5px;
  border-style: solid;
}



.title {
  width: 200px;
  height: 50px;
  color: #ffffff;
  font-size: 55px;
  font-weight: bold;
  font-family: Arial;
  display: table-cell;
  vertical-align: middle;
}

.button {
  cursor: pointer;
  width: 200px;
  height: 50px;
  background-color: #000000;
  border-color: #ffffff;
  border-style: solid;
  border-width: 5px;
  color: #ffffff;
  font-size: 25px;
  font-weight: bold;
  font-family: Arial;
  display: table-cell;
  vertical-align: middle;
  border-radius: 5px;
  transition: background-color 0.3s, color 0.3s;
}

.button:hover {
  background-color: #ffffff;
  color: #000000;
}

.sidetable {
  padding: 30px 0px;
  height: 200px;
}


#moves {
  width: 200px;
  height: 50px;
  color: #aaaaaa;
  font-size: 30px;
  font-weight: bold;
  font-family: Arial;
  display: table-cell;
  vertical-align: middle;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<center>
  <div class="container">
  
  
  <div class="game"><div class="row"><div onclick="toggle(0,0);" class="block b1"></div><div onclick="toggle(1,0);" class="block b1"></div><div onclick="toggle(2,0);" class="block b1"></div><div onclick="toggle(3,0);" class="block b1"></div><div onclick="toggle(4,0);" class="block b1"></div></div><div class="row"><div onclick="toggle(0,1);" class="block b1"></div><div onclick="toggle(1,1);" class="block b1"></div><div onclick="toggle(2,1);" class="block b1"></div><div onclick="toggle(3,1);" class="block b1"></div><div onclick="toggle(4,1);" class="block b1"></div></div><div class="row"><div onclick="toggle(0,2);" class="block b1"></div><div onclick="toggle(1,2);" class="block b1"></div><div onclick="toggle(2,2);" class="block b1"></div><div onclick="toggle(3,2);" class="block b1"></div><div onclick="toggle(4,2);" class="block b1"></div></div><div class="row"><div onclick="toggle(0,3);" class="block b1"></div><div onclick="toggle(1,3);" class="block b1"></div><div onclick="toggle(2,3);" class="block b1"></div><div onclick="toggle(3,3);" class="block b1"></div><div onclick="toggle(4,3);" class="block b1"></div></div><div class="row"><div onclick="toggle(0,4);" class="block b1"></div><div onclick="toggle(1,4);" class="block b1"></div><div onclick="toggle(2,4);" class="block b1"></div><div onclick="toggle(3,4);" class="block b1"></div><div onclick="toggle(4,4);" class="block b1"></div></div></div>
    
    <div class="side">
      <center class="sidetable">
        <div class="title">Tiles</div>
        <br>
        <div class="button" onclick="newgame()">New Game</div>
        <br><br>
        <div id="moves">Moves: 0</div>
      </center>
    </div>
    
  </div>
    </center>


9
Якщо вас цікавлять подібні ігри-головоломки, погляньте на портативну колекцію головоломок Саймона Татама . Крім цього типу (там називається Flip), ви можете знайти варіанти багатьох японських та інших головоломок. Все під ліцензією BSD і, мабуть, цікаве прочитання.
Дубу

10
Як щодо реверсивної інженерії це? Почніть з чистої дошки, а потім автоматизуйте, скажімо, 20 клацань на випадкових квадратах. Таким чином, ви знаєте, що в кінці має бути рішення.
AJFaraday

3
Я хочу продовжувати грати, але через ваше запитання, на мене з'їдається невпевненість у тому, чи дійсно я переможу! Весела гра :)
MrDuk

@MrDuk codepen.io/qwertyquerty/pen/WMGwVW ось готовий проект! Цей виправлений і відшліфований. Я також зробив додаток для електрон.
Qwerty

@Qwerty, коли я спробував переглянути Вашу ручку в повному обсязі сторінки, я отримав повідомлення "Власнику цієї ручки потрібно підтвердити свою електронну адресу, щоб увімкнути перегляд повної сторінки". Підтвердьте свою електронну адресу на CodePen, щоб я міг насолоджуватися вашою грою в повному вікні! :)
stephenwade

Відповіді:


161

Це тип гри, коли одна і та ж хода, що виконується двічі, повертає дошку до її попереднього стану. Отже, щоб дошка була вирішуваною, генеруйте її, граючи в зворотному напрямку. Почніть з вирішеної (порожньої) дошки, після чого почніть програмно «клацати» випадковим чином або певну кількість разів, або поки на дошці не з’явиться потрібна кількість білих квадратів. Одне рішення - просто виконати ті самі рухи у зворотному порядку. Можуть існувати й інші більш короткі рішення, але ви гарантовано матимете хоча б одне.

Ще одне, набагато складніше рішення - це визначити алгоритм вирішення, який проходить всі можливі стани гри з вашої вихідної позиції, щоб спробувати знайти рішення. Це потребуватиме набагато більше часу, щоб реалізувати та запустити, але це дозволить по-справжньому генерувати дошки. Я не буду вникати в специфіку цього рішення, тому що це просто не така гарна ідея.


22
@Qwerty: для вашої конкретної проблеми натискання одного і того ж квадрата двічі скасовується, тому ніколи не виникає причин клацати будь-який квадрат більше одного разу. Ви можете вибрати певну кількість квадратів для натискання, не повторюючи, або розглянути рішення, яке призначає XX% шанс натискання на кожен квадрат на дошці. (Ред: Гарна відповідь, +1!)
Джефф Боуман

3
Раніше я робив майже таку ж гру і закінчив використовувати цей підхід. Я включив анімацію на початку, в якій швидко відображався вирішений стан, який швидко переходив до невирішеного стану; це було гарненько
Джаред Гогуен

1
@JaredGoguen дивно, я додав це і повернувся сюди, щоб побачити ваш коментар.
Qwerty

4
@JeffBowman Дійсно, набір розв'язуваних ігор може трактуватися як 25-бітове значення, причому кожен біт відповідає квадрату, який відповідає кількості перетворених мод 2. Отже, можна генерувати випадкове число в діапазоні 0. .33,554,432, а потім обчислити значення кожного квадрата на дошці від нього у короткому порядку.
Monty Harder

7
Для чого це варто, хоча це правильна відповідь на математичне питання, як відповісти на цю проблему, зазвичай це сумнівна практика з точки зору дизайну. Таке покоління, без якогось конкретного плану, як правило, призводить до загадок, які відчувають себе дуже "однаково", без особливих цікавих міркувань або будь-яких об'єднуючих тем. Можна «процедурно генерувати» цікаві проблемні екземпляри для головоломки, але зазвичай потрібно набагато складніше подивитися, які цікаві особливості ваших головоломок.
Стівен Стадницький

92

Хоча наведені вище відповіді розумні (і, мабуть, як я це зробив би у будь-якому випадку), ця гра дуже добре відома. Він називається Lights Out , і він математично вирішений. Є рішення, якщо і лише тоді, коли дві суми різних елементів (наведені на сторінці вікіпедії) додають нульовий модуль 2 (тобто парне число). Загалом, невелика лінійна алгебра повинна давати подібні умови рішення для ігор на будь-якій дошці.


2
Сумно дізнатися, що це вже зроблено. Я думав, що я на чомусь.
Qwerty

39
@Qwerty оригінальних ідей дуже мало, і вам, звичайно, не потрібно мати жодної, щоб досягти успіху (пор. Rovio, King).
OrangeDog

14
Ця гра існує, але ви завжди можете розширити ідею! Додайте більше функцій! Додайте різні правила для того, що відбувається, коли ви кудись клацніть, як кольори, які складаються разом, залежно від того, з якого напрямку було активовано / деактивовано. Додайте різні "інструменти", які вам доведеться використовувати. Додайте не прямокутні дошки! Багато цікавих справ, які можна зробити. Тільки пам’ятайте, що рух завжди повинен змінювати себе.
Ед Марті

7
@OrangeDog: Навіть "Lights Out" не був оригінальним, це лише найменування бренду, яке стало популярним у 90-х. Стаття у Вікіпедії, наприклад, перераховує це та це
BlueRaja - Danny Pflughoeft

1
Які відповіді ви називаєте "вищезазначеними відповідями"? Це абсолютно незрозуміло, оскільки на моєму екрані над вашим лише одна відповідь. Пам'ятайте, що відповіді змінюють порядок залежно від голосів та параметрів користувача. Ви завжди повинні посилатися на конкретні відповіді, а не посилатися на щось "вище".
Девід Річербі

13

Ідіть навпаки, коли генерувати вашу головоломку

Замість випадкового вибору плиток і перетворення їх з білого на чорний, почніть з порожнього шиферу, потім виберіть плитки, але замість того, щоб перетворити цю плитку на чорну, зробіть її так, як якщо б її вибрав користувач, в результаті чого перегорнути всі інші плитки навколо нього.

Таким чином ви гарантовано матимете хоча б одне рішення: користувачеві доведеться скасувати те, що ви зробили гравцеві "AI" для створення рівня.


7

Ед і Олександр мають на це право.

Але якщо ви дійсно хочете знати , якщо кожне рішення можливо, є способи.

Існує обмежена кількість можливих головоломок

Клацання на одній площі двічі дає той самий результат, що зовсім не клацати на ній, незалежно від того, скільки кліків було зроблено між ними. Це означає, що кожне рішення можна описати, надавши кожному квадрату двійкове значення "натиснуто" або "не натиснуто". Аналогічно кожна головоломка може бути описана, надаючи кожному квадрату двійкове значення "переключений" або "не змінено". Це означає, що є 2 ^ 25 можливих головоломок і 2 ^ 25 можливих рішень. Якщо ви можете довести, що кожне рішення вирішує унікальну головоломку, то для кожної головоломки повинно бути рішення. Аналогічно, якщо ви знайдете два рішення, які вирішують одну і ту ж головоломку, не може бути вирішення кожної головоломки.

Також 2 ^ 25 - це 33 554 442. Це досить багато, але це не некерована кількість. Хороший алгоритм та гідний комп’ютер, ймовірно, могли б змусити це зробити за пару годин, особливо якщо врахувати, що половина головоломок - обертання другої половини.


4
Більше половини - "обертання" - окрім горизонтальних відбитків, у вас є вертикальні відбиття та обертання.
Завод-Муза

@ Clockwork-Muse, так, але це важче обчислити точне число, оскільки, хоча асиметричні конструкції можна обертати і перевертати за 8 перестановок, симетричні конструкції мають меншу кількість перестановок. Тому я лише згадав про білу / чорну інвертування, оскільки кожен розчин має рівно 1 обернений. (Хоча для того, щоб працювати на зворотному рівні, вам доведеться довести, що ви можете перевернути всю дошку)
Арканіст Люпус

Виявляється, як згадував Роберт Мастрагостіно у своїй відповіді, це насправді добре відома, добре вивчена проблема. Кожна головоломка має рівно 4 рішення, і більшість випадкових дощок не вирішуються. Пошук у цьому просторі може бути цікавим, але оскільки вже існує доказ ( math.ksu.edu/math551/math551a.f06/lights_out.pdf ), ви також можете зробити пару крапкових продуктів і мати однакову відповідь у кількох мікросекунди :)
GrandOpener

Математичний час: якщо ви хочете обчислити кількість різних дощок (незалежно від розчинності), враховуючи всі симетрії, то лема Бернсайда - це шлях: Є 16 симетрій (одна тривіальна, три обертання, чотири відбиття, а потім кожна з цих 8 поєднана з інверсією включення / вимкнення), і для кожної з цих симетрій деяка кількість дощок абсолютно не змінюється. Якщо взяти середнє значення цілком незмінних дощок за симетрією, це дорівнює кількості різних дощок.
Артур

1
@PeterTaylor Кодування тренажера, безумовно, займе набагато більше часу, ніж це для запуску результатів.
corsiKa

4

Узагальнена відповідь:

  1. Створіть матрицю розміру (# ходи) x (# вогнів).
  2. Помістіть 1 у комірку, якщо переміщення, відповідне цьому рядку, перемикає світло, що відповідає цьому стовпцю, 0 інакше.
  3. Виконайте усунення Гаусса-Йордана (модуль 2) на матриці.
  4. Якщо в матриці, що отримує результат, є по одному 1 у кожному стовпчику, а кожен рядок має максимум один одиницю 1, то кожна сітка вирішується.

1

Інші вже згадували способи з’ясувати, чи розв’язується ваша випадково створена головоломка. питання, яке ви також повинні задавати, - чи хочете ви насправді створювати головоломки, що генеруються випадковим чином.

Випадково генеровані головоломки мають один і той же основний недолік: Їх складність є майже непередбачуваною. Можливі головоломки, які ви можете отримати, можуть варіюватися від уже вирішених, від тривіальних (рішення очевидно) до важких (рішення не очевидно) до неможливих (головоломка взагалі не вирішується). Оскільки складність непередбачувана, це робить для гравця незадовільний досвід, особливо якщо вони виконують кілька головоломок підряд. Вони навряд чи отримають плавну криву складності, яка може змусити їх нудьгувати або засмучуватися залежно від загадок, які вони отримують.

Ще одна проблема випадкового покоління полягає в тому, що час, необхідний для ініціалізації головоломки, непередбачуваний. Взагалі кажучи, ви збираєтесь (майже) негайно отримати вирішувану головоломку, але при певній удачі ваші головоломки, що генеруються випадковим чином, можуть опинитися на смузі нерозв'язних головоломок.

Один із способів вирішити обидва з них - це заздалегідь задані вектори кожної доступної розв’язуваної головоломки, розташовані в групи складності, а потім вибирати випадкову головоломку з розв’язуваних головоломок на основі складності. Таким чином, ви будете впевнені, що кожна головоломка вирішується, що складність передбачувана і що покоління буде виконуватися в постійний час.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.