|
<!DOCTYPE html> |
|
<title>Pac-Man in 140byt.es by @maettig</title> |
|
<pre>LOADING...</pre> |
|
<h2></h2> |
|
<span id="points">0</span> POINTS |
|
<style type="text/css"> |
|
* { color: #FFF; font-family: Consolas, monospace; text-shadow: 0 0 .2em #FFF; } |
|
body { background: #000; margin: 4em; } |
|
h2 { font-size: 3em; margin: .2em 0; } |
|
img { border: 0; font-size: 32px; height: 32px; padding: 1px; vertical-align: top; width: 32px; } |
|
pre { font-size: 58px; line-height: 32px; margin: 0; } |
|
#points { font-size: 2em; line-height: 2em; } |
|
.air { color: #222; text-shadow: 0 0 .2em #222; } |
|
.player { color: #FD0; text-shadow: 0 0 .2em #FD0; } |
|
.wall { color: #30F; text-shadow: 0 0 .2em #30F; } |
|
.ghost { color: #A0F; text-shadow: 0 0 .2em #A0F; } |
|
</style> |
|
<script type="text/javascript"> |
|
// 138 bytes |
|
var getFirstElement = function(a) |
|
{ |
|
a = /([#.]?)(.*)/.exec(a || '*'); |
|
a = document['getElement' + (a[1] > '-' ? 'sByClassName' : a[1] ? 'ById' : 'sByTagName')](a[2]); |
|
return a[0] || a |
|
} |
|
// 69 bytes |
|
var getOuterHTML = function(a) |
|
{ |
|
return a.outerHTML || XMLSerializer().serializeToString(a) |
|
} |
|
// 126 bytes |
|
var parseLevel = function(l, w) |
|
{ |
|
l = l.join ? l[0].length > 1 //if it's an array of strings per row |
|
? l.join('\n') : l.join('') : l; //then join rows else join characters |
|
w = l.indexOf('\n') + 1; //calculate row length |
|
// It would be possible to calculate player position with `l.indexOf(1)` but that's 7 bytes longer. |
|
// It would be possible to count gold with `l.split(2).length - 1` but that's 11 bytes longer. |
|
l = l.split(''); //convert to character array |
|
l.w = w; //store width |
|
l.c = l.d = l.p = 0; //initialize gold count, player walking direction, points |
|
return l |
|
} |
|
// 110 bytes |
|
var initLevel = function(l) |
|
{ |
|
for (var i = g = []; i < l.length; ) |
|
{ |
|
l[i] & 8 && //if found a ghost then |
|
g.push({ //append to the array of ghosts |
|
x: i, //ghost position |
|
d: 0 //ghost walking direction (0 = north) |
|
}); |
|
if (l[i] & 1) l.x = i; //store player position |
|
l.c += l[i++] == 2 //count gold |
|
} |
|
return g |
|
} |
|
// 136 bytes |
|
var loadSprites = function(t, f) //theme, filename with $1 placeholder |
|
{ |
|
for (var i in t) |
|
with (new Image()) //new is required in IE |
|
{ |
|
alt = i; |
|
onload = function() |
|
{ |
|
t[this.alt] = getOuterHTML(this) |
|
} |
|
src = t[i].replace(/.*"(.*)".*/, f) |
|
} |
|
} |
|
// 88 bytes |
|
var renderLevel = function(l, t) //level object, optional theme object |
|
{ |
|
for (var c, h = '', x = 0; x < l.length; x++) |
|
h += t && t[c = l[x] & 8 || l[x]] //ghosts can sit on gold, render the ghost only |
|
? t[c] : c; //use theme or original character (e.g. the newline) |
|
return h |
|
} |
|
// 129 bytes |
|
var updatePlayer = function(l, k) |
|
{ |
|
l[l.x] = 0; |
|
l.p += l[l.x += l.d = k - 37 >> 2 || l[l.x + (k = k % 2 ? k - 38 : (k - 39) * l.w)] & 4 ? l[l.x + l.d] & 4 ? 0 : l.d : k] == 2; |
|
l.e |= l[l.x] & 8; |
|
l[l.x] = 1 |
|
} |
|
// 134 bytes |
|
var updateGhosts = function(a, l, g, d) |
|
{ |
|
for (g in a) |
|
l[a[g].x] &= 7; //remove all ghosts first |
|
for (g in a) |
|
{ |
|
g = a[g]; |
|
d = g.d % 4; |
|
d = d % 2 ? d - 2 : (d - 1) * l.w; //calculate walking direction |
|
l[g.x + d] & 4 //if walking into a wall |
|
? g.d++ //rotate ghost by 90 degree |
|
: l.e |= 1 & l[ //else check if hitting the player |
|
g.x += d]; //and walk |
|
l[g.x] |= 8 //place ghost |
|
} |
|
} |
|
var levels = [parseLevel([ |
|
'44444444444', //no ghosts |
|
'42222222224', |
|
'42444242424', |
|
'42412242424', |
|
'42444242424', |
|
'42222242224', |
|
'44444444444']), |
|
parseLevel([ |
|
'4444444444444', //1 ghost |
|
'4222224222224', |
|
'4244424244424', |
|
'4242228222424', |
|
'4242424442424', |
|
'4242421242424', |
|
'4242444242424', |
|
'4242222222424', |
|
'4244424244424', |
|
'4222224222224', |
|
'4444444444444']), |
|
parseLevel([ |
|
'444444444444444', //2 ghosts |
|
'424222222222224', |
|
'424244444242444', |
|
'422222222222224', |
|
'424244444242424', |
|
'424242212242424', |
|
'424242444442424', |
|
'422222222222224', |
|
'444242444442424', |
|
'482222222222484', |
|
'444444444444444']), |
|
parseLevel([ |
|
'4444444444444444444', //classic with 2 ghosts |
|
'4222242228222422224', |
|
'4244242444442424424', |
|
'4242222222222222424', |
|
'4242442440442442424', |
|
'4222222408042222224', |
|
'4242442444442442424', |
|
'4242222221222222424', |
|
'4244242444442424424', |
|
'4222242222222422224', |
|
'4444444444444444444']), |
|
parseLevel([ |
|
'444444444444444', //3 ghosts |
|
'422222282222224', |
|
'424444424444424', |
|
'424222424822424', |
|
'424242424242424', |
|
'422242212242224', |
|
'424242424242424', |
|
'424228424222424', |
|
'424444424444424', |
|
'422222222222224', |
|
'444444444444444']), |
|
parseLevel([ |
|
'4444444444444444444', //5 ghosts |
|
'4222222248222222224', |
|
'4244444242444442444', |
|
'4242222282222222224', |
|
'4242444442444442424', |
|
'4242422242482222424', |
|
'4242424242424244424', |
|
'4222222222222228224', |
|
'4244424242424242424', |
|
'4242222842422242424', |
|
'4242444442444442424', |
|
'4222222222222222424', |
|
'4442444442424444424', |
|
'4222222122422222224', |
|
'4444444444444444444'])]; |
|
var theme = { |
|
0: '<span class="air">\u2219</span>', //doesn't need to be checked |
|
1: '<span class="player">\u263B</span>', //can be checked with &1 |
|
2: '<span class="gold">\u2219</span>', //can be checked with &2 |
|
4: '<span class="wall">\u25A1</span>', //can be checked with &4 |
|
8: '<span class="ghost">\u00A4</span>', //can be checked with &8 or >7 |
|
'\n': '<br>' //required for IE |
|
} |
|
loadSprites(theme, 'sprite-$1.gif'); //load optional GIF files from the same directory |
|
document.onkeydown = function(e) |
|
{ |
|
level.keyCode = (e || window.event).keyCode |
|
} |
|
var ghosts, level, number = 0; |
|
window.setInterval(function() |
|
{ |
|
if (!level && levels[number]) |
|
ghosts = initLevel(level = levels[number++]); |
|
if (level.p >= level.c) |
|
{ |
|
if (level.p < level.c-- + 4) //wait a few moments before loading next level |
|
return; |
|
level = 0 //unload current level when won |
|
} |
|
if (!level || level.e) //stop updating when lost or won |
|
return; |
|
updatePlayer(level, level.keyCode || 0); |
|
updateGhosts(ghosts, level); |
|
getFirstElement('PRE').innerHTML = renderLevel(level, theme); |
|
getFirstElement('#points').innerHTML = level.p; |
|
getFirstElement('H2').innerHTML = level.e ? 'GAME OVER!' : level.p < level.c ? '' : 'YOU WIN!' |
|
}, 250); |
|
</script> |
Sorry I haven't tried but why not replace the following code in updateGhosts
by