Source code first, version is ES6
13 lines regular (700bytes) |
|
Compressed 500bytes (of course, two document s can be compressed with eval) |
|
Previous hot 20 line code address (with BUG)(900bytes) |
One dimensional array 700char
The snake body at (0,0) position is represented by 0, (0,1) by 1, (1,0) by 10, and so on
Because just 13 lines of js,
Line 4 is the declaration
Line 5 is difficult to understand. You can split the?: operator into four if lines. Please refer to the following version of 2D array
Line 9: 0|x and ~ ~ x and x > > 0 can remove the mantissa of x(number)
It should be easy to read
<!DOCTYPE html> <canvas id="1" width="400" height="400"></canvas> <script> let dir=1,food=3,snk=[1,0],ctx=document.getElementById("1").getContext("2d") document.onkeydown=e=>{dir = snk[0]-snk[1]==-(tmp = [-1,-10,1,10][e.keyCode-37]||dir)?dir:tmp} setInterval(()=>{ snk.unshift(Head = snk[0] + dir) if(Head!=food) snk.pop() else while(snk.includes(food=0|Math.random()*10*10)) ; if(snk.indexOf(Head,1)!=-1||(dir==1&&Head%10==0)||(dir==-1&&Head%10==9)||Head<0||Head>=100) return document.write(0&snk.shift()) //Death record snake length for(let i=0; i<100; i++){ ctx.fillStyle = '#0'+(food==i)*9910+snk.includes(i)*1990 ctx.fillRect(i%10*40,(i-i%10)*4, 40,40) } },100) </script>
Color effect
<!DOCTYPE html> <canvas id="1" width="400" height="400"></canvas> <script> let dir=1,food=3,snk=[1,0],n_=0, ctx=document.getElementById("1").getContext("2d") document.onkeydown=e=>{ dir =snk[0]-snk[1]==-(tmp = [-1,-10,1,10][e.keyCode-37]||dir)?dir:tmp} setInterval(()=>{ snk.unshift(Head = snk[0] + dir) if(Head!=food) snk.pop() else while(snk.includes(food=0|Math.random()*10*10)) ; if(snk.indexOf(Head,1)!=-1||(dir==1&&Head%10==0)||(dir==-1&&Head%10==9)||Head<0||Head>=100) return alert("died"+ ++n_+"times") //Number of deaths recorded for(let i=0 ; i<100; i++){ ctx.fillStyle = '#0'+~~((food===i)*13000*Math.random())+~~(snk.includes(i)*3000*Math.random()) ctx.fillRect(i%10*40,(i-i%10)*4, 40,40) } },120) </script>
Explain
If you want to write by yourself: pay attention to two points
- The snake's tail should disappear before the snake's head. The snake's head should be more mature than the food man,
-
Snakes can't go in the opposite direction
It can be tested with a snake of length 4
Code style
-
Eliminate unnecessary labels
https://google.github.io/styleguide/htmlcssguide.html#Optional_Tags
-
if() return uses only one line
-
Except for the keyboard response where three lines can be saved by using the three item operator, there is no need to use
Two-dimensional array
All of the above are implemented with one-dimensional arrays, and the following are written with two-dimensional arrays. To simplify, you can also simplify it to within 17 lines and within 900 chars (shorter than that of 20 lines), but it is unnecessary
1100char with notes
<!DOCTYPE html> <canvas id="1" width="400" height="400" style="border: 1px solid "></canvas> <script> ctx = document.getElementById("1").getContext("2d") //CanvasRenderingContext2D inferface let Len = 10, dir = 2, dirNow ; //Explain after dirNow food = [3, 0]; Snake = [[0, 0], [1, 0]] //The coordinates of food and Snake are recorded by Snake array Map = {'0,0':'#52a', '1,0':'#52a '} / / map used to record drawing colors dirMat = [[-1, 0], [0, -1], [1, 0], [0, 1]] //Directional matrix pairEq = ((p1, p2) => p1[0] == p2[0] && p1[1] == p2[1]) //A function that detects whether two pairs of numbers are equal document.onkeydown = e =>{ if (37 <= e.keyCode == e.keyCode < 41 && dirNow != ( (e.keyCode - 35) % 4) ) //Confirm that it is the direction key and ensure that the direction is opposite to the current movement direction dir = e.keyCode -37 } !function () { Head = Snake[Snake.length-1].map((x, i) => x + dirMat[dirNow=dir][i]); //Get the next movement of the head if (!pairEq(Head, food)) Map[Snake.shift()]='#fff '/ / the tail must be removed before the head can be added. Eating or not eating food is the only criterion if (Snake.some(x=>pairEq(x,Head)) || !Head.every(x => 0<=x == x < Len)) //Determine if the head of the snake hits the body or the wall return document.write("Game Over") //In this way, calling document.write will empty all pages Snake.push(Head); //Can be added to the head while (Snake.some(x => pairEq(x, food))) //It is more convenient to produce food after adding new head food = [~~(Math.random() * Len), ~~(Math.random() * Len)]; //Because js has no concept of shaping, ~ ~ now it is equivalent to rounding off to the origin Map[Head] = '#52a' ; Map[food] = '#ad5' for( k in Map){ ctx.fillStyle= Map[k] ctx.fillRect(parseInt(k[0])*40,parseInt(k[2])*40,40,40) //e.g. k="1,3", so the map size is limited to 10 } setTimeout(arguments.callee, 100); //This function is called once after 100ms. }() </script>
Colorful (mainly pretty) 1100char
<!DOCTYPE html>
<canvas id="1" width="400" height="400" style="border: 1px solid " ></canvas>
<script>
ctx = document.getElementById("1").getContext("2d")
let Len = 10, dir = 2, dirNow ;
food = [3, 0]; Snake = [[0, 0], [1, 0]]
Map = {'0,0':'fff', '1,0':'fff'}
dirMat = [[-1, 0], [0, -1], [1, 0], [0, 1]]
pairEq = ((p1, p2) => p1[0] == p2[0] && p1[1] == p2[1])
document.onkeydown = e =>{
if (37 <= e.keyCode == e.keyCode < 41 && dirNow != ( (e.keyCode - 35) % 4) )
dir = e.keyCode -37
}
!function () {
Head = Snake[Snake.length-1].map((x, i) => x + dirMat[dirNow=dir][i]);
if (!pairEq(Head, food)) Map[Snake.shift()]='0'
if (Snake.some(x=>pairEq(x,Head)) || !Head.every(x => 0<=x == x < Len))
return document.write("Game Over")
Snake.push(Head);
while (Snake.some(x => pairEq(x, food)))
food = [~~(Math.random() * Len), ~~(Math.random() * Len)];
Map[Head] = Map[food] = 'fff'
for( k in Map){
ctx.fillStyle='#'+(0xfff-~~(parseInt(Map[k],16)*Math.random())).toString(16)
ctx.fillRect(parseInt(k[0])*40,parseInt(k[2])*40,46,43)
}
setTimeout(arguments.callee, 100);
}()
</script>