パズルゲームが常に可能かどうかを知るにはどうすればよいですか?


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
この種のパズルゲームに興味がある場合は、サイモンタサムのポータブルパズルコレクションをご覧ください。このタイプ(フリップと呼ばれます)以外にも、多くの日本語やその他のパズルのバリエーションがあります。すべてがBSDライセンスの下にあり、おそらく興味深い読み物です。
ドゥブ

10
リバースエンジニアリングはどうですか?空白のボードから始めて、自動化します。ランダムな正方形を20回クリックします。そうすれば、最後に解決策がなければならないことがわかります。
AJFaraday

3
私はプレーし続けたいのですが、あなたの質問のために、私が実際に勝つかどうかの不確実性は私を食べています!楽しいゲーム:)
MrDuk

@MrDuk codepen.io/qwertyquerty/pen/WMGwVWこれが完成したプロジェクトです!これは修正され、洗練されています。また、電子アプリも作成しました。
Qwerty

@Qwertyペンを全ページ表示で表示しようとすると、「このペンの所有者は全ページ表示を有効にするにはメールアドレスを確認する必要があります」というメッセージが表示されました。CodePenでメールアドレスを確認して、ゲームを全画面で楽しめるようにしてください!:)
スティーブンワデ

回答:


161

これは、同じ動きを2回実行すると、ボードが以前の状態に反転するタイプのゲームです。そのため、ボードが解けるようにするには、逆にプレイしてボードを生成します。解決済みの(空白の)ボードから開始し、プログラムで特定の回数、またはボードに必要な数の白い正方形が現れるまで、ランダムに「クリック」を開始します。1つの解決策は、同じ動きを逆の順序で実行することです。他の短いソリューションが存在する場合もありますが、少なくとも1つは保証されています。

もう1つのはるかに複雑なソリューションは、解決策を見つけるために、開始位置から可能なすべてのゲーム状態を通過する解決アルゴリズムを定義することです。これは実装と実行に非常に時間がかかりますが、ボードを真にランダムに生成できます。このソリューションの詳細については触れません。なぜなら、それはあまり良いアイデアではないからです。


22
@Qwerty:特定の問題では、同じ正方形を2回クリックするとそれ自体がキャンセルされるため、正方形を複数回クリックする理由はありません。特定の数の正方形を選択してクリックせずにクリックするか、ボード上の各正方形にXX%のクリック率を割り当てるソリューションを検討します。(エド:いい答え、+ 1!)
ジェフボウマン

3
私は以前とほぼ同じゲームを作成し、このアプローチを使用することになりました。最初に、解決済みの状態から未解決の状態にすばやく移行するアニメーションを含めました。きれいでした。
ジャレッドゴーゲン

1
@JaredGoguen奇妙なことに、私はそれを追加し、あなたのコメントを見るためにここに戻ってきました。
Qwerty

4
@JeffBowman確かに、解けるゲームのセットは25ビット値として扱うことができ、各ビットはmod 2を反転した回数である正方形に対応します。したがって、0の範囲で乱数を生成できます。 .33,554,432そして、ボード上の各正方形の値をそこから短い順序で計算します。
モンティハーダー

7
価値があるのは、これがこの問題にどのように答えるかという数学的な質問に対する正しい答えですが、これは通常、設計の観点からは疑わしい習慣です。この種の生成は、特別な計画がなくても、一般に、特定の関心点や統一されたテーマがなく、非常に「同じ」と感じるパズルにつながります。パズルゲームの興味深い問題インスタンスを「手順的に生成」することは可能ですが、通常は、パズルの興味深い機能をより厳密に調べる必要があります。
スティーブンスタドニッキー

92

上記の答えは賢明ですが(そしておそらく私がとにかくそれを行う方法)、この特定のゲームは非常によく知られています。Lights Outと呼ばれ、数学的に解決されています。さまざまな要素の2つの合計(ウィキペディアページで指定)がゼロmod 2(つまり偶数)に追加される場合にのみ、解決策があります。一般に、小さな線形代数は、どのボード上のゲームでも同様の解法条件を与えるはずです。


2
すでに作られていることを知るのはちょっと悲しい。私は何かに取り組んでいると思った。
Qwerty

39
@Qwertyにはオリジナルのアイデアはほとんどなく、成功するためにアイデアを持っている必要はありません(キング、ロビオを参照)。
ハーミングモニカを停止

14
この特定のゲームは存在しますが、いつでもアイデアを拡張できます!さらに機能を追加してください!どこをクリックしたときに何が起こるかについて、さまざまなルールを追加します。たとえば、アクティブ化/非アクティブ化された方向に基づいて色が追加されます。使用する必要があるさまざまな「ツール」を追加します。非長方形のボードを追加してください!楽しいことがたくさんあります。動きは常にそれ自体を逆にしなければならないことを覚えておいてください。
エドマーティ

7
@OrangeDog:「Lights Out」でさえオリジナルではなく、90年代に人気を博したブランド名です。Wikipediaの記事は、例えば、一覧表示されます。この、この
ダニーPflughoeft - BlueRaja

1
どの回答を「上記の回答」と呼んでいますか?私の画面では、あなたの答えは1つしかありません。回答は投票とユーザーオプションに応じて順序が変わることに注意してください。「上」に言及するのではなく、常に特定の回答にリンクする必要があります。
デビッドリチャービー

13

パズルを生成するときは、逆の方向に進んでください。

タイルをランダムに選択して白から黒に変える代わりに、白紙から始めて、タイルを選択しますが、そのタイルを黒に変える代わりに、ユーザーが選択したようにして、他のすべてのタイルを反転させますその周りに。

この方法では、少なくとも 1つのソリューションが保証されます。ユーザーは、「AI」プレイヤーがレベルを作成するために行ったことを取り消す必要があります。


7

エドとアレクサンドルはその権利を持っています。

あなたがいる場合でもないすべてのソリューションが可能であるかどうかを知りたい、方法があります。

可能なパズルの数には限りがあります

同じ四角を2回クリックすると、その間で何回クリックされても、まったくクリックしないのと同じ結果になります。つまり、各正方形に「クリック」または「クリックなし」のバイナリ値を与えることで、すべてのソリューションを説明できることを意味します。同様に、各パズルには、各正方形に「トグル」または「トグルなし」のバイナリ値を与えることで説明できます。つまり、考えられるパズルは2 ^ 25個あり、解決策は2 ^ 25個あります。各ソリューションがユニークなパズルを解決することを証明できる場合、すべてのパズルに対するソリューションが必要です。同様に、同じパズルを解決する2つのソリューションを見つけた場合、すべてのパズルにソリューションがあるわけではありません。

また、2 ^ 25は33,554,432です。それはかなりたくさんありますが、それは管理不能な数ではありません。優れたアルゴリズムと適切なコンピューターは、おそらくパズルの半分が他の半分の逆であると考えると、おそらく数時間でそれをブルートフォースにすることができます。


4
半分以上は「逆」です-水平反射に加えて、垂直反射と回転があります。
時計仕掛けミューズ

@ Clockwork-Muse、はい、しかし、非対称デザインは8つの順列で回転および反転できますが、対称デザインは順列が少ないため、正確な数を計算するのは困難です。したがって、すべてのソリューションには正確に1つのインバースがあるため、ホワイト/ブラックインバーティングのみに言及しました。(その逆は機能しますが、ボード全体を裏返すことができることを証明する必要があります)
アルカニストループス

ロバート・マストラゴスティーノが彼の答えで述べたように、これは実際によく知られ、よく研究された問題です。解決可能なパズルにはそれぞれ4つの解決策があり、ランダムボードの大半は解決できません。そのスペースをすべて検索するのは楽しいかもしれませんが、すでに証明(math.ksu.edu/math551/math551a.f06/lights_out.pdf)が存在するため、いくつかのドット積を作成して、いくつかの同じ答えを得ることができますマイクロ秒。:)
GrandOpener

数学の時間:すべての対称性を考慮して、別個のボードの数を計算したい場合(可解性に関係なく)、バーンサイドの補題が進むべき方法です:16の対称性があります(1つの単純な、3つの回転、4つの反射、オン/オフの反転と組み合わされたこれらの8つの各)、およびこれらの各対称に対して、いくつかのボードは完全に変更されていません。対称性ごとに完全に変更されていないボードの平均を取る場合、それは個別のボードの数に等しくなります。
アーサー

1
@PeterTaylor結果を実行するよりもシミュレータをコーディングする方が間違いなくはるかに時間がかかります。
corsiKa

4

一般化された答え:

  1. サイズ(#移動)x(#ライト)のマトリックスを作成します。
  2. その行に対応する移動でその列に対応するライトを切り替える場合はセルに1を入れ、そうでない場合は0を入れます。
  3. マトリックスでガウスヨルダン消去(モジュロ2)を実行します。
  4. 結果のマトリックスの各列に単一の1があり、すべての行に最大1つの1がある場合、すべてのグリッドは解決可能です。

1

他の人は、ランダムに生成されたパズルが解けるかどうかを見つける方法をすでに述べています。ただし、あなたが尋ねるべき質問は、実際にランダムに生成されたパズルが必要かどうかです。

ランダムに生成されたパズルにはすべて同じコアの欠陥があります。難易度はほとんど予測できません。あなたが得るかもしれないパズルは、すでに解決されたものから、ささいなもの(解決策は明らか)から難しいもの(解決策は明らかではない)、不可能(パズルはまったく解けない)まであります。難易度は予測不可能であるため、特に複数のパズルを連続して行う場合は、プレーヤーにとって満足のいくものではありません。スムーズな難易度のカーブを取得する可能性は非常に低いため、取得するパズルによっては退屈したりイライラしたりする可能性があります。

ランダム生成の別の問題は、パズルの初期化にかかる時間が予測できないことです。一般的に、解決可能なパズルを(ほぼ)すぐに取得しますが、運が悪いと、ランダムに生成されたパズルは、解決できないパズルの連続になってしまう可能性があります。

これらの両方を解決する1つの方法は、利用可能なすべての解決可能なパズルの定義済みベクトルを難易度グループに配置し、難易度に基づいて解決可能なパズルからランダムパズルを選択することです。この方法で、すべてのパズルが解けること、難易度が予測可能であること、生成が一定の時間で行われることを確信できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.