Làm thế nào tôi có thể biết nếu trò chơi câu đố của tôi luôn luôn có thể?


68

Tôi đã tạo ra một trò chơi giải đố trong đó mục tiêu là loại bỏ tất cả các viên gạch trắng. Bạn có thể thử nó ở cuối câu hỏi.

Mỗi lần, bảng được tạo ngẫu nhiên với các ô màu trắng ở những vị trí ngẫu nhiên trên lưới 5 * 5. Bạn có thể nhấp vào bất kỳ ô nào trên lưới đó và nó sẽ chuyển màu của nó và tất cả các ô chạm vào nó trên các mặt của nó. Vấn đề nan giải của tôi là thực tế là tôi không biết liệu nó có tạo ra một bảng không thể. Cách tốt nhất để kiểm tra những thứ như thế này là gì?

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
Nếu bạn thích loại trò chơi giải đố này, hãy xem Bộ sưu tập Câu đố di động của Simon Tatham . Ngoài loại này (được gọi là Flip there), bạn có thể tìm thấy các biến thể của nhiều câu đố của Nhật Bản và khác. Mọi thứ đều theo giấy phép BSD và có lẽ là một bài đọc thú vị.
Dubu

10
Làm thế nào về kỹ thuật đảo ngược nó? Bắt đầu với một bảng trống, sau đó tự động hóa, cho biết 20 lần nhấp vào các ô vuông ngẫu nhiên. Bằng cách đó bạn biết phải có một giải pháp cuối cùng.
AJFaraday

3
Tôi muốn tiếp tục chơi, nhưng do câu hỏi của bạn, sự không chắc chắn về việc tôi có thực sự chiến thắng hay không đang ăn thịt tôi! Trò chơi thú vị :)
MrDuk

@MrDuk codepen.io/qwertyquerty/pen/WMGwVW đây là dự án đã hoàn thành! Cái này là cố định, và đánh bóng lên. Tôi cũng đã tạo ra một ứng dụng điện tử.
Qwerty

@Qwerty khi tôi cố gắng xem Bút của bạn trong chế độ xem toàn trang, tôi nhận được thông báo "Chủ sở hữu của Bút này cần xác minh địa chỉ email của họ để bật Chế độ xem toàn trang". Vui lòng xác minh địa chỉ email của bạn trên CodePen để tôi có thể thưởng thức trò chơi của bạn trong cửa sổ đầy đủ! :)
stephenwade

Câu trả lời:


161

Đây là loại trò chơi trong đó cùng một động tác được thực hiện hai lần đảo ngược bảng về trạng thái trước đó. Vì vậy, để đảm bảo một bảng có thể giải được, hãy tạo nó bằng cách chơi ngược lại. Bắt đầu với một bảng đã giải (trống), sau đó bắt đầu lập trình "nhấp" ngẫu nhiên một số lần nhất định hoặc cho đến khi bảng có số ô vuông màu trắng mong muốn. Một giải pháp sau đó chỉ đơn giản là thực hiện các động tác tương tự theo thứ tự ngược lại. Các giải pháp ngắn hơn khác có thể tồn tại, nhưng bạn được đảm bảo có ít nhất một.

Một giải pháp khác, phức tạp hơn nhiều, là xác định một thuật toán giải quyết đi qua tất cả các trạng thái trò chơi có thể từ vị trí bắt đầu của bạn để cố gắng tìm giải pháp. Điều này sẽ mất nhiều thời gian hơn để thực hiện và chạy, nhưng sẽ cho phép các bảng được tạo ngẫu nhiên thực sự. Tôi sẽ không đi vào chi tiết cụ thể của giải pháp này, vì nó không phải là một ý tưởng hay.


22
@Qwerty: đối với vấn đề cụ thể của bạn, nhấp vào cùng một hình vuông hai lần sẽ tự hủy, vì vậy không bao giờ có bất kỳ lý do nào để nhấp vào bất kỳ ô vuông nào nhiều hơn một lần. Bạn có thể muốn chọn một số ô vuông nhất định để nhấp mà không lặp lại hoặc xem xét một giải pháp chỉ định tỷ lệ nhấp chuột XX% cho mỗi ô vuông trên bảng. (Ed: Câu trả lời hay, +1!)
Jeff Bowman

3
Tôi đã thực hiện gần như cùng một trò chơi trước đó và kết thúc bằng cách sử dụng phương pháp này. Tôi đã bao gồm một hình ảnh động khi bắt đầu cho thấy trạng thái đã giải quyết sẽ chuyển sang trạng thái chưa được giải quyết một cách nhanh chóng; đẹp thật.
Jared Goguen

1
@JaredGoguen lẻ, tôi đã thêm nó và quay lại đây để xem bình luận của bạn.
Qwerty

4
@JeffBowman Thật vậy, tập hợp các trò chơi có thể giải được có thể được coi là một giá trị 25 bit, với mỗi bit tương ứng với một hình vuông là số lần được lật mod 2. Vì vậy, người ta có thể tạo một số ngẫu nhiên trong phạm vi 0. .33,554,432 và sau đó tính giá trị của mỗi ô vuông trên bảng theo thứ tự ngắn.
Monty Harder

7
Đối với những gì nó có giá trị, trong khi đây là câu trả lời chính xác cho câu hỏi toán học về cách trả lời vấn đề này, đây thường là một thực tiễn đáng ngờ từ quan điểm thiết kế. Loại thế hệ này, không có bất kỳ kế hoạch cụ thể nào với nó, thường dẫn đến các câu đố cảm thấy rất 'giống nhau', không có bất kỳ điểm quan tâm cụ thể hoặc bất kỳ chủ đề thống nhất nào. Bạn có thể 'tạo thủ tục' các trường hợp vấn đề thú vị cho một trò chơi giải đố, nhưng nó thường đòi hỏi một cái nhìn khó khăn hơn nhiều về các tính năng thú vị của câu đố của bạn.
Steven Stadnicki

92

Mặc dù các câu trả lời trên rất thông minh (và có lẽ tôi sẽ làm như thế nào), trò chơi đặc biệt này rất nổi tiếng. Nó được gọi là Tắt đèn , và đã được giải toán. Có một giải pháp nếu và chỉ khi hai tổng các phần tử khác nhau (được đưa ra trên trang wikipedia) thêm vào số 0 mod 2 (tức là một số chẵn). Nói chung, một đại số tuyến tính nhỏ sẽ đưa ra các điều kiện giải pháp tương tự cho các trò chơi trên bất kỳ bảng nào.


2
Thật buồn khi biết rằng nó đã được thực hiện. Tôi nghĩ rằng tôi đã vào một cái gì đó.
Qwerty

39
@Qwerty có rất ít ý tưởng ban đầu và bạn chắc chắn không cần phải có một ý tưởng để thành công (cf Rovio, King).
OrangeDog

14
Trò chơi đặc biệt này tồn tại, nhưng bạn luôn có thể mở rộng về ý tưởng! Thêm nhiều tính năng! Thêm các quy tắc khác nhau cho những gì xảy ra khi bạn nhấp vào một nơi nào đó, như các màu cộng lại với nhau dựa trên hướng được kích hoạt / hủy kích hoạt. Thêm các công cụ khác nhau mà bạn phải sử dụng. Thêm bảng không hình chữ nhật! Rất nhiều công cụ thú vị để làm. Chỉ cần nhớ rằng một động thái phải luôn luôn đảo ngược chính nó.
Ed Marty

7
@OrangeDog: Ngay cả 'Tắt đèn' không phải là bản gốc, đó chỉ là tên thương hiệu phổ biến trong những năm 90. Ví dụ, bài viết trên wikipedia liệt kê cái nàycái này
BlueRaja - Danny Pflughoeft

1
Những câu trả lời nào bạn đang đề cập đến như "các câu trả lời trên"? Hoàn toàn không rõ ràng, vì trên màn hình của tôi, chỉ có một câu trả lời ở trên của bạn. Hãy nhớ rằng câu trả lời thay đổi thứ tự tùy thuộc vào phiếu bầu và tùy chọn người dùng. Bạn phải luôn liên kết với các câu trả lời cụ thể thay vì đề cập đến một cái gì đó "ở trên".
David Richerby

13

Đi theo cách khác khi tạo câu đố của bạn.

Thay vì chọn ngẫu nhiên các ô và chuyển chúng từ màu trắng sang màu đen, hãy bắt đầu từ một ô trống, sau đó chọn các ô nhưng thay vì chuyển ô đó thành màu đen, hãy làm cho nó như thể người dùng đã chọn nó, dẫn đến lật tất cả các ô khác xung quanh nó.

Bằng cách này, bạn sẽ được đảm bảo có ít nhất một giải pháp: người dùng sẽ phải hoàn tác những gì người chơi "AI" của bạn đã làm để tạo cấp độ.


7

Ed và Alexandre có quyền của nó.

Nhưng nếu bạn làm muốn biết nếu mọi giải pháp là có thể, có nhiều cách.

Có một số hữu hạn các câu đố có thể

Nhấp vào cùng một hình vuông hai lần sẽ tạo ra kết quả giống như không nhấp vào nó, bất kể có bao nhiêu lần nhấp được thực hiện giữa chúng. Điều đó có nghĩa là mọi giải pháp đều có thể được mô tả bằng cách cung cấp cho mỗi ô vuông một giá trị nhị phân là 'nhấp chuột' hoặc 'không nhấp chuột'. Tương tự, mỗi câu đố có thể được mô tả bằng cách cho mỗi ô vuông một giá trị nhị phân là 'được bật' hoặc 'không được đặt'. Điều đó có nghĩa là có 2 ^ 25 câu đố có thể và 2 ^ 25 giải pháp có thể. Nếu bạn có thể chứng minh rằng mỗi giải pháp giải một câu đố duy nhất thì phải có một giải pháp cho mọi câu đố. Tương tự, nếu bạn tìm thấy hai giải pháp giải cùng một câu đố thì không thể có một giải pháp cho mọi câu đố.

Ngoài ra, 2 ^ 25 là 33.554.432. Đó là khá nhiều, nhưng nó không phải là một con số không thể quản lý. Một thuật toán tốt và một máy tính tốt có lẽ có thể vũ phu trong một vài giờ, đặc biệt là khi bạn cho rằng một nửa câu đố là nghịch đảo của nửa kia.


4
Hơn một nửa là "nghịch đảo" - bên cạnh phản xạ ngang, bạn có phản xạ dọc và xoay.
Clockwork-Muse

@ Clockwork-Muse, vâng, nhưng khó tính một con số chính xác hơn, bởi vì trong khi các thiết kế bất đối xứng có thể được xoay và lật trong 8 hoán vị, các thiết kế đối xứng có ít hoán vị hơn. Vì vậy, tôi chỉ đề cập đến nghịch đảo trắng / đen, vì mọi giải pháp có chính xác 1 nghịch đảo. (Mặc dù để làm việc ngược lại, bạn phải chứng minh rằng bạn có thể lật toàn bộ bảng)
Arcanist Lupus

Hóa ra, như Robert Mastragostino đã đề cập trong câu trả lời của mình, đây thực sự là một vấn đề nổi tiếng, được nghiên cứu kỹ lưỡng. Mỗi câu đố có thể giải được có đúng 4 lời giải và phần lớn các bảng ngẫu nhiên không thể giải được. Tìm kiếm tất cả không gian đó có thể rất thú vị, nhưng vì đã có một bằng chứng ( math.ksu.edu/math551/math551a.f06/light thừng.pdf ), bạn cũng có thể thực hiện một vài sản phẩm chấm và có cùng một câu trả lời micro giây. :)
GrandOpener

Thời gian toán học: Nếu bạn muốn tính toán số lượng bảng riêng biệt (bất kể khả năng thanh toán), tính tất cả các đối xứng, thì bổ đề của Burnside là cách để đi: Có 16 đối xứng (một tầm thường, ba phép quay, bốn phép phản xạ, và sau đó mỗi trong số 8 kết hợp với đảo ngược bật / tắt) và đối với mỗi đối xứng đó, một số bảng hoàn toàn không thay đổi. Nếu bạn lấy trung bình của các bảng hoàn toàn không thay đổi trên mỗi đối xứng, thì bằng với số bảng khác biệt.
Arthur

1
@PeterTaylor Chắc chắn sẽ mất nhiều thời gian hơn để mã hóa trình giả lập so với việc chạy kết quả.
corsiKa

4

Câu trả lời khái quát:

  1. Tạo ma trận kích thước (# di chuyển) x (# đèn).
  2. Đặt 1 vào một ô nếu thực hiện di chuyển tương ứng với hàng đó bật đèn sáng tương ứng với cột đó, 0 nếu không.
  3. Thực hiện loại bỏ Gauss-Jordan (modulo 2) trên ma trận.
  4. Nếu ma trận kết quả có 1 đơn trong mỗi cột và mỗi hàng có tối đa 1 đơn, thì mọi lưới đều có thể giải được.

1

Những người khác đã đề cập đến các cách để tìm hiểu xem câu đố được tạo ngẫu nhiên của bạn có thể giải được hay không. câu hỏi bạn cũng nên đặt ra là liệu bạn có thực sự muốn các câu đố được tạo ngẫu nhiên hay không.

Tất cả các câu đố được tạo ngẫu nhiên đều có cùng một lỗ hổng cốt lõi: Khó khăn của chúng là khá nhiều khó lường. Các câu đố có thể bạn có thể nhận được có thể từ giải quyết, đến tầm thường (giải pháp rõ ràng) đến khó (giải pháp không rõ ràng) đến không thể (câu đố hoàn toàn không thể giải được). Bởi vì khó khăn là không thể đoán trước, nó tạo ra trải nghiệm không thỏa mãn cho người chơi, đặc biệt nếu họ làm nhiều câu đố liên tiếp. Họ rất khó có được một đường cong khó khăn trơn tru, điều này có thể khiến họ chán nản hoặc thất vọng tùy thuộc vào những câu đố họ nhận được.

Một vấn đề khác của thế hệ ngẫu nhiên là thời gian để câu đố khởi tạo là không thể đoán trước. Nói chung, bạn sẽ nhận được một câu đố có thể giải được (gần như) ngay lập tức, nhưng với một số điều xui xẻo, các câu đố được tạo ngẫu nhiên của bạn có thể kết thúc bằng một chuỗi các câu đố không thể giải được.

Một cách để giải quyết cả hai điều này là có các vectơ được xác định trước của mọi câu đố có thể giải được, sắp xếp thành các nhóm khó và sau đó chọn một câu đố ngẫu nhiên từ các câu đố có thể giải được dựa trên độ khó. Bằng cách này, bạn sẽ chắc chắn rằng mọi câu đố đều có thể giải được, rằng khó khăn là có thể dự đoán được và việc tạo ra sẽ được thực hiện trong thời gian liên tục.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.