Created
November 18, 2014 21:25
-
-
Save 3ki5tj/e58dc6dd31329cc0ed4c to your computer and use it in GitHub Desktop.
Lightsout puzzle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" > | |
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html;charset=utf-8"> | |
<title>Lights out</title> | |
<style type="text/css"> | |
/*<![CDATA[*/ | |
body { | |
font: 90% "MS Trebunchet", "Lucida Grande", 'Verdana', 'Tahoma', 'Calibri', sans-serif; | |
width: 600px; | |
margin: auto; | |
} | |
h1 { | |
font: small-caps 160% "Constantia", "Times New Roman", serif; | |
} | |
h2 { | |
font: small-caps 130% "Geogia", "Times New Roman", serif; | |
margin: 0px 0px 10px 0px; | |
border-top: #e0e0e0 2px dotted; | |
padding-top: 10px; | |
} | |
table { | |
border-collapse: collapse; | |
margin: 10px 0px; | |
-moz-user-select: none; | |
-webkit-user-select: none; | |
} | |
td { | |
width: 30px; | |
height: 30px; | |
text-align: center; | |
padding: 0px; | |
margin: 0px; | |
color: #808080; /* color for hints */ | |
background-color: #e0e0e0; | |
border: #ffffff 2px outset; | |
font-weight: bold; | |
} | |
td.off { | |
} | |
td.on { | |
background-color: #ff0033; | |
border: 2px groove #ff0033; | |
} | |
/*]]>*/ | |
</style> | |
<script type="text/javascript"> | |
// <![CDATA[ | |
var n = 5; | |
var solmax = 1000; | |
var carr = new Array(); // if light is on | |
var hint = new Array(); // hinted region | |
var clicked = new Array(); // clicked odd number of times | |
function draw() | |
{ | |
var s = '<table id="table">\n'; | |
for (i = 0; i < n; i++) { | |
s += "<tr>\n" | |
for (j = 0; j < n; j++) { // draw 35*35 squares | |
var id = i*n + j; | |
s += '<td id="' + id + '" onclick="gridclick(id)"> </' + 'td>\n'; | |
} | |
s += '</' + 'tr>\n'; | |
} | |
s += '</' + 'table>'; | |
document.getElementById("tablewrapper").innerHTML = s; | |
update(); | |
} | |
function update() | |
{ | |
for (var id = 0; id < n*n; id++) | |
document.getElementById(""+id).innerHTML = | |
(!clicked[id] && hint[id]) ? "×" : " "; | |
} | |
function getn() | |
{ | |
o = document.getElementById("n"); | |
n = parseInt(o.value); | |
if (n < 1) n = 1; | |
if (n > 30) n = 30; | |
o.value = n; | |
solmax = parseInt(document.getElementById("solmax").value); | |
} | |
function play() | |
{ | |
getn(); | |
for (i = 0; i < n*n; i++) clicked[i] = carr[i] = hint[i] = 0; | |
draw(); | |
} | |
function flip(i, j) | |
{ | |
if (i >= 0 && i < n && j >= 0 && j < n) { | |
var id = i*n+j; | |
carr[id] = !carr[id]; | |
o = document.getElementById(id).style; | |
document.getElementById(id).className = carr[id] ? "on" : "off"; | |
//o.borderColor = o.backgroundColor = (carr[id] ? "#ff0080" : "#e0e0e0"); | |
} | |
} | |
function gridclick(id) | |
{ | |
id = id*1; | |
i = (id/n)|0; j = id % n; | |
flip(i, j); | |
flip(i+1, j); | |
flip(i-1, j); | |
flip(i, j+1); | |
flip(i, j-1); | |
clicked[id] = !clicked[id]; | |
update(); | |
var win = true; | |
for (id = 0; id < n*n && win; id++) | |
if (carr[id] == 0) win = false; | |
if (win) alert("Congratulations! You win!"); | |
} | |
function bitcount(i) | |
{ | |
var tmp = i - ((i >> 1) & 033333333333) - ((i >> 2) & 011111111111); | |
return ((tmp + (tmp >> 3)) & 030707070707) % 63; | |
} | |
var state = new Array(); | |
function solve() | |
{ | |
lst = document.getElementById("results"); | |
lst.length = 0; // clear list | |
lst.options[0] = new Option("Searching..."); | |
getn(); | |
var count = 0, idbest = 0; | |
var hitmin = 1000000; | |
var MAX = (1 << n) - 1; | |
state[0] = 0; // the hidden 0th row | |
for (row = MAX; row >= 0; row--) { // to enumerate every possibility of the first row | |
for (me = row, j = 1; j <= n; j++) { // to derive other rows | |
state[j] = me^MAX; // inverse the color of the previous row | |
me = (state[j-1] ^ state[j] ^ (state[j]>>1) ^ (state[j]<<1)) & MAX; | |
} | |
if (me == MAX) { // on the last row lights are all on, found a solution | |
for (hits = 0, j = 1; j <= n; j++) | |
hits += bitcount(state[j]); | |
if (hits < hitmin) { | |
idbest = count; | |
hitmin = hits; | |
document.getElementById("best").innerHTML = "Best: solution " + count + "."; | |
} | |
lst.options[count] = new Option("" + count + " (" + hits + " clicks): " + state[1]); | |
count++; | |
if (count > solmax) break; | |
} | |
} | |
if (count) { | |
o = document.getElementById("results"); | |
lst.style.visibility = "visible"; | |
lst.selectedIndex = idbest; | |
selectsolution(); | |
} | |
} | |
function init() | |
{ | |
document.getElementById("results").style.visibility = "hidden"; | |
play(); | |
} | |
// parse option | |
function selectsolution() | |
{ | |
lst = document.getElementById("results"); | |
if (lst.selectedIndex < 0) return; | |
for (i = 0; i < n*n; i++) clicked[i] = carr[i] = hint[i] = 0; | |
s = lst.options[lst.selectedIndex].text; | |
s = s.substring(s.indexOf(":")+2, s.length); | |
arr = s.split(" "); | |
MAX = (1<<n)-1; | |
for (me = arr[0]^MAX, state[0] = 0, j = 1; j <= n; j++) { // to derive other rows | |
state[j] = me^MAX; | |
me = (state[j-1]^state[j]^(state[j]>>1)^(state[j]<<1)) & MAX; | |
for (i = 0; i < n; i++) | |
hint[(j-1)*n+i] = (state[j]>>i)&1; | |
} | |
draw(); | |
} | |
window.onload = init; | |
// ]]> | |
</script> | |
</head> | |
<body> | |
<h1>Lights out</h1> | |
<p>On a N×N board, all lights are initially white. | |
By clicking a light, the color of this light and four adjacent ones (up,down,left,right) | |
will be flipped (from red to white, or from white to red). | |
The aim is to turn all lights to red. | |
<div id="appwrapper"> | |
N: <input type="text" id="n" value="5" size="4"> | |
<input type="button" onClick="play();" value="Play"> | |
<div id="tablewrapper" onSelectStart="return false;"> </div> | |
<input type="button" onClick="solve();" value="Solve"> | |
limit <input type="text" id="solmax" value="1000" size="8"> solutions<br> | |
<select id="results" onChange="selectsolution()"> | |
<option value="null"> </option> | |
</select> | |
<span id="best"></span><br> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment