[ ^ ][ ^ ]
login

なにそれ

[ SINGLE POST ]

SNE1K commented

Some time ago I made a snake game as small as possible (code golfing) I ended up with [this](https://static.nani-so.re/showcase/snake) Here is the commented version of my code ```js <pre style="letter-spacing:8"id="A"> <!-- pre element can be minimized by removing spaces, removing the closing part (the browser will close it for us) The double quotes around the id can also be removed --> <script> Y=200;P='o';J=' ';N=15;C='#';E='+';m=[]; //Y being the initial interval time of the game (200ms) //P is the default player character for the snake //J is the default empty map character //N is the inner map width and height //C is the map border character //E is the bonus character //m is an empty array that will later contain the map X=C.repeat(N+2);for(T in X)m[T]=C+J.repeat(N)+C;m[0]=m[0].slice(0,-2)+E+C;m.unshift(X);m.push(X); //X=C.repeat(N+2); put in the variable 'X' the caracter from the variable 'C' N+2 times //The X variable will be '#################' (15+2) //for(T in X)m[T]=C+J.repeat(N)+C; //a loop that will executes 17 times (length of the X variable) and append the m array with sub array containing the variable C (#) + the variable J ( ) N times (15) + the variable C (#) again //m[0] to m[16] will contain '# #' //m[0]=m[0].slice(0,-2)+E+C; //this part will add a bonus at the end of the first item from the array by removing the last two characters and adding back the E variable (+) and the C variable (#) //'# #' will become '# +#' this //m.unshift(X);m.push(X); //this part adds X (#################) at the begining of the array, shifting all other indexes by 1, and adding X again to the end of the array //The final m is //[ //['#################'], //['# +#'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['# #'], //['#################'], //] function s(a,b,c){return a.substring(0,b)+c+a.substring(b+1)} //function allowing to replace one character 'b' for a character 'c' in a string 'a' function f(){e=setInterval(function w(){ //function f setting an interval stored in the e variable containing the w function if(!z){R=p.length-1; //if not z (z being the variable telling the game if the player is dead or not) //p is an array containing all of the player positions as sub arrays (updating each inteval) //R is the number of player moves if(h=p[R][0],j=p[R][1],h=1==d?h-1:h,h=-1==d?h+1:h,j=2==d?j-1:j,j=-2==d?j+1:j,p.push([h,j]),g=p.length-1,l=m[h][j],r){ //set all variables in if //h=p[R][0] //j=p[R][1] //h and j are variables containing the last x and y player move //h=1==d?h-1:h,h=-1==d?h+1:h,j=2==d?j-1:j,j=-2==d?j+1:j //check where the player moved depending of the d (direction) variable and updates h and j with the new values //p.push([h,j]) //push the new x and y coordonates calculated above //g=p.length-1 //update g with the new player moves length //l=m[h][j],r //put the new player position map character in the variable l (to check later if the player stepped on a bonus, on a wall or on himself) //finaly check if is true (==1) (r being the "ready" variable telling that the game started) if(J!=l) //if the player is not on an empty character if(E==l){ //if player touches a bonus x=y=0; //intialize the x and y variables at 0 for(t++,k=1;J!=m[x][y];) //for(t++,k=1,m[h]=m[h].replace(E,J);J!=m[x][y];) //t++ will grow the snake tail by one //k=1 means the tail just grown, will be useful later //J!=m[x][y]; the last bit is just a while loop saying if m[x][y] doesn't match an empty space (J) then repeat the loop repeat itself (generating new x and y values until it finds a free space to put the new bonus) with(Math) //with(Math) will be useful to call random() without having to write Math.random() each time x=~~(random()*N+2),y=~~(random()*N+2); //put a random number within the map width and height m[x]=s(m[x],y,E);Y-=5 //replace the empty space of the map chunk affected (m[x]) by the bonus character (using the s function) //lower the interval time by 5ms } else //else means the character where the player is, isn't a bonus or an empty character, mean the player hit himself or a wall z=1,P='x'; //z=1 means game over //P='x'; changes the player character to x (so the player knows the snake is dead) !k&&t<g&&(b=p[g-t],m[b[0]]=s(m[b[0]],b[1],J)),k=0 //0==k if tail isn't growing //&&t<g and tail size is inferior to player position array (means the player moved more time than the tail length) //(b=p[g-t] //set the b variable being the last player position after the tail length //m[b[0]]=s(m[b[0]],b[1],J) //replace the matching map positions to an empty character (it will clean after the snake, if we didn't do that, the snake would have an infinite tail) //sets the k variable to 0 (to reset it if the tail was growing) //if the tail was growing the last tail element wouldn't have been cleaned which would have make it grow by one } for(a='',i=0;i<t;i++)i<g+1&&(b=p[g-i],m[b[0]]=s(m[b[0]],b[1],P)); for(b in m) { for(K in m[b]) H=m[b][K], a+=H.fontcolor(/\#/.test(H)&&"#03B"||/\w/.test(H)&&"#2B2"); a+="\n" } A.innerHTML=a } return w}(),Y)} //the w function returns itself, this allows to immediatly start the game on the first call instead of having to wait for the first interval to complete //Y is the interval time variable in ms (200 by default) t=3,p=[[1,1]];var i,z,r,k,d;f(), //t is the variable containing the intial snake tail length (3) //p=[[1,1]] is the inital player position //var i,z,r,k,d;f(), variable initialisation and lauching the f() function once window.addEventListener("keydown",function(k){ //event listener on keydown if(c=k.keyCode,-1!=[37,38,39,40].indexOf(c)) //storing keycode on the c variable //if -1!=[37,38,39,40].indexOf(c) checking of the c variable is either 37, 38, 39 or 40 (up down left right arrows on keyboard) with(Math)D=1==abs(39-c)?39-c:2*(38-c),z||abs(D)!=abs(d)&&(d=D,clearInterval(e),f(),r=1)}); //with(Math) allows to call abs without having to write down Math.abs each time //D=1==abs(39-c)?39-c:2*(38-c),z||abs(D)!=abs(d)&&(d=D,clearInterval(e),f(),r=1)}); //short way to write: // D=(abs(39-c)==1)?39-c:(38-c)*2; // if(!z){ // if(abs(D)!=abs(d)) { // d=D; // clearInterval(e); // f(); // r=1; // } // } //which follow the rules: //0 not moving //1 = up //-2 = right //-1 = down //2 = left //it basically checks if the direction is the same or if the direction is on the same axis, if so do nothing, else update direction //both the same direction and the same axis check are performed at the same time, since up / down are 1 and -1 and left / right are 2 and -2 I used Math.abs to obtain only positive numbers, it only has to check if abs(old_direction)!=abs(new_direction) are different to know if they aren't the same twice or on the same axis //if the direction is updated, the interval is cleared to take the new direction immediatly instead of waiting for the next interval to allow for smooth controls //it also puts the r variable at 1, the r variable tells if the game started or not (the first keypress on arrows will start the game) ``` if you wanna get into code golfing I recommend looking up some old examples of demo ([demoscene](https://en.wikipedia.org/wiki/Demoscene)), competitions (such as [js1k](https://js1k.com/)) as well as checking shorthand tricks for your language of choice. finally fantasy consoles (like [pico8](https://www.lexaloffle.com/pico-8.php)) have some very good examples too I have some resources about it [here](https://static.nani-so.re/links#code_golfing) Peace