Match the black patterns with the snake. Use the arrow keys to move and R to restart a puzzle. Can you beat the 55 levels?
b.style.width="48ch";onkeydown=d=e=>{if(!w){z=(f=l<25)?4:l<30?+"75766"[l-25]:l<43?5:6;(k=e.which%36)<5?(q=p+[,-1,-16,1,16][k],q+=!f&&n&&m(q)>1?[,z,16*z,-z,-16*z][k]:0,n=m(q)<2,s.includes(q)||(s=[p=q,...s])):(n=0,s=[p=81,80]);s.length=l<6?8:l<12?11:l<21?13:f?15:l<30?14:l<43?15:l<48?16:l<52?20:22;w=s.every(p=>!m(p))&&setTimeout`d(++l${500}w=n=0)`;for(B=i="";i<176;i++)B+=`<a style=width:3ch;height:3ch;float:left;background:#${s.includes(i)?w?161:"da6":[111,,777][m(i)]}>${i-p?(i?"":" "+(l+1)):"👀"}`};b.innerHTML=l<55?B:'<marquee><h1>🎉 YOU WON 🎉'};m=p=>(x=p%16)<(t=8-z/2|0)||x>t+z-1||(y=p>>4)<t-2||y>t+z-(f?1:3)?2:!(parseInt("19r,yn,2nn,on,sc,2yc,1aer,3ddj,34v,7pb,327,m48,1egj,ab87,4var,44cc,4v9z,5lye,cdfb,cn3c,1am6,gtjz,9tuf,4wz2,b7cj,1hrdfddq8y,g3t6b,2tc09uicht,1ibkfyb,pesw8s3,jrxo1,9jorj,j7r6m,jio5o,fv5kd,jdyrj,b2lvj,b1asx,jopxb,9luxq,d8473,jnejl,jrkbh,91tgwx,e03aae4,427yw3s,im7v7p,ofbd9ip,46nskug,p2yhnzn,ofaqrjz,1v4x23l,v7krrlr,uq3x8jj,qb2u913".split(",")[l],36)/2**(z*(y-t+2)+(x-t))&1)*(f+1);d(l=w=n=0)
Yi5zdHlsZS53aWR0aD0iNDhjaCI7b25rZXlkb3duPWQ9ZT0+e2lmKCF3KXt6PShmPWw8MjUpPzQ6bDwzMD8rIjc1NzY2IltsLTI1XTpsPDQzPzU6Njsoaz1lLndoaWNoJTM2KTw1PyhxPXArWywtMSwtMTYsMSwxNl1ba10scSs9IWYmJm4mJm0ocSk+MT9bLHosMTYqeiwteiwtMTYqel1ba106MCxuPW0ocSk8MixzLmluY2x1ZGVzKHEpfHwocz1bcD1xLC4uLnNdKSk6KG49MCxzPVtwPTgxLDgwXSk7cy5sZW5ndGg9bDw2Pzg6bDwxMj8xMTpsPDIxPzEzOmY/MTU6bDwzMD8xNDpsPDQzPzE1Omw8NDg/MTY6bDw1Mj8yMDoyMjt3PXMuZXZlcnkocD0+IW0ocCkpJiZzZXRUaW1lb3V0YGQoKytsJHs1MDB9dz1uPTApYDtmb3IoQj1pPSIiO2k8MTc2O2krKylCKz1gPGEgc3R5bGU9d2lkdGg6M2NoO2hlaWdodDozY2g7ZmxvYXQ6bGVmdDtiYWNrZ3JvdW5kOiMke3MuaW5jbHVkZXMoaSk/dz8xNjE6ImRhNiI6WzExMSwsNzc3XVttKGkpXX0+JHtpLXA/KGk/IiI6IuKAgiIrKGwrMSkpOiLwn5GAIn1gfTtiLmlubmVySFRNTD1sPDU1P0I6JzxtYXJxdWVlPjxoMT7wn46JIFlPVSBXT04g8J+OiSd9O209cD0+KHg9cCUxNik8KHQ9OC16LzJ8MCl8fHg+dCt6LTF8fCh5PXA+PjQpPHQtMnx8eT50K3otKGY/MTozKT8yOiEocGFyc2VJbnQoIjE5cix5biwybm4sb24sc2MsMnljLDFhZXIsM2RkaiwzNHYsN3BiLDMyNyxtNDgsMWVnaixhYjg3LDR2YXIsNDRjYyw0djl6LDVseWUsY2RmYixjbjNjLDFhbTYsZ3Rqeiw5dHVmLDR3ejIsYjdjaiwxaHJkZmRkcTh5LGczdDZiLDJ0YzA5dWljaHQsMWlia2Z5YixwZXN3OHMzLGpyeG8xLDlqb3JqLGo3cjZtLGppbzVvLGZ2NWtkLGpkeXJqLGIybHZqLGIxYXN4LGpvcHhiLDlsdXhxLGQ4NDczLGpuZWpsLGpya2JoLDkxdGd3eCxlMDNhYWU0LDQyN3l3M3MsaW03djdwLG9mYmQ5aXAsNDZuc2t1ZyxwMnlobnpuLG9mYXFyanosMXY0eDIzbCx2N2tycmxyLHVxM3g4amoscWIydTkxMyIuc3BsaXQoIiwiKVtsXSwzNikvMioqKHoqKHktdCsyKSsoeC10KSkmMSkqKGYrMSk7ZChsPXc9bj0wKQ==
// MiniLOSSST
// ==========
// The game is rendered on a grid of 16 x 11 squares.
// The squares are <a> elements measuring 3ch x 3ch and floating to the left.
// The size "3ch" (24px) was chosen because it is a good size to contain the emoji eyes at their default size.
// The body's width is set to 48ch, to wrap after each line of 16 squares.
b.style.width = "48ch";
// The game contains 25 "nowrap" puzzles and 30 "wrap" puzzles, counted with the variable l.
// The snake is represented by s, an array of cell indexes, where a new value is inserted at the beginning after each move.
// The function d is called on load and at every keydown event. It updates and redraws the scene.
onkeydown = d = e => {
// Don't move the snake during the win animation (when w == 1).
if(!w){
// f: type of puzzle (nowrap: 1 / wrap = 0).
f = l < 25
// z: puzzle size (nowrap: 4 / wrap: 7, 5, 7, 6, 6, 5 (13 times) and 6 (12 times).
z = f ? 4 : l < 30 ? +"75766"[l - 25] : l < 43 ? 5 : 6
// k: e.keyCode (a.k.a. e.which) modulo 36.
k = e.which % 36
// DEBUG MODE (NOT PRESENT IN THE JS1K ENTRY)
// Press shift (k = 16) to skip a level.
// Also, reset the win flag (w) and the inbounds flag (n) to 0.
// Note: the value passed to d is 0.
k == 16 && d(++l, w = n = 0)
// END DEBUG MODE
// If k < 5, it means that the left (k == 1), top (k == 2), right (k == 3) or bottom (k == 4) key is pressed.
// Special case: if k == 0, it means that we just passed to the next level, so nothing happens.
k < 5 ?
(
// q: target cell (-1: left / -16: top / 1: right / 16: bottom).
// The offsets array has no value at index 0 to avoid moving when d(0) is called.
q = p + [, -1, -16, 1, 16][k],
// Apply wrap for puzzles > 24 (f == 0) if the snake head is inbounds (n == 1) and the target is an exterior cell (m(q) == 2):
// k == 1: add z to q to wrap from left to right.
// k == 2: add 16 * z to q to wrap from top to bottom.
// k == 3: add -z to q to wrap from right to left.
// k == 4: add -16 * z to q to wrap from bottom to top.
// Here again, the offsets array has no value at index 0 to avoid moving when d(0) is called.
q += !f && n && m(q) > 1 ? [, z, 16 * z, -z, -16 * z][k] : 0,
// Set inbounds flag (n) to true if the target cell (m(q)) is 0 or 1.
n = m(q) < 2,
// Move snake:
// - if s (the array representing the snake) contains q, it's a collision and nothing happens.
// - if s doesn't contain q, the new head position (q) is appended at the beginning of s and saved in p. #ES6!
s.includes(q) || (s = [p = q, ...s])
)
// Else, it means that any other key was pressed
:
// Reset current level: reset inbounds flag (n) to 0 and snake positions (s) to cells 81 and 80.
// also, save head position (p = 81).
(n = 0, s = [p = 81, 80])
// Truncate the snake at its max size (nowrap: 8 / 11 / 13 / 15, wrap: 14 / 15 / 16 / 20 / 22).
// Setting an array's length to a value less than its length is enough to truncate it.
s.length = l < 6 ? 8 : l < 12 ? 11 : l < 21 ? 13 : f ? 15 : l < 30 ? 14 : l < 43 ? 15 : l < 48 ? 16 : l < 52 ? 20 : 22
// w: true if all the parts (p) of the snake (s) are on a black cell (m(p) == 0). #ES6!
w = s.every(p => !m(p)) &&
// If the puzzle is solved, wait 500ms to increase level (l), reset win (w) and inbounds (n) flags, and draw the next puzzle.
// This code is equivalent to : `setTimeout("d(++l, w = n = 0)", 500)`.
setTimeout`d(++l ${500} w = n = 0)`
// Draw the scene
// Reset the string B containing the body's innerHTML, and i (the cell counter),
// Ihen loop on all the cells of the scene.
// Note: i can be initialized to an empty string (like B): it will coerce to 0 when the loop continues.
for(B = i = ""; i < 176; i++){
// Update B with a new <a> element. This element measures 3ch x 3ch, floats left, and has a background set to:
// #161 (green) if the cell belongs to the snake (s.includes(i)) and the puzzle is won (w == 1).
// #DA6 (tan) if the cell belongs to the snake and the puzzle is not won yet (w == 0).
// #111 (black) if the cell belongs to the pattern of the puzzle. (m(i) == 1).
// #777 (light gray) if the cell belongs to the exterior of the pattern (m(i) == 0).
// #0 if the cell belongs to the wrap area around the pattern (m(i) == 2), on puzzles > 25.
// Trick: #0 is an invalid value for a CSS background, so the cell stays white.
B +=
`<a style=width:3ch;height:3ch;float:left;background:#${
s.includes(i) ? w ? 161 : "da6" : [111, , 777][m(i)]
}>${
// Set the content of the element.
// If the cell isn't the snake's head (i - p > 0):
// - A small space + the level number (l) on the top-left corner (i == 0).
// -Nothing on the other cells (i > 0).
// Or some emoji eyes is the cell is the snake's head. (i - p == 0, so i == p).
i - p
? (i ? "" : " " + (l + 1))
: "👀"
}`
// Fill the body with the generated HTML if the level is between 0 and 55, or a congratulation message at the end.
b.innerHTML = l < 55 ? B : '<marquee><h1>🎉 YOU WON! 🎉'
}
}
};
// The function m returns the color of the cell p passed in parameter.
// 0: black pattern / 1: wrap area / 2: exterior.
m = p => {
// Compute cell coordinates (x, y) based on p.
x = p % 16
y = p >> 4 // p >> 4 == Math.floor(p / 16).
// t: distance from the center of the scene (we use it to keep the puzzle centered).
t = 8 - z / 2 | 0
return
// Test if the cell is inside the centered puzzle.
x < t || x > t + z - 1 || y < t - 2 || y > t + z - (f ? 1 : 3)
// Return 2 if the cell is outside.
? 2
:
// Each part of this string represents a level encoded in base36.
!(
parseInt(
'19r,\
yn,\
2nn,\
on,\
sc,\
2yc,\
1aer,\
3ddj,\
34v,\
7pb,\
327,\
m48,\
1egj,\
ab87,\
4var,\
44cc,\
4v9z,\
5lye,\
cdfb,\
cn3c,\
1am6,\
gtjz,\
9tuf,\
4wz2,\
b7cj,\
1hrdfddq8y,\
g3t6b,\
2tc09uicht,\
1ibkfyb,\
pesw8s3,\
16nz5,\
9jorj,\
j7r6m,\
jio5o,\
fv5kd,\
jokrj,\
jdyrj,\
b2lvj,\
b1asx,\
jopxb,\
9luxq,\
d8473,\
jnejl,\
jrkbh,\
e03aae4,\
427yw3s,\
im7v7p,\
ofbd9ip,\
46nskug,\
p2yhnzn,\
ofaqrjz,\
1v4x23l,\
v7krrlr,\
uq3x8jj'
.split(",")[l],
36
)
// The current level is converted in base 10, then each bit of its base2 value is extracted using the following computation.
// Considering N is the number where the puzzle is encoded, and X & Y the coordinates inside the puzzle,
// extracting the bit Y * Z + X of the number N is equivalent to: N / ( 2 ** (z * Y + X) & 1 ).
/ 2 ** (z * (y - t + 2) + (x - t)) & 1
// We multiply this bit by 2 for levels < 25 and 1 for levels > 25,
// so the non-pattern cells in the puzzles can look different on nowrap puzzles (m(p) == 1) and wrap puzzles (m(p) == 2).
) * (f + 1)
}
// Reset win flag (w), level number (l) and inbounds flag (n) to 0 and start the game.
d(w = l = n = 0)
//Made with <3 by The Codegolf Team