퍼즐 게임이 항상 가능한지 어떻게 알 수 있습니까?


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
이런 종류의 퍼즐 게임에 관심이 있다면 Simon Tatham의 Portable Puzzle Collection을 살펴보십시오 . 이 유형 (Flip there)과는 별도로 많은 일본어 및 기타 퍼즐의 변형을 찾을 수 있습니다. 모든 것은 BSD 라이센스하에 있으며 아마도 흥미로운 읽을 거리입니다.
Dubu

10
리버스 엔지니어링은 어떻습니까? 빈 보드로 시작한 다음 자동화하여 임의의 사각형을 20 번 클릭하십시오. 그렇게하면 끝에 해결책이 있어야한다는 것을 알 수 있습니다.
AJFaraday

3
나는 계속 놀고 싶지만, 당신의 질문으로 인해, 내가 실제로 이길 지에 대한 불확실성이 나를 먹고 있습니다! 재미있는 게임 :)
MrDuk

@MrDuk codepen.io/qwertyquerty/pen/WMGwVW 여기 완성 된 프로젝트가 있습니다! 이것은 고정되고 세련됩니다. 나는 또한 전자 앱을 만들었습니다.
Qwerty

@Qwerty 전체 페이지보기에서 펜을 보려고 할 때 "이 펜의 소유자는 전체 페이지보기를 사용하려면 전자 메일 주소를 확인해야합니다."라는 메시지가 나타납니다. 전체 창에서 게임을 즐길 수 있도록 CodePen에서 이메일 주소를 확인하십시오! :)
stephenwade

답변:


161

이것은 같은 움직임이 두 번 수행되어 보드를 이전 상태로 되 돌리는 게임 유형입니다. 따라서 보드가 풀릴 수있게하려면 반대로 재생하여 보드를 생성하십시오. 해결 된 (빈) 보드로 시작한 다음 특정 횟수만큼 또는 보드가 원하는 수의 흰색 사각형을 가질 때까지 프로그래밍 방식으로 "클릭"을 시작하십시오. 한 가지 해결책은 단순히 동일한 이동을 역순으로 수행하는 것입니다. 더 짧은 다른 솔루션이있을 수 있지만 적어도 하나는 있어야합니다.

훨씬 더 복잡한 또 다른 솔루션은 시작 위치에서 가능한 모든 게임 상태를 통과하여 솔루션을 찾으려고하는 해결 알고리즘을 정의하는 것입니다. 이를 구현하고 실행하는 데 시간이 오래 걸리지 만 보드가 실제로 임의로 생성 될 수 있습니다. 이 솔루션의 구체적인 내용은 다루지 않겠습니다. 왜냐하면 그다지 좋은 아이디어는 아니기 때문입니다.


22
@Qwerty : 특정 문제의 경우 같은 사각형을 두 번 클릭하면 자체적으로 취소되므로 사각형을 두 번 이상 클릭 할 이유가 없습니다. 반복하지 않고 클릭 할 특정 수의 사각형을 선택하거나 보드의 각 사각형에 XX %의 클릭 확률을 지정하는 솔루션을 고려할 수 있습니다. (Ed : Nice answer, +1!)
Jeff Bowman

3
나는 거의 똑같은 게임을 만들었고이 접근법을 사용하여 끝났습니다. 처음에는 해결 된 상태가 해결되지 않은 상태로가는 모습을 빠르게 보여주는 애니메이션을 포함 시켰습니다. 예뻤습니다.
Jared Goguen

1
@JaredGoguen 이상해, 나는 그것을 추가하고 당신의 의견을보기 위해 여기로 돌아 왔습니다.
Qwerty

4
@JeffBowman 실제로, 해결 가능한 게임 세트는 25 비트 값으로 취급 될 수 있으며, 각 비트는 모드 2를 뒤집은 횟수 인 제곱에 해당합니다. 따라서 0 범위의 난수를 생성 할 수 있습니다. .33,554,432 그런 다음 보드의 각 사각형 값을 짧은 순서로 계산하십시오.
Monty Harder

7
가치가있는 것은 이것이이 문제에 어떻게 대답해야하는지에 대한 수학적 질문에 대한 정답이지만, 이것은 일반적으로 디자인 관점에서 모호한 관행입니다. 특별한 계획이없는 이런 종류의 세대는 일반적으로 특별한 관심의 대상이나 통일 된 주제가없는 매우 '사미'라고 느끼는 퍼즐을 만듭니다. 퍼즐 게임에 대해 흥미로운 문제 인스턴스를 '절차 적으로 생성'하는 것이 가능하지만 일반적으로 퍼즐의 흥미로운 기능이 무엇인지 훨씬 더 세밀하게 검토해야합니다.
Steven Stadnicki

92

위의 답변은 영리하지만 (어쩌면 내가 어떻게 할 것인지),이 특정 게임은 매우 잘 알려져 있습니다. 이를 Lights Out 이라고하며 수학적으로 해결되었습니다. wikipedia 페이지에 제공된 다양한 요소의 두 합이 0 mod 2 (예 : 짝수)에 추가되는 경우에만 해결책이 있습니다. 일반적으로 작은 선형 대수는 모든 보드의 게임에 대해 비슷한 솔루션 조건을 제공해야합니다.


2
그것이 이미 만들어 졌다는 것은 슬픈 일입니다. 나는 무언가에 있다고 생각했다.
Qwerty

39
@ Qwerty에는 독창적 인 아이디어가 거의 없으며 반드시 성공하기 위해 아이디어를 가질 필요는 없습니다 (참조 : Rovio, King).
OrangeDog

14
이 특정 게임이 존재하지만 아이디어를 항상 확장 할 수 있습니다! 더 많은 기능을 추가하십시오! 활성화 / 비활성화 된 방향에 따라 함께 추가되는 색상과 같이 어딘가 클릭 ​​할 때 발생하는 동작에 대해 다른 규칙을 추가하십시오. 사용해야 할 다른“도구”를 추가하십시오. 직사각형이 아닌 보드를 추가하십시오! 할 많은 재미있는 것들. 이동은 항상 자신을 반대로해야한다는 것을 기억하십시오.
Ed Marty

7
@OrangeDog : 'Lights Out'조차 독창적이지 않았습니다. 90 년대에 인기를 얻은 브랜드 이름 일뿐입니다. 위키 피 디아 문서, 예를 들어, 나열
BlueRaja - 대니 Pflughoeft

1
어떤 답변을 "위의 답변"이라고합니까? 내 화면에는 귀하의 답변 위에 하나만 있기 때문에 완전히 불분명합니다. 답변은 투표 및 사용자 옵션에 따라 순서가 변경됩니다. 당신은 항상 "위"를 언급하는 대신 특정 답변에 연결해야합니다.
David Richerby

13

퍼즐을 만들 때 다른 방향으로 가십시오.

대신 무작위로 타일을 선택하고 검은 색에서 흰색으로 돌려의 다음 대신 회전의 타일을 선택, 백지에서 시작 하는 사용자가 선택한 것처럼 다른 모든 타일을 뒤집어 결과, 블랙 타일을 그것을 만들 그 주위에.

이렇게하면 최소한 하나의 솔루션 이 보장됩니다 . 사용자는 "AI"플레이어가 레벨을 생성하기 위해 수행 한 작업을 취소해야합니다.


7

에드와 알렉산드르의 권리가 있습니다.

그러나 만약 당신 모든 솔루션이 가능한 경우 알고 싶은, 방법이있다.

한정된 수의 퍼즐이 있습니다

같은 사각형을 두 번 클릭하면 클릭 사이에 클릭이 몇 번 있더라도 전혀 클릭하지 않는 것과 동일한 결과가 생성됩니다. 즉, 각 사각형에 '클릭 됨'또는 '클릭하지 않음'의 이진 값을 지정하여 모든 솔루션을 설명 할 수 있습니다. 마찬가지로, 각 사각형에 '토글'또는 '토글되지 않음'의 이진 값을 제공하여 각 퍼즐을 설명 할 수 있습니다. 이는 2 ^ 25 가능한 퍼즐과 2 ^ 25 가능한 솔루션이 있음을 의미합니다. 각 솔루션이 고유 한 퍼즐을 해결한다는 것을 증명할 수 있다면 모든 퍼즐에 대한 솔루션이 있어야합니다. 마찬가지로, 같은 퍼즐을 해결하는 두 가지 솔루션을 찾으면 모든 퍼즐에 대한 해결책이있을 수 없습니다.

또한 2 ^ 25는 33,554,432입니다. 꽤 많지만 관리 할 수없는 숫자는 아닙니다. 좋은 알고리즘과 괜찮은 컴퓨터는 아마도 두 시간 동안, 특히 퍼즐의 절반이 다른 절반의 반대라고 생각할 때 무차별 한 힘을 줄 수 있습니다.


4
절반 이상은 "반전"입니다. 수평 반사 외에 수직 반사 및 회전이 있습니다.
Clockwork-Muse

@ Clockwork-Muse, 그렇습니다. 그러나 비대칭 디자인은 8 개의 순열로 회전하고 뒤집을 수 있지만 대칭 디자인은 순열이 적기 때문에 정확한 수를 계산하기가 어렵습니다. 따라서 모든 솔루션에 정확히 1의 역수가 있으므로 흰색 / 검정 반전 만 언급했습니다. (그 반대가 작동하려면 있지만, 당신은 당신이 전체 보드를 전환 할 수 있음을 증명해야 함)
신비 술사 루푸스

Robert Mastragostino가 그의 답변에서 언급했듯이, 이것은 실제로 잘 알려져 있고 잘 연구 된 문제입니다. 각 해결 가능한 퍼즐에는 정확히 4 개의 솔루션이 있으며 대부분의 랜덤 보드는 해결할 수 없습니다. 해당 공간을 모두 검색하는 것은 재미있을 수 있지만 이미 증거가 있기 때문에 ( math.ksu.edu/math551/math551a.f06/lights_out.pdf ) 몇 개의 내적을 수행 할 수 있으며 몇 가지 동일한 결과를 얻을 수 있습니다 마이크로 초. :)
GrandOpener

수학 시간 : 모든 대칭을 고려하여 고유 한 보드 수를 계산하려면 (해상도에 관계없이) 번 사이드의 정리는 다음과 같은 방법으로 진행됩니다. 각 8 개는 on / off의 반전과 결합되어 있으며, 각 대칭에 대해 일부 보드 수는 완전히 변경되지 않았습니다. 대칭 당 완전히 변경되지 않은 보드의 평균을 취하면 이는 개별 보드의 수와 같습니다.
Arthur

1
@PeterTaylor 결과를 실행하는 것보다 시뮬레이터를 코딩하는 데 시간이 훨씬 더 걸립니다.
corsiKa

4

일반적인 답변 :

  1. 크기 (# 이동) x (# 표시 등)의 행렬을 만듭니다.
  2. 해당 행에 해당하는 이동이 해당 열에 해당하는 표시등을 토글하는 경우 1을 셀에 넣으십시오. 그렇지 않으면 0입니다.
  3. 매트릭스에서 Gauss-Jordan 제거 (모듈로 2)를 수행하십시오.
  4. 결과 행렬에 각 열에 단일 1이 있고 모든 행에 최대 하나의 단일 1이 있으면 모든 그리드를 해결할 수 있습니다.

1

다른 사람들은 무작위로 생성 된 퍼즐을 해결할 수 있는지 확인하는 방법을 이미 언급했습니다. 그래도 물어봐야 할 질문은 실제로 무작위로 생성 된 퍼즐을 원하는지 여부입니다.

무작위로 생성 된 퍼즐은 모두 같은 핵심 결함을 가지고 있습니다. 그들의 어려움은 거의 예측할 수 없습니다. 당신이 얻을 수있는 가능한 퍼즐은 이미 해결 된 것에서부터 사소한 것 (솔루션은 명백하다), 단단한 것 (솔루션은 명확하지 않음), 불가능한 것 (퍼즐은 전혀 풀리지 않는다)까지 다양합니다. 난이도는 예측할 수 없기 때문에 플레이어가 특히 여러 퍼즐을 연속으로하는 경우 만족스럽지 못한 경험을합니다. 매끄러운 난이도 곡선을 얻을 가능성이 거의 없으므로 어떤 퍼즐을 얻는 지에 따라 지루하거나 좌절 할 수 있습니다.

랜덤 생성의 또 다른 문제점은 퍼즐을 초기화하는 데 걸리는 시간을 예측할 수 없다는 것입니다. 일반적으로, 당신은 (거의) 즉시 해결 가능한 퍼즐을 얻을 것입니다, 그러나 약간의 불운으로, 무작위로 생성 된 퍼즐은 해결할 수없는 퍼즐로 끝날 수 있습니다.

이 두 가지를 해결하는 한 가지 방법은 사용 가능한 모든 해결 가능한 퍼즐의 미리 정의 된 벡터를 가지고 난이도 그룹으로 배열 한 다음 난이도에 따라 해결 가능한 퍼즐에서 임의의 퍼즐을 선택하는 것입니다. 이런 식으로 모든 퍼즐을 풀 수 있고 어려움을 예측할 수 있으며 일정한 시간에 생성이 이루어질 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.