Skip to content

Instantly share code, notes, and snippets.

@kentbrew
Created June 13, 2015 16:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kentbrew/4fcc9d4fc7824c8d1a04 to your computer and use it in GitHub Desktop.
Save kentbrew/4fcc9d4fc7824c8d1a04 to your computer and use it in GitHub Desktop.
Glint 1.0: a single-page puzzle game straight outta 1994. See me run on http://tilde.club/~kentbrew/glint.html
<!doctype html>
<html>
<head>
<title>Glint 1.0</title>
<style>
body {
font-family: monospace;
}
</style>
</head>
<body>
<h3><a href="index.html">~kentbrew</a>: Glint 1.0</h3>
<table bgcolor="black">
<tr>
<td>
<table id="board" border="10" bgcolor="black" bordercolor="black" cellspacing="1" cellpadding="0">
<tr>
<td>
<table border="1" bordercolor="black" cellspacing="0">
<tr>
<td id="000" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="010" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="020" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
<tr>
<td id="100" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="110" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="120" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
</table>
</td>
<td>
<table border="1" bordercolor="black" cellspacing="0">
<tr>
<td id="031" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="041" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="051" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
<tr>
<td id="131" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="141" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="151" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table border="1" bordercolor="black" cellspacing="0">
<tr>
<td id="202" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="212" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="222" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
<tr>
<td id="302" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="312" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="322" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
</table>
</td>
<td>
<table border="1" bordercolor="black" cellspacing="0">
<tr>
<td id="233" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="243" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="253" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
<tr>
<td id="333" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="343" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="353" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table border="1" bordercolor="black" cellspacing="0">
<tr>
<td id="404" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="414" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="424" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
<tr>
<td id="504" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="514" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="524" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
</table>
</td>
<td>
<table border="1" bordercolor="black" cellspacing="0">
<tr>
<td id="435" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="445" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="455" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
<tr>
<td id="535" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="545" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
<td id="555" bgcolor="black" height="36" width="32" onclick="doMove(this);">&nbsp;</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td align="center">
<font color="white" face="verdana" size="-1"><p id="status"></p></font>
</td>
</tr>
</table>
<h3>What's This?</h3>
<p>Glint is a toy originally made for <a href="http://kentbrewster.com/glint-an-iphone-toy/">the iPod Touch</a>, back when there was no such thing as the App Store and Steve Jobs insisted we should all make "Web apps" out of HTML, CSS, and JavaScript. (Once again, Steve was ahead of his time.)</p>
<p>To play, fill the board completely with colors without duplicating a color in any row, column, or sub-board. If you mess up, some pieces will disappear and go back in the stack. It's like Sudoku, only hostile to color-blind people.</p>
<p>This version of Glint was specially made for tilde.club, to answer this question: <b>"If I'd made Glint in 1996, what would it have looked like?"</b></p>
<p>Answer? TABLES! And FONT tags! And lots and lots of inline JavaScript, the kind that makes Doug Crockford spit out his Diet Dr. Pepper. Turns out I have <b>an unique set of skills</b> needed to make this happen: I spent a year and a half building individual ad mantles for the front page at yahoo.com, when it had to run flawlessly on Netscape 4.79.</p>
<p><b>I loved making this.</b> LOVED. I've been sitting here cackling and rubbing my hands together all night. Which pretty much describes the entire tilde.club experience so far.</p>
<h3>Notes</h3>
<p><b>Unexpected consequence of 1996 technology.</b> After I pinch to zoom, this version of Glint seems to work better on my recent-generation iPhone than the original version, which was optimized for 320px and has goofy Apple viewport headers that blows it up out of whack.</p>
<p><b>Trigger warning for OCD.</b> Once you start trying for that perfect score you will never, ever stop.</p>
<p><b>Research in progress.</b> Hooked up GA over lunch, trying to understand how often someone wins, restarts, misplays each of the available colors, etc. Nothing evil, I promise!</p>
<p><b>Special cool thing.</b> lurking in here is a predictably-random number generator inspired by a processor bug documented in <b><i><a href="http://books.google.com/books?id=7vuNLcQhg8UC&pg=PA275&lpg=PA275&dq=233280+fortran&source=bl&ots=BCYF3zKJMM&sig=6xSzZO7LWx7JYUvDTIR-n-4UN4k&hl=en&sa=X&ei=Vs40VPnlKtCmyAT9l4CACw&ved=0CB4Q6AEwAA#v=onepage&q=233280%20fortran&f=false">Numerical Recipes in Fortran 77</a></i></b>. Why this is neat: we can seed it with the Unix timestamp divided by 86,400,000 to make a special game of Glint for every day, and you should come back tomorrow for the next one. You can reload the page to try today's puzzle again, or--if you're impatient--just change the number after the hash in your URL bar.</p>
<p>Here's how the predictably-random number generator gives us the same game for every day:</p>
<p><pre><font color="brown"> if (!window.location.hash) {
window.location.hash = Math.floor(new Date().getTime() / 86400000);
}
window.onhashchange = function () {
document.location.reload();
};
var gameId = window.location.hash.split('#')[1];
var rseed = gameId;
var rnd = function (n) {
rseed = (rseed * 9301 + 49297) % 233280;
r = Math.floor(rseed / (233280.0) * n);
return r;
};</font></pre></p>
<p>Once we have this in place we call <font color="brown">rnd(n)</font> instead of <font color="brown">Math.random(n)</font>, and we get a stream of numbers that look random but are always the same for any initial seed. Presto, procedurally-generated quasi-randomness!</p>
<p>---</p>
<p>
Games played since 10/8/2014:
<!-- hitwebcounter Code START -->
<a href="http://www.hitwebcounter.com/">
<img align="absmiddle" src="http://hitwebcounter.com/counter/counter.php?page=5803337&style=0025&nbdigits=5&type=page&initCount=0" border="0" >
</a>
</p>
<script>
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<script language="JavaScript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-55546970-1']);
var board = document.getElementById("board");
var theColors = [
"red",
"yellow",
"blue",
"cyan",
"green",
"violet"
];
var moveColor;
var moves = -7;
var stack = [
"red", "red", "red", "red", "red", "red",
"yellow", "yellow", "yellow", "yellow", "yellow", "yellow",
"blue", "blue", "blue", "blue", "blue", "blue",
"green", "green", "green", "green", "green", "green",
"orange", "orange", "orange", "orange", "orange", "orange",
"purple", "purple", "purple", "purple", "purple", "purple"
];
if (!window.location.hash) {
window.location.hash = Math.floor(new Date().getTime() / 86400000);
}
window.onhashchange = function () {
document.location.reload();
};
window.onbeforeunload = function () {
_gaq.push(['_trackEvent', 'exit', 'status', gameId + ':' + moves + ':' + stack.length]);
};
var gameId = window.location.hash.split('#')[1];
var rseed = gameId;
if (gameId) {
_gaq.push(['_trackEvent', 'start', 'id', '' + gameId + '']);
}
var rnd = function (n) {
rseed = (rseed * 9301 + 49297) % 233280;
r = Math.floor(rseed / (233280.0) * n);
return r;
};
for (var j, x, i = stack.length; i; j = rnd(i), x = stack[--i], stack[i] = stack[j], stack[j] = x);
var showMoveColor = function (c) {
var table = document.getElementsByTagName('TABLE');
for (var i = 0; i < table.length; i = i + 1) {
if (table[i].getAttribute("bordercolor")) {
table[i].setAttribute("bordercolor", c);
}
}
};
var updateStatus = function (win) {
var left = stack.length;
if (win) {
left = 0;
}
document.getElementById('status').innerHTML = 'Game: ' + gameId + ' Moves: ' + moves + ' Left: ' + left;
};
var getNextMove = function() {
moves = moves + 1;
if (stack.length) {
moveColor = stack.pop();
showMoveColor(moveColor);
updateStatus();
} else {
showMoveColor('black');
updateStatus(true);
if (moves == 30) {
var msg = "Perfect score!";
} else {
var msg = "You win! Now see if you can do it in less than " + moves + " moves!";
}
_gaq.push(['_trackEvent', 'win', 'score', '' + moves + '']);
alert(msg);
}
};
var doMove = function (cell) {
_gaq.push(['_trackEvent', 'doMove']);
var badMove = false;
var color = cell.getAttribute("bgcolor");
if (color == "black") {
cell.setAttribute("bgcolor", moveColor);
var row = cell.id[0];
var col = cell.id[1];
var sub = cell.id[2];
var check = document.getElementsByTagName('TD');
for (var i = 0; i < check.length; i = i + 1) {
var t = check[i].id;
if (t && t != cell.id) {
var bgColor = check[i].getAttribute("bgcolor");
if (bgColor != "black") {
if (t[0] == row) {
if (bgColor == moveColor) {
for (var j = 0; j < check.length; j = j + 1) {
var k = check[j].id;
if (k && k !== cell.id) {
var kr = k[0];
if (kr == row) {
var xbg = check[j].getAttribute("bgcolor");
if (xbg !== 'black') {
badMove = true;
stack.unshift(xbg);
check[j].setAttribute("bgcolor", "black");
}
}
}
}
}
} else {
if (t[1] == col) {
if (bgColor == moveColor) {
for (var j = 0; j < check.length; j = j + 1) {
var k = check[j].id;
if (k && k !== cell.id) {
var kc = k[1];
if (kc == col) {
var xbg = check[j].getAttribute("bgcolor");
if (xbg !== 'black') {
badMove = true;
stack.unshift(xbg);
check[j].setAttribute("bgcolor", "black");
}
}
}
}
}
} else {
if (t[2] == sub) {
if (bgColor == moveColor) {
for (var j = 0; j < check.length; j = j + 1) {
var k = check[j].id;
if (k && k !== cell.id) {
var ks = k[2];
if (ks == sub) {
var xbg = check[j].getAttribute("bgcolor");
if (xbg !== 'black') {
badMove = true;
stack.unshift(xbg);
check[j].setAttribute("bgcolor", "black");
}
}
}
}
}
}
}
}
}
}
}
if (badMove) {
_gaq.push(['_trackEvent', 'badMove', 'color', moveColor]);
} else {
_gaq.push(['_trackEvent', 'goodMove', 'color', moveColor]);
}
getNextMove();
}
};
getNextMove();
doMove(document.getElementById('222'));
doMove(document.getElementById('333'));
doMove(document.getElementById('000'));
doMove(document.getElementById('555'));
doMove(document.getElementById('141'));
doMove(document.getElementById('414'));
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment