Let’s write a Snake game in plain JavaScript

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
okay see this works and i'm going to turn on the stream on my phone so that i can see the chat [Music] second read it okay i can see the chat now so i'm just gonna put this separately so that i see what you're all saying but basically the plan is so i want to write a um like a snake game so uh to give you a concrete example um the version that i remember was the one so this was my first phone nokia 32 10. and the way this lane game looked there was this was the version before the popular one because the most popular one was nuka 3310 and so it had kind of like a fancy snake but the the version on uh 3210 is a bit simpler which is nice because it's easier to implement it's just like a very blocky snake uh that yeah that just looks like a bunch of blocks so that is uh that is the version that i want to actually um actually implement and i've done this before i think one time but i didn't fully finish it and also it was like maybe three years ago so i don't actually remember how to do it so that's yeah that's that's what i'm gonna do uh actually let me let me just post oh i guess you can see yeah you can see from the description what i'm doing okay so i'm not planning to i don't plan to like use react or anything i'll just stick the kind of vanilla javascript um so what i'm going to do is i'm going to create like a like a an html file and i'm going to put it in the browser and this is true okay okay that's that starts thinking let me verify that you can actually see it yeah seems fine so let's just verify yeah okay it works fine um so i think i'll just write it kind of inline well i guess i don't know if the highlighting is going to be good so um yeah let me create another file um and add this to the page and just verify yeah it works so let me resize this a little bit okay so i think the way uh the way i'll try to do this is there's like multiple parts to this right so i need to um just to get it showing the kind of the game canvas and then i need to figure out how to draw something on it um like a static version of the snake then i need to figure out how to make it move and respond to input and i'm gonna need to figure out how to um make it update its position i guess and like uh have the boot spawn in the right places and actually uh like have the snake grow when it crosses uh the food and also make it end the game if i crash into the border um is it true that the alert will get deprecated well i hope not i don't know uh but we will see i guess so the first thing i think i'll try to do is just make it show up like some kind of a canvas that we we can work with so actually i'll just make a div here and i'm not literally going to use the canvas element because i don't know how to how to use it so i think i'm going to kind of approximate that with a um with just a bunch of divs and maybe later i'll i'll make like an actual canvas if i if i learned how to do this but i'm getting i'm gonna call this canvas because conceptually it is a canvas i'm gonna give it some styles maybe um sorry this is really uh this might look like a very weird html file without the body or anything um so this thing let's give it um i don't know 500 uh okay that might be yeah yeah that actually looks pretty reasonable um um so why a snake game well i just like this game it was my favorite game when i when i like when i had my first phone i would play it all the time um really go for some kind of collision detection well i mean i do have to detect when it bumps into the wall but that that's and when it bumps into itself but that's about the extent of it so it's not really collision detection i have a react related question can ask here no not really this this is not a react q a so um we have a thing rebuilt in here which is a snake game so i think the first thing that i want to do is just the to have some way to paint on this on this div so the snake itself is kind of blocky right like it's composed of pixels so it would be nice to to be able to do something like general snake and gonna pass some coordinates um and have it appear there so for example like so it would be cool if something like this would give me like a snake that is drawn here just so i can like kind of work with it so i think that's i think that's the first thing i'll do um so for this to work the way i'm imagining it now is uh because i don't i don't use an actual canvas i'm just gonna use diff i need basically a div for every pixel so i need to make a grid and then i will toggle the background color of each individual pixel and that's how i will be drawing the snake so for this to work i actually need to initialize the canvas so what i'm going to do is actually i'll remove this for now so so i'll do something like this and i'll call it immediately so let's get the canvas itself and that's going to be the thing we're going to be working with and the first thing i want to do is i want to create um create the grid um so there's it's going to do choices here i think it makes sense to make it so the cr each item in the grid has to be like a rectangle um one way to do it would be to use the browser layout and just put like all the pixels as one big row another approach is to actually divide it into like rows and columns and the third approach is just to give them absolute position which i think is the simplest so i think i'm gonna give this position relative and then and then i'm gonna make a bunch of pixels with absolute positions so um so let's create uh let's i guess let's have a loop um um i know something like this and each will be 10 10 pixels so blend up by 300 by 500. um yeah so i'm just gonna make a div and um why oh there's a bunch of questions yeah yeah i don't think it makes sense to use react i well i guess like oh hi sophie uh i was thinking that like i might do this in react but then i realized like what what is kind of the point like it it would be very similar to a plain js solution so might as well do it in plain js maybe i can add the react later just for fun but um yeah uh back to sublime text yeah i mean i i tried code i just i couldn't stick with it also this is a new computer so i don't have anything set up so just download it sublime sublime is great so what i'm gonna do is i'm gonna give this pixel some styling so i'm gonna give it position absolute let's so one thing i'm not sure about uh okay i want to give it some borders just so i can see it but i'm not sure okay i just want to look this up because i i don't actually understand what this does i know there's a thing called border box and i'm curious if that's gonna push that into because uh want to give it well the height yeah okay that that is actually what i want so this is what i want for the pixels uh i think this was other box uh yeah i'm gonna i think i've seen people do this so maybe i'm wrong but anyway this this lets me do this so i will give them one pixel solid red just so i can see them and make sure that my my layout actually makes sense and the left is going to be um so the left is going to be row rows well no it's going to be the well the current column times pixel um i don't remember if you have to append the bx i think you do and then the top is going to be this and then let's edit the canvas and let's see no it didn't work oops um why didn't it work though not read property so no uh so this is not a thing so did i did i call it something different oh okay so it actually gets too early so let's execute it here yeah okay that's actually not what i expected why does it look so weird this is not oh i forgot to give it the size i guess so um yeah cool awesome i have a yeah but it's not see the layout doesn't work and i think that's because for well this because for this thing and do you want the is it is that how you do it yeah yeah i think this makes sense okay i have a grid um so i have a grid and then i want to i've initialized the canvas and then i want to have like a function that actually draws the snake so let's let's implement that so i think well so this may not be the most efficient way to do it but it's fine so what i'm gonna do is every time i draw the snake i will just go over the entire grid and i will set the pixel based on if snake is well yeah so there are some questions about like which data structure to use um i'm not actually sure um like i could iterate over all pixels and decide whether to draw each separate one based on whether the snake has this coordinate set i can do it the other way around like iterating over the snake itself as and set in pixels um like the important part is like if i call this and then i call it with some like other coordinates right like for example if it moves i might want to call it with this like it's important that this pixel gets cleared um and i think for now i will go with kind of a brute force approach so i will think about this later but for now um what i'll do is just to get something on the screen i will have a like an algorithm with with pretty bad complexity so i'll have like some nested loops and stuff but what i want to do is i want to go over all the rows and i want to go over all the columns and for each of those i guess i need the i need to reference the pixel like i need to have like a quick way to get the corresponding pixel so maybe i could put the pixels themselves in a um some kind of some kind of a map so i can grab them later um but the map needs some kind of a key and i need both i and j i think what i could do is um so let's let's have pixels that would be a map and let's have a concept of a position so this would be this would be a string not because it has to be a string but it has to be something that i can later look for it in the map so it shouldn't depend on like specific object or something like this like i think it makes sense to have like i uh underscore j for example as the as the position and then uh wait no this doesn't make sense what did i do yeah and then and then we we put the pixel the corresponding pixel under this position and then later what i'll do is when i draw it i again copy and paste this um so for for this position what i'm gonna do is grab the corresponding pixel and um yeah and i'm gonna color it either um so this this red is getting actually pretty ugly i change this to like something subtle so i'm gonna color this yeah i'm gonna color this depending if the snake has the corresponding um position here so let's let's actually kind of pre-process this a little bit so maybe like a daily this would be a set that i could quickly match against so snake positions so what i'm gonna do is well i guess i could just let x and y off snake again take the position of that and and add it to the set and now we can now we have a set of snake positions and we can quickly check uh so pixel back pixel style background equals uh so if snake positions so if the snake is there then we want to color it black otherwise we want to color it white yay we got it working so here's um yeah here's the uh the snake and what's uh but we don't we don't actually know that this works yet because the thing that we kind of care about here is that it should um like the thing that i expect is that if i called draw snake repeatedly but like another position that it would actually clear the other pixels so let's let me just try to kind of add some kind of a loop here so what i'm going to do is so the match actually make this is the this is where the snake currently is and then uh yeah and i'll have like um hmm so i'll have a function that i'm just calling draw that is gonna draw the current snake i don't know this makes sense and i'll have a function um called step that is going to to kind of do whatever should happen every time you know the timer ticks depending on like how fast the game is going so when we we take a step we update the position and we draw and then updating the position um this is overly abstracted this is annoying i'll just i'll i'll just do it here so um so what i want to do here is um i move the snake i want the so i have the tail which is i guess the first item so i want to pop that but i think the re i think it's it's like shift that will pop it from the beginning and then i want to take its head which is the last item uh yeah and i'm actually gonna so the snake is supposed to move right so like it's i'm supposed to give it a new head that will be one pixel forward so uh i will do something like current snake dot push and so and the next head so for now let's say it always moves to the right so the the new uh horizontal coordinate is the same so it's the first item in the array and then the near the like the the row is the same and then the column is the thing that that that is plus one until it runs into a wall but we'll we'll see about how that goes so it draws the snake and then uh yeah and then let's uh so let's make sure that you know it's able to well i still need to i still need to draw the initial state so that is uh yeah so i do need this call in the beginning uh so let's again sure yeah this works and then i'll do a set interval and i'm going to step every 100 milliseconds wait this doesn't work uh yeah i cannot find pixel i guess why why would that be though because i thought i had it right let's let's see why that happens excel position 050 pixels so yeah like what is what's your problem mate uh oh wait it ran out of bounds uh oh okay my loops are mixed up yeah that's what i get for using the for loop okay no this is not this is not doing what i want this is not doing that at all see uh okay let's see maybe maybe some of you have spotted some mistakes yeah i've already fixed this one uh line 16 needs had one yeah really oh yes you're right that is the mistake okay yay okay it's gonna never to be seen again um but yeah that is uh that is already pretty cool i think the so we have a few things that we could do next uh like i guess it would be nice to get it actually respond to input another thing we could do is get it to kind of crash but i think respecting the input makes more sense as the next stage so what i want to do is uh when i when i press like keyboard buttons um like up down left and right i want to um i wanted to respond to my movement so uh what i'll do is um so let's have a listen so there's like a concept of the current direction right which is um which is like left like starts as starts as bright and then we need to we need to calculate this based on the on the direction i guess another way we could express the direction a is as a function it might be kind of neither let's let's maybe do this so um um wait it's not x did that exactly why i think it's how am i doing this yeah i guess i'm not calling them these are not excellent why this is more like top and left uh yeah did i pull them yeah let's say this is top this is left i'll just call it dnl so top is the same left plus one and then move left the same but the minus one then move top is this and then the bottom is this i don't know if this will actually keep making sense maybe i'll i'll get rid of this just seems kind of good to use functions for this and then the current direction is right and then um yeah and the way you apply current direction is just gonna have like the next fad is current direction applied to the head and that would be let's see if this actually works okay so if i change this to move bottom i wonder what happens no it doesn't work um well because we haven't implemented turns right so it doesn't i guess this is actually not enough uh what doesn't know i would expect it to work that doesn't work so oh top yeah it should go this should go like this yeah okay that's that actually makes sense so i can i can make it move in different directions let's see um let me see the comments what about when they change directions quickly so the body has multiple directions yeah i think rupert answered correctly that it doesn't matter because the thing that we're adjusting is like it seems like it's changing directions but really the only thing that's changing is which where do we add kind of new items to it so and that is why you can like turn multiple times because it's really the the next thing that's going to be added that is affected by the keyboard so let's let's hook it up to the keyboard so that it actually listens to us um so i don't i don't actually remember how to do it but i think we need to do something like window.that event listener i don't know uh key down versus key press it should be key up actually well no i think it's important like when you hit the button that um because yeah uh okay key down is fired for all of them um hmm oh okay this is actually nice okay i went that key key down cool this is what i wanted um so what's interesting is that we like when we press the key we don't actually want to move the snake we only want to change the direction because uh it's well well we'll talk about this later but let's see if this this works no no it doesn't work uh wait no this worked but i don't think it goes up and down the thing is i'm actually not sure because i'm i'm using this keyboard uh hkb which is like fine but it it doesn't have arrow keys so it's kind of um like i have to press a special combo to do them and i think i'm pressing correctly now but it's actually really uh really tricky to to get used to so but no these are definitely up and down and here if i press up nothing happens okay move down is not defined uh oh because i call them move top and bottom um the bottom down um okay now as a direction i guess it makes sense yeah let's rename that okay wow this is actually cool um okay so so there there's actually like some subtle aspects that well okay so the first thing that's definitely wrong is i shouldn't be able to go in the reverse to the current direction like this doesn't make any sense so i think i think on nokia's is the ones i played it would just straight up ignore if you try to do this so i think that's that's what i'm going to do as well so um i don't i don't like double quotes so if oh wait and this is way too indented so if so if you're not moving right only then can we move left if we're not moving left only then can we move right if we're not moving down only then when can we move up and if we're not moving up and then can we move down okay yeah so now it ignores if i try to reverse course no wait i'm still able to sometimes so okay so one thing that is that is definitely different and not correct compared to how it worked on the old phones is that it used to be possible to um like i should i should be able to make quick turns so i should be able to press down left in very quick succession like down left and then it should do both because that's the only way like when the snake is getting really really long like this the only way to maneuver is like you should be able to have like chin and then it should make both of these things as if it has skewed the updates so i think it's not just um i think it's not because like currently in this implementation is the latest the the latest one wins but i think that's actually not correct and i think it should try to queue them up somehow let me see let me see what's in the comments can you show the start of the code yeah sure i mean it's you can just scrub back to the to the beginning of the stream but the beginning of the code is just yeah i just initialize the canvas set all the pixels and there's a function that draws the actual snake then the the current snake coordinates the movements and changing the direction and then the step um sophie's saying that's not quite right i think you want to compare against the previous direction i see yeah i think that is the mistake because i i was definitely able to like if i'm if i if that's what was bugging me like if i if i move fast enough like i am able to reverse it and i should not be able to and sophie pointed out why why this happens is because we're like uh we're able to move left um so for example if i'm moving to the right and then i press down then it updates the current direction to to be uh to be down but then if before it paints i issue left then this check is like this check works out right because it's uh well it's it's already been updated so it thinks it's okay to go left but it's actually not okay because i haven't made a step in between which means that the direction we really want to be comparing to is the kind of the last the last flushed direction so the last one that was successful so i think maybe i'll i'll do that um there's probably a better way to do it and again i want to implement this ability to press multiple keys because i'm pretty sure that worked on nokia so i think that is that is going to be essential but i just want to fix the bug for now so what i'll do is uh i'll have something called washed direct maybe not the best name uh but essentially um the the direction i want to use in the comparisons is the one that is actually on currently like the last one that was used during an actual step so so i think i want to update it here let's see if that if that so helps can still i can still operate it with yeah so now i can now i can't make it go in reverse so i think that that fixed the the bug um i think i should just implement uh wasd as well because i just can't i just can't reliably use arrow keys on this keyboard it's it's kind of wild so uh uh what was this thing that let me just oh okay i'll just okay there is probably a better way to do it but i'll just do it like this wait w is top right so this is going to be a this is going to be d and this is going to be as okay yeah so the thing that i'm noticing now i mean obviously you don't see it because you're you're not looking at my fingers but it is definitely like i want to be i want to do movements like this and they just don't always work so if i do them fast enough they don't work and the reason for this is because it overwrites the um is because well if i if i do two uh if i update the direction twice very fast it only takes care the the last update but then on the other hand i just wish there was just wish i had it and i'll knock you to actually test what happens um like what is the if i make five key process very fast obviously it's not going to replay them all that doesn't make sense so i think maybe it used to work like i have here just felt a bit different like i remember making those combinations like really really fast and they would not get lost even between a single dick maybe it only worked for maybe only kept like two the last two why didn't you go for request animation frame instead of set intel well i mean it doesn't really matter in this case because i don't have i i i could do it but i don't have something to do at 60 frames per second like i'm actually artificially being slower than that yeah i think what i'll do is i want to make a bit of a checkpoint because i i might want to change some things later so i'll actually but okay uh actually remove this the folder what what wait the ice socket terminal uh okay what the f yeah awesome uh so i'm i'm going to reload this and i'll make a commit because i think i'm in a good place now and i don't want to lose my progress if i decide to change how it works so i will do this uh yeah i mean whatever sure but yeah i don't care um okay okay this is committed maybe let's uh maybe for now let's implement the more i just can't decide if i should fix it or not also i think my mouse just stopped my mouse just stopped responding to scrolls that is funny what the hell oh whatever seriously just my mouse doesn't work okay my mouse works again um yeah i think i i don't really like that i think i'm gonna change how this works so the thing i'm going to do is i'm going to make cue of the key movements and i'll try to make it so that it takes one item from the key every time that it takes like the first item on the queue so if you if you press multiple things very fast it still makes sense together sort of i wish there was just a way to play it so i could verify what nokia does but i will make it so that if you press for example like down right down right very fast i will make it so that on each like on each tick it will take the the next command that was queued and if it is valid then it's going to apply it and i think that will match more closer to how i remember that it works so in that world there is no current direction at all i think so oh sophie is saying something are using the mouse if it's disconnected well i was using trackpad um yeah i don't think i should step immediately because the way i remember the game it did not do that because especially if you're um if you're on a kind of slower level right so if it if it moves slower uh for example if it's like 500 which is the kind of the level that you start with i'm pretty sure you couldn't force it to go faster just by pressing the buttons but i think you might you might have been able to cue them so i i think i'll go with the queue now but if there's like an approach that's closer to the original like that would be cool but i just don't know what it is and i don't think the current one makes sense maybe it's a cube with a limited number of things in it but i'll try the q so i think what i want to do here is i'll do something like this well okay i'll just say um move q is like an empty array this is not a thing um just just delete all of this i need to think about this more so i'm going to call this direction here so i think this pushes off left this pushes move right this pushes up and this pushes the bottom and when it's time to do something i actually want to figure out like which okay so what what is the direction that we're going to use we still need the i said we still need the current direction so in this world the current direction actually represents the the flushed one so the one that we're actually going into so that would be move right um and i think what we need to do here is to update it depending on the cube so i think we want to if direction q is not empty we pick the next direction from the from the queue so that would be the the first thing in the queue but then if that thing is the same like if it's something that we want to ignore we should we should ignore it i guess like if you quickly press like you're moving right but you quickly press like left down i think we can immediately go down so we kind of should skip over yeah so i think let's write a super small function are opposite so if there's probably some easier way to do it so oh okay so i want to keep beacon um so say the next direction is the same as the current direction however while we have something in direction q we're gonna take something from it uh if it is if it is opposite to where we're going now then we are going to ignore it and keep going otherwise we're going to say that this is our next direction and we're going to break because we don't want to consume anything else from the queue and then we say that foreign direction equals next direction yeah i think something like this might work uh and we should i should probably just visualize what the well i guess yeah i think i should visualize it because i'm not sure okay so what i'm gonna do is i'm actually going to i'm gonna do this and i'm gonna write a small helper uh well i mean in this case it's going to be specific to this queue i'll just say document get element by id debug dot inner text equals key uh map so there's gonna be a function i'll just pick up the function name and just join them okay so why doesn't it doesn't moving down do anything so i press arrow down oh this is called move down okay this is silly though like it definitely oh but maybe it did that like i didn't remember let me see so if i press but yes so this is what i was able to do like i remember that i was able to do this like i would press like right and up very quickly and would actually do those things uh but i'm not sure that i could do this but maybe maybe that's how it worked but i think i'll keep it this way i i kind of prefer this behavior so let's let's make it let's make it much faster again yeah like this this matches how i remember playing it okay cool so i will uh maybe i'll need this well yeah i'll just remove this for now so i'm going com i'm going to comment this because it is well okay let's verify that i still can't go for example yeah i can't just go to the left i can just go up and just go down yeah this looks good so let me let me remove this um actually let's leave the let's leave this thing but let's just say it will json stringify whatever whatever is passed through it and i'll maybe use this later and for now i'll remove this okay i think it's time for a um for a comment oh let's see let's see this case like if if i if i press down yeah that seems fine it seems like it works oh come on yeah that's fine okay let's check on the comments uh oh this is this is funny okay uh so if i do yeah if i apply them both like surface comment if i apply them both to the um to uh by passing zero zero and then applying both to them and send scene if that's if that doesn't move it but yep uh hi rana uh yeah uh let's see yeah i mean i could i could refactor this a little bit i'm just afraid of breaking it like i think you're saying basically that if if they're not opposite then i do this and then i break and then yeah i think that that is a bit cleaner so then i don't need um it's very fine oops yeah i think that's fine so okay so i think we need to we need to do a few things here so one is that it should uh well what's what's the what's the most fun thing to add next because we could add the food of course it seems like the food is pretty important uh we could add a collision detection so that in the original version of the game it couldn't go through the walls i know that in nokia 33 10 it can go through the walls um but the original version was kind of strict there which i think i like so i will it shouldn't go through the walls and it also shouldn't go through itself that's that's not okay so i think maybe let's let's implement this uh so there should be some kind of end game like we should see when it uh when you lose the game so the the place where we determine the next head is here so maybe like if it's next head itself um well i'll just write this in line so if is if not check valid at something like this then what i'm gonna do is i'm gonna game interval so i'm gonna clear the game intervals to stop the game well i'm just gonna i'm gonna write this so so i need to write the function so is valid is valid next what is it isabellet check wallet hat let's say i'll just return through immediately and then stop in the game is gonna let's do something like this is not how it actually worked but let's just just so that it's clear that it says yeah that that that's fancy um and so how do we check if the hat is valid well okay so one thing if um what is the type of a hand is that um that is that is essentially top and left so if we say if top is less than zero or left is less than zero it's not valid if if top goes over the number of rows or oh come on that goes over the number of cons i think that's also bad uh for now let's say otherwise it's true but i think we'll also have to compare it to you yeah wonderful and yeah okay uh so that works but i also need to forbid it from crossing itself because currently i i can just well i mean it's it's it's too small but like um it's actually hard for me to show that there is yeah so like it can currently cross itself and it should break so i think the way we we do this is um we actually do know the current snake um the current snake points so and we also have a thing that already turns them to a set it's somewhere maybe maybe let's extract this their function um it's not ideal to to keep recalculating this if we already have this information right so this is actually um we only need to check against the the current snake so it would be nice to just keep track of this so for now i will be recreating it but later i might want to actually keep this like in the top level variable so that so that we don't so that we don't keep recalculating this but for now i'll call this get snake position set right oh wait right and then i can use this in the other place as well so currently here uh in order to check if the head is valid actually to get snake positions for the current snake well i guess i can pass the current snake and the next head well i mean i already technically have access to it but whatever i'll um i'll maybe refactor this later uh so so if um how do i do this it's like underscore uh so if snake positions already has this position then that is also bad otherwise we're fine um yeah wait it's supposed to stop why why did it okay so if i run into a wall it stops but if i do this then it doesn't stop something is missing so if not check well it had supposed to stop the game right doesn't it clear oh it doesn't clear the interval oh i see okay so yeah that's what i wanted to do yeah awesome oh yeah it's too far but i think i think this is correct so let's see um let me save this okay so it's time to make it actually uh have food and kind of seed it but i think before we do this like i really don't like that i'm calculating this set in two different places uh i think uh since i will need it regardless whenever i update the the snake i think i'll do something like just be two variables and i will always update them together and so oh i'm actually mutating it i forgot about it okay i'll get rid of this abstraction but what i'll do is whenever i mutate it i'll just do the same thing well i could also update it in a smarter way right because i know what i'm changing but that's kind of micro optimization so uh by this point i have updated the snake so i will update the positions and i will remove this argument from draw snake remove it here we always draw the current snake and snake positions are now always the just call the set and move this down because it's like let's be your function okay and then when i check the valid head i'll just have it except the head and yeah it'll just be we'll move it a little bit up because it uses oh okay i'll make it take positions themselves and yeah then it's still like appear function yeah i think this this kind of makes sense to me let's see if i didn't break oh i broke it neck position is not defined yeah right okay yeah so so now i don't have to recalculate this set every time i just kind of update it once and then i use it both in draw snake and wherever in the in the step function as well um so that is actually nice because i don't want to oh yeah maybe i'm optimizing the wrong thing so let's uh let's implement the the food so food is kind of interesting because we want to spawn the food at random places on the map but it's actually not going to be quite correct because it can be random places it has to be places that are not occupied by the snake because if we spawn food in a place that's occupied by the snake that would be like we can obviously we can spawn on the snake uh but for now we're actually gonna ignore it and uh will start with completely random food like random places to see that and then we'll see um we'll see how to change this let me see if there are any comments games classes really make sense like the snake should be a class that can move up etc yeah i i really happen to disagree with this i think especially in games it's actually way easier to work directly with the data structures because you don't know like for example if you're thinking about uh like the the food like if you like if you see the food at random places in the game like you do have to think about maybe initially you implement this like as a random thing and then you realize oh actually i need to keep a set of like cells that are not occupied so that i can peek between them and so on and like you need the flexibility to change the data structure midway but if you just like have a bunch of classes like and and then like they have a bunch of fields like it can actually be pretty tricky to change it later uh like i did like with the with how we're checking direction so i don't think classes would help here like at all um i just i just don't see it so um so when do we need to spawn i guess first let's just make some let's just render some food like i think uh i think that would be a good place to start so um we'll have current food and that's also coordinate right so let's let's place it somewhere in like in the in the middle of the screen or something so it is a coordinate and let's make sure that we draw uh the the food so i'm gonna structure this a little bit so so if the snake is in the position then background is black but actually i'll have an earlier condition that says if uh so let's have fruit position i should really write the helper that converts these things um yeah i guess i'll just i'll just write this helper now okay maybe this is computer naming because it is it's actually kind of like a key maybe [Music] uh i don't care i kind of like thinking that yeah i mean conceptually it is a key so maybe let's call this a key and this would be okay okay so we have some terminology so the key is a thing that's like indexable um not that it matters but yeah so if the this is the foot key so if the key is the same as the foot key so i will prioritize food because where we might have a situation where it kind of uh overlaps with the snake and if i get into the situation i actually want to see it but but we'll like we'll need to fix it regardless so this does not happen um so let's see all of this still makes sense uh no it doesn't number zero is not iterable ah right so when does this happen what are we passing oh of course yeah that would not work okay we have we have food and we can go through it which is funny so the next thing we need to do is actually consume the food um let's see we're not consistent about top left versus left top that is probably correct uh am i not oh yeah that doesn't make sense i think this this is supposed to be like i think it's always supposed to be top left that is kind of what i wanted so i is rose so that is yeah top and yeah i think in practice i am consistent it's just that i miss like i just incorrectly specified them here uh yeah so let's let's just yeah verify that it still works and this still works yeah we're cool okay so let's uh let's make us consume the food because that's what this link is supposed to do so this should be somewhere here so um the the head is valid and now if the head is actually uh so if so what happens when we consume the food i think what happens is we don't lose the tail so it's not that um it's not that we add something to the snake that wasn't there before because it would have moved into the into the space where the food is it's just that we don't cut off its tail so i think actually we we might need the this thing but do with like shifting i think that should actually happen later so we should we push the next head and then if next head is so if next head is the the place where the food is well if it's not where the food is then we want to cut off its tail but if it is well if it is then we want to move the food right so and i will not implement this correctly for now i will [Music] uh okay so take random by the number of rows so if we just round it i think it would be yes i think we need to floor it so that we don't get over the that we don't get the actual number of rows and next left is i think the same but for columns and aren't equals next top and next left and this is not draw snake anymore this is kind of like draw canvas because it also updates it also updates the food right let's see if i can consume this i think this is correct uh let me try to make it a bit faster okay this is kind of fun this is nice but if it gets long enough like i should get into a situation that was described in earlier where oh no uh i don't know if i can play this oh okay ah wait i need to make it so that it can restart because i really uh yeah if i press i want to keep reloading the browser so if i press r then i want to restart the game which means this would be initials think uh and because i'm mutating it yeah i just need the function that it's like make initial snake okay so now initially i set it to make initial snake and then when i reset restart the game where does that happen i think it yeah here uh i'm gonna clear well this is just gonna be in the array and i'll say current snake is initial snake orange snake keys is the key set current snake current food equals well i'm gonna call this spawn food and i'm actually going to call this spawn food so this would be the thing that's responsible for it and aren't food it will spawn food and so that is the thing the same thing i'm gonna do here so i want to reset the what do we have here yeah i don't want to touch like these things uh so yeah so this is like this this runs once and then is the actual state of our program okay so i should be able to restart the game now why is it not doing anything move right oh yeah let me just move this now restarting doesn't work oh because i need to start the interval again and reset the um i think i need to do this and i'm gonna call the start game and i'm gonna call it here and actually i'm gonna move this through into stop game start game and i'm gonna move this initialization here and then actually i'm going to remove for example this actually should be set as well um i'm gonna remove all of these because they will be set by the first started game call yeah yeah i can now restart the game okay that level is a bit too intense uh let me try to am i so bad at this okay no i can't this is too much uh but i will uh yeah let me get back to um the where is the place first of the interval yeah so this should be like 100 100 no 50 20. yeah that is reasonable okay i'll keep that 15. so the thing that we added is restarted and now let's make so we do consume food now um but it spawns in random places which means that at some point if our snake is really big it's going to spawn over the snake and i think the easiest way to see this is actually maybe if we make the field very small so like um well maybe even smaller all that is yeah but you you can already see like there are cases where it spawns uh directly on the snake maybe if we make fewer columns as well yeah like that it should it should never spawn on this thing that is bad so this is the thing that we need to fix next and this happens here so i think the way to fix this like there could be multiple approaches right so the the most naive approach uh would be to you know every time we generate uh the food like this would be funny to write this is a horrible way to do it but uh just for the sake of it um so just to see if it actually works so um we're gonna try to generate the position and then uh if the snake already has this position this position we're just gonna try again and we're gonna keep trying until until it actually works so uh yeah i think that i think that fixed that i think they it always appears well no maybe not let's see let's make it a bit slower so that i can see what's going on yeah i think that is correct i think well i mean it's horribly inefficient but i think it does it does ensure that we never get a you know a thing here and if i uh if i find this word my generation spawn foot like if i if i remove this protection then it definitely occasionally spawns inside of the of the snake but this is very inefficient because well like in theory there is a you know a very unlikely possibility that it will keep looping forever so this doesn't really make sense um so i think what i what i want to do instead is i want to limit um like i want to be smarter about how i'm picking the the place to spawn the food and i want to avoid any need to do it more than once so i don't want to do this thing where i generate a place and then like suddenly it's already already taken by the snake so i think what i want to do at any point in time is where is it okay to spawn foot and and then and then picking randomly from those cells but it's also important that i want that to be cheap to check of course but then like i also want that to be cheap to update and i think like checks are less important because we only spawn food pretty rarely right like only when you get through it but we actually do have to check if you're um like if we update some kind of data structure every time you move we want that to be fast so like that needs to be really efficient and i'm thinking like the thing that i'm kind of leaning towards is like something like the inverse of what we have with the current snake keys where we have a set of all the places that are occupied by the snake i think i would maybe go for a set of all the places that are not occupied by the snake and then that those are the places that we choose well yes so those are the places that we choose the food from so maybe let's give that a try so uh so i'll have current vacant keys and this is so i have this the key set that do i use it anywhere else well yeah i use it when i create the snake but i'll have to i also need i'll also need to update the the vacant things at the same time [Music] so maybe this should just give me two sets so instead of maybe this should go over all positions so i will i will get rid of this to keyset function i think what i will do is i'll have update key sets which is gonna update both of these and yeah and instead of this it's going to do something different so i will we'll move this move this up a little bit um so when we create i think it makes sense to create a few empty sets here so and then we will be update this is the thing that brings them in sync with the current snake so i see so currently the way it works is that it always i always recreate these sets from the current snake so maybe as a further optimization i could just not do that later and only apply the thing that's actually changed but for now i think i will keep the existing structure where i recreate them i'll just so i'll just implement the um i'm gonna make it work first and then and then i'll uh i'll see if i can avoid recreating them every time so i think first i want to go over all of the cells actually so and i want to add this to the set of the vacant keys so this is where this put the food can spawn and then for each of the each of the snake keys i want to say no actually it is not allowed to spawn here because it is taken by the snake and so so the way spawn food now works now is that um if i think about the win in the game later but [Music] if there are no vacant keys um i don't think this actually makes sense because like it's not your fault if you're like if you've taken almost all well i guess it is your fault if you can't later turn around and there's like something spawns at your very tail but you're unable to catch it i guess it is kind of your fault so maybe yeah maybe we actually implement this right here well maybe stop game should throw because uh well it's not great control flow but like i just want to interrupt the dependent function i'll revisit this later but i'll have this it's probably almost impossible to win the game but technically possible i guess i'll just add it but this doesn't make sense the way the rethorn is structured like the parent function should take into account that we might not be able to spawn food um well okay yeah i'll implement this properly so um so if spawn food returns null that's when we're going to stop game so here uh well otherwise yeah so we can kind of win the game now um so let's see it's spawning foot so i think what i want to do is um i just want to get a random index uh that is between zero and the size of the vacant spots so maybe again floor math round rare sorry random times the size of the subway well not array but size of this map well not not the map the set and i think i want to return uh okay so that's a set but the thing i want to return is not the different type right we only ever use the okay so i'm going to change this to this will be current foot key so that i don't need to kind of parse it back so get this and this would be also the key orange foot key current foot key spawn foot should return the key which it would do by taking well there is is there a well-defined order well i can just iterate over um so i can iterate over the over the set i don't know if this makes sense but i think if it's random it doesn't matter anyway so yeah um let's look at food because i don't think i changed all these just yes so this there's no food here now there's just current food key yeah let's see if that changes anything i cannot read properties of undefined yeah current vacant keys it's like well i do initialize it here so isn't this being called it's been called when i started the game so why would they have been although scene of undefined this is definitely not being called so start game uh i don't get it start game oh okay i call it early so um i can't spawn food until i've updated but once i spawn it that doesn't mean it's not vacant anymore like i'm thinking it it shouldn't matter because i can't spawn more than one at a time so maybe it shouldn't matter i guess i won't be set in no it's okay i'll set them yeah i think this should work no link is not defined uh where is it just think yeah that should be current snake okay okay so i think if we look at what's going on here it never appears on the snake initially but here something weird happened there's also a little display issue because when it when the snake eats the food i think currently it gets displayed like for some reason it feels like there's a small delay there that doesn't feel right yeah i don't think this is working correctly now um so maybe let's would be nice to start writing some tests so what i'm going to do is i'm going to go into branch is that no ah and i'm gonna commit what i have but i'm gonna make some changes so one thing i want to change is i want to um i'm gonna get rid of the interval because that makes debugging really difficult so instead i will make it move forward when i press a button or something like this so that would be here wait start interval set interval yeah i'll just comment this out and instead i will call step when i press some button for example spacebar so let's see if that worked oh okay i should uh i should probably prevent i don't know that's gonna work i want clear interval game interval oh seriously i forgot define it okay so this should be i'll just say it should be here okay i can actually control it now i think that maybe like this this is unrelated to the spawn conversation but i think it feels kind of wrong that like i think the snake maybe is supposed to grow forward but i'm just really not sure but anyway like i can already see there are like definitely some kind of bugs like for example this should never happen so i want to add some login and i want to see like um i guess how these how all of these things are changing over time and see where i have messed up oh there's been there's been a bunch of comments about about how to do how to actually approach this so let me just read the comments first um and practice almost all okay no need to fill current vacancies and every call if keep a set yeah i mean i do want to like actually uh like i don't want to recalculate it every time i'm just starting with this because if i do have the another romanian structure in place that i like take from this set then i will like look at how to actually update the set in an easier way um yeah um it's the issue that the pink food is spawning in the wrong cell i mean yeah that's that's kind of what it it's kind of what the asia is but uh to be able to debug it i need to understand what's happening so i think every time i draw i would also want to so where is my yeah canvas so i would also want to dump a bunch of info so maybe um so this would be a set i don't think you can json stringify a set maybe i can do this and and also let's changes to be it's like a pre tag and this should be something like i think that's how you format it uh let's wait that's kind of large i don't need i need it to be so large why is it so large am i editing the wrong file like what's going on it's like i'm editing the wrong file somehow now it's here i don't understand what what is what is this what is being cached like okay okay i don't know what happened but yeah so oh i know what's going on it's because it's because i'm cancelling the default action of the r so that that was that was silly um or i'll just fix all the shortcuts so oh come on i think that's how you do it maybe let's try it once yeah okay all right now at least i can refresh the page so uh yeah let's let's get back so this will be our debugging pane yeah and let's get into some bad so let's just kind of see if the way it works in general makes sense so i will um i'll put this well and i'll put this first okay so um yeah so this is the snake that's where the food is and these are the vacant ones which i guess currently includes the food so let's see how they are um so five six seven five six seven eight nine and then if we make a move uh zeros yeah so this so far this makes sense and then this has become part of the snake and this is vacant yeah so this one is fine i want to get into some broken state okay so this one is interesting how did it okay i missed i missed the part when it goes wrong so i might actually have to like actually lock them yeah i'll do that okay so this is a weird situation so the so the snake was from three to eight so let's see so the foot was at eight the snake was from two to six and one seven eight nine were vacant which i think makes sense well except that the food was literally at eight uh maybe that's the case i was talking about like when it that it spawns it in the same place where the snake's hat is maybe that is the problem so if um so let me see about the timing so we spawn food so we push to the snake's head so the snake's head is busy but we still can spawn like spawn doesn't know about it yet because we haven't updated the key sets yet and so technically it can still try to spawn in the same place which would be wrong so i guess the the the bad way to do it to fix it is like to make sure that we update it once here and then once we've you know modified the snake we update the game but this is not a good way to do it but i just want to see if that actually like resolves the issue so uh let's see yeah i can't get it to do that buggy thing anymore i think that was the problem yeah yeah i think that that was the bug um but i i don't really like this solution but however it is better than what we had before because the snake doesn't doesn't spawn the food in random places so i'm gonna i'm gonna kind of snapshot it and and now i will work to optimize it let me check um let me check the chat uh benjamin says i would save the position of last cell the snake in the first cell of the snake and make sure the food cannot spawn in those cells and the soul between them well the problem is yeah right uh like it can turn so there isn't really a notion of like between we do have the positions but like how do you ensure that it cannot spawn right like you need to know at the time you're speaking the the element like you need to pick where it goes um so like we can simply make sure that it doesn't spawn there like you need to have a strategy for how to do it oh there is another there is another suggestion uh wouldn't doing something like rich rich if not a snake uh well you'll need to be more specific than that right like where do you use the random generator exactly uh but yeah like essentially what we're doing is is that except that like i think you need a strategy for the but but then ideally you also don't like i don't love like iterating over all of the cells in this case maybe it's kind of premature but i think it's nice if you don't have to do it so i want to i want to fix up the like i don't really want to recalculate these um i think the game already works so let me just check that it actually works now so uh let me set this back to what was it like 30 50 let's and let's turn the the interval thing back on and the interval needs to be like 50. so i can die or pokemon oops yeah yeah i think the game basically works now um but i want to want to make this a bit more efficient um i'm sorry this is just really really engaging for me it's it's so fun to play oh come on i want to catch this one okay um yeah so let's let's maybe checkpoint here so i'm um i'm gonna hide the the debug pane so this well i'm just gonna not dump things into it so i'll get rid of this it seems like it wasn't really useful and i'll check point what was the was the branch name awesome and now i'm going to try to optimize it to optimize this a little bit um so what i'm not super happy with is that we constantly recreate this these sets but like we should be able to kind of track them once they have been created for the first time uh what happens when you run into the snake like the head yeah yeah this this is already handled uh if you try to do that like it would just well yeah it would just game over which it should so um i'll need to think about this a little bit so there are basically two operations that can never happen to a snake one operation is that we add something to give it a new head and the other operation is to cut off a piece of its tail so i think maybe for like the first thing i want to do is to actually um is the somebody says painting they had a different color is a good ex thing well that the the original nokia 32 10 implementation that i'm i'm like re-implemented here did not do that so i don't do that either um yeah so i'm i'm i'm gonna make two functions so i'm gonna make a function that is like push head accepts uh next head and i'm gonna have a function that's uh pop tail that doesn't accept anything and so this would be a call to poptail and which currently listed this and update the key sets and this would be push head next head which currently does this apologist this should have been there so this is just refactoring oh oh that's actually that makes the game way more fun wait i kind of like this okay that is so funny ah okay no i i think i he heading to actually yeah i forgot the cold pork tail that's why it doesn't pop yeah but it does grow which is good right and now i'm going to change how this is actually implemented so i think what i want to do is i don't want to keep recalculating these i think i want to only so this is actually initial light this is actually like what i do initialize like initially this is something i want to do once and then i want to update them as we go so i think this is what i want to do here and then i don't need to actually set them to anything because this thing will do it for me so this is more this is more of a one-time thing so i'll move this through and you know actually if it's only used in one place i will just i will just inline it there so get rid of this function i'll just do it here yeah so we we create these things and we fill them in just once and then it will be the job of these two functions to actually to actually update them and so we need to update when we push ahead we need to know its scheme and we need to remove it from the vacant ones and we need to add it to the snake keys whereas when we pop the tail we should also get a key and we should add it to the vacant ones and we should remove it from the snake once uh and it doesn't work next head is not defined right because that was supposed to be the tail okay so now we don't recreate any sets the problem is i don't know if this logic is actually correct because i don't like well it could be completely broken right but we just wouldn't know it so um i will admit it but to verify that it actually kind of makes sense because i don't have any tests so uh i think what i'll do is again i will just limit it one to one row and like 10 columns and just see if and then again disable the interval uh so yeah and i'll just check that each step yeah you see so it like doesn't it doesn't seem to spawn on the snake ever whoa i've won the game uh okay that that is kind of funny uh maybe if i make it maybe if i make two rows i should be able to always win maybe because i can go like this yeah i think this implementation works i think this actually makes makes sense but i want to show one more trick um so let me undo my changes because they weren't needed so uh let me just go over the code and see if like i'm still on board with everything that's going on here so this is the initialization this is kind of the rendering code so i'm i'm going to kind of split it up and this is kind of like attraction and this is kind of like um i will move the interaction thing down because really it's this is game state and these are utilities these are all stateless and then this is more in the kind of interaction space these are utilities there i'll actually move you to this to the bottom okay still works i just move things around so okay and now uh yeah i just wanted to read through the code to make sure that it still makes sense so we have uh we draw uh this is kind of not i mean it's fine but like we kind of know what changed we update so we we could also kind of micro optimize it by actually moving the drawing logic directly to when we push you know when we pop the tail or push the head we could just um kind of change the pixels that were affected so that's one possible optimization it doesn't really matter but could do it for fun um let's see if this everything here makes sense to me so take the hat take the direction see if that's where we're trying to go if that's stop at the first feasible direction choose to go there see if we can get ahead and if it's not valid then we stop in the game otherwise we push the head and if we ate the food then we spawn the next food if we can't we you won the game or else we put pop tail and then we draw the canvas and then we we are with our sets like we we always keep keep them up to date we don't recreate them unnecessarily and and we choose a random thing from from the from the keys that are vacant yeah i think this is actually this is actually looking pretty good to me yeah so one more thing that i wanted to show um that is um it's not about like features it's more about like this code is kind of scary because i'm i'm modifying multiple things that are conceptually uh like related right so if i make a mistake like for example if i like forget like this like it's actually pretty hard to to see that i i made the mistake right because it it kind of works it's just at some point it will run out of the um well it will run off the things like vacant keys even though they actually are vacant so uh what i'll do here is um it's like check integrity so this is something that i would only do when debugging so maybe i could add like if uh what is so for example if i add uh key restraint oh wait i have a lot of errors what the hell oh yeah of course i haven't defined this thing but window location search yeah so if if this says uh curate debug i'm gonna run this extra function that is that is actually gonna be pretty well comparatively to other things it's going to be somewhat expensive um but will it will verify that i haven't messed up so the way it will do that is um so these are our these are the things so um so what are some things i want to check so i want to check there should not be food in the snake right um except for the brief moment when it eats the food but we check integrity after that so like which i can directly after we've updated the the food spot so again there should not this the sink should never intersect itself which means that it should not contain basically the same item twice the snake should have holes so the snake should be continuous if i may say so um the snake shouldn't be out of bounds the union of vacant plus one same cell can't ever be both vacant and snake um the the union of vacant plus snake cells must be entire field and i think these are the most well and of course the snake keys this set must match the snake array at all times uh yeah i think those are those are reasonable things to check for let me let me see um the comments instead of a for loop you could also directly modify the array with the snake coordinates no this wouldn't work this wouldn't work because uh well i have to clear the previous cells right like if i'm moving from like position zero to five to position like one to six then i have to clear the zero so i can't adjust the iterate over the um over the new snake coordinates i could i could limit it to like iterating over the snakes previous that that's actually uh maybe an easy optimization that's pretty simple right like um i could store i could copy the snakes ordinance before changing it and i know that the pixels i want to change are only the ones with where the snake well actually like only the tail potentially plus like only the head and so on that would be nice to optimize i agree but for now i want to check uh let me implement this integrity checks um so yeah food can't be yeah that's a good point food can't be out of bounds either so let's let's do this first let's now let's add some cool effect if if the integrity is violated so uh let's say ah is okay true and then at the end however we implement these checks if not is okay i'm gonna stop the game um i'm actually just gonna i'm just gonna fork this function and um i'll give it like special purple color and i'll i will throw yeah that's what i'll do and then let's let's just verify that if is okay is false yeah it will just pause the game and be like what the hell has happened um so so now let's let's start implementing it so there should um there should not be food in the snake well there's the order in which i'll implement them i think i'll start with um i will have to parse the food well let's go over all coordinates so let's let's get this um wait this is not ruby okay um so we got the key let's say we have food count zero and then if keem is current foot key we increase the food count well let's also call this failed check let's say this is null but if it's not now and we're going to throw with the failed check and so if would count is not exactly one it can also only ever be one there cannot be two foods so let's see if that actually works so maybe let's introduce a mistake intentionally where we spawn food uh i guess that's actually kind of tricky like how do you even intro well we could make spawn food go out of bounds so if it goes out of bounds it will be zero so it won't be like two but it will be zero so in that in that case um it should error because we'll never find it so current foot key well let's let's just explicitly make it well these are all the real keys but let's let's just make it return blah yeah and then make it let's make it return blah only sometimes so like it's if we had a bug that is you know um that only happens like half all the times right so this may be fine oops yeah yeah okay so it catches catches a mistake like this so okay so there has to be only one food so another thing we care about is that food should not be in the snake so um so let's go over the snake as well and maybe let's let's maybe have a set of all keys and snake keys and food keys which we now calculate uh ourselves and we're gonna check that they're the same as the ones that we expect which we actually already have the logic for because we we have this thing that actually generates it for the first time right somewhere like new set yeah so we have this and i think what we want to do is we want to generate these sets and just compare their the same as we expected yeah i think that's that's reasonable so what i'm going to do is i will extract this we're essentially partitioning the the field into two sets so um that is how i'm going to call it so uh so we'll copy paste this here this will be snake set this will be awakened set then this is are vacant keys this is a snake oh i'm gonna call this snake case vacant keys and i'm going to return them as a tuple so there's going to be snake keys and vacant keys well i guess partition cells i don't know how to call it but whatever so what i'm going to do here is snake keys vacuum keys it's partition cells for the current snake which is the initial snake and the sign current snake keys and then now somebody will say oh but you can do this like this and i think it's just like doing it in line this kind of it's like this this is not valid js right like it would say you have to do like this and this kind of sucks so i will not do it so i will do this and vacant keys vacant keys yeah but now i can also use this in my here so i can do like that all keys well like snake keys vacant keys those partition cells for the current snake and i am gonna have all keys that i get just from um well i don't know if i need that because if i trust this algorithm which i do i trust it uh it goes over all the rows and columns it marks things as being yeah like it it fully depends oh by the way it should look at this it fully depends on this snake and like i believe it's guaranteed to be consistent so i will take it for granted that it is consistent and so i don't think i need to actually do anything extra here um okay so this is checking for the food and then here i will take this snake easem and vacant keys and i will just compare i want to make sure that all the items in them are the same as the ones that we calculated so i don't know what's a good way to compare the contents of two sets uh i don't know is there something that i could use no i think what i'll do is i'll do something like this so i'll have a function that's like um and i'll just assume that they contain primitives because that's my use case so if um and because i don't care about performance um but the reader should know this um i'll just use jason's drinkify so what i'll do is return um so i turn this into an array sorted and i json stringify it so i will compare two of those things and that's what i'll be using so so if um snake keys and i'll also call this check integrity slow so if the so if the snake keys are not the same as the ones that we've calculated then we're gonna we're gonna say that the failed check is uh snake keys don't match and if the vacant keys are not the same then i think then we'll say bacon keys don't match um so food cannot be out of balance this is already solved um the snake shouldn't be out of bounds i don't think we guarantee this or do we okay the same cell can't ever be both vacant and snake i think we do guarantee it now because we trust this algorithm that it does a partition and then we check both of them against the blessed results so i think this is this is solved uh the union of vacant snake cells is entire field i think this is also solved because partition cells goes over all the items in the in the full field so it has to and then it checks our arrays where accumula sets we are accumulating against it so i think that is also that is also now being checked the snake keys set must match the snake array again this is already solved by by this because we use the snickery as the source of truth there should not be food in the snake so i think that we can check this with um if currency keys has current foot key there's there's food in the snake um the snake should never intersect the self so well if current snake length is not the same as the current snake keys size it means that it's intersected itself because it means that there's fewer well there's just if we deduplicate the cells this set is smaller it means that we have the same thing twice in the current snake so that would be that would be wrong um the snake there should not be food in the snake we already checked this the snake should be con the snake shouldn't be out of bounds so if the snake were out of bounds then um i think this is covered somehow i think if the snake were out of bounds actually i'm not sure that we cover this i think let's let's cover this just in case so i'll have all keys here that uh that are like all the valid keys that i'm just going to do to fill in here and then i'm gonna check if the so there should be something for making the union uh isn't there oh seriously okay uh nice um sure so if we compare two sets the set we get from the think you can what what does it take uh can it take multiple no just one uh well i can do this so um so this is going to be the union of uh current snake keys and current vacant keys and then the all keys that i calculated myself so if these are not the same then something something is out of bounds um and the last thing i would check is that this thing is continuous so as i let's iterate with this thing itself uh so let first cell equals current snake the first item and then from one to now to iron snake length what i want to do is to check that that it is well i want to check the distance between two cells right so then the the cell we're looking at is this one this should be called previous cell well i guess i can just do this so um this is the cell the previous cell is i minus one i can do this safely because we start iterating from one and then if um so the distance is sum of cell 0 minus so the first coordinate well so there's dx is this d y is this or is it the other way around what do we have first i mean it doesn't really matter but uh is it top and left it stop and yeah okay so it's this is d y this is the x and if d y like the only two valid things are d y is zero and dx is either one or minus one or the other way around i think these are the only valid things so if if it's somehow if the next cell has somehow moved because someone jumped then then that's that should be a failure snake as a break and i think that is sufficient but of course i implemented it poorly so let's see or maybe i actually have a bug and maybe this this has found the bug so let's let's see if if how this happens so um it says something is out of bounds because i'm comparing a set of all things with a a set of six things because i forgot to put the in this thing okay yeah so this is actually running all my checks now and it seems like so far it doesn't break oh come on uh see every time i i test it like i get pulled into actually playing it because it's so much fun oh okay um so i will i will commit what i have here but i will verify that i'm actually that this thing i added and spend so much time on that it actually catches coded mistakes and i just wrote everything perfectly and so that's that's why i didn't catch anything so let's say that i forgot to do this yeah yeah you see so if i forget to do this breaks if i forget to do this tulsa breaks i forget to do this also breaks i forgot to do this also breaks if i if i spawn well we already checked that if i spawn food in the random place it breaks uh maybe if i if i jump over something so like maybe if i if i make a mistake here so maybe i do this this so move up yeah you see i moved up it jumped 10 pixels and then it flagged it like no that's that's not possible that should never happen or if i forget to update it so like if i do this and then i go up well it ended the game whereas i i think it should have crashed it but i'll take it but yeah i think i think this is working um is checking all of the things that we care about uh well i can also check that it that if we turn off the so if we just say hey like this is always well it it should flag us so let's see that if i go outside the bounce yeah it flags it and then if i crash the snake into itself yeah it also flags it as a mistake so we're actually we've done pretty pretty well so i will move the integrity integrity check at the bottom and this is kind of like a debug thing as well as the this dump helper i had some did it just oh i guess i deleted it so i'll delete these styles as well and is that is that all that i wanted to do yeah so this is this goes into debugging maybe i'll pull stop game here with balls but i'll also update yeah and then throw yeah okay and let's let's verify one more time that if i break something it's still broken so again let's forget to do something here yeah okay and let's let's let's make sure that i can actually play it without this flag yeah ah awesome okay i'm gonna comment this and this is looking pretty good i'm gonna format it ah just so it looks a bit nicer and i will later put up a link to a gist so that if you want to play with it and like work it and you know maybe like maybe one thing that would be fun for you to look at like if you want to is uh so currently we iterate over all the pixels when we draw the canvas which is fine but like if you i think it might be funny to see how you can like without changing the logic too much like what is the minimal set of changes needed to make it so that you only like you know which pixels to update so you only update them and again like as i said earlier it's not enough to just go over the snake because you also have to clear up like uh the basically the tail right like that is in addition to the snake you also have to clean up its its previous tail but other than that i don't think actually there are there are any cases in the game where aside from the snake you would need to update any other pixels so yeah that could be that could be a fun optimization but other than that i think it works pretty well so another thing you could try is like implement the um the thing without the without the borders so that you can hop through the borders um yeah but other than that i don't know you could make it nicer you can switch render into canvas i guess that could also maybe make more sense and you know actually paint the snake to be pretty um yeah but i'm kind of out of ideas of what what else you would want to do here so i think that that is the end of the stream so i hope you enjoyed it and i will again like i said i will put this um i will put this into just and put it into the video description so that you can play with it yourself and maybe do something with it thanks for watching
Info
Channel: Dan
Views: 3,062
Rating: undefined out of 5
Keywords:
Id: dFRiNUp-FT0
Channel Id: undefined
Length: 185min 53sec (11153 seconds)
Published: Sat Dec 11 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.