Snake in Excel with Python (& xlwings)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello there in this tutorial we are creating snake in excel with python and we are using the excel wings module for that now if you have never used python in excel or if you aren't even aware that this is something you can do let me give a brief introduction to python in excel essentially you can control every part of your computer with python and excel is no exception in fact python has multiple modules that can do just that the most popular one is called openpi excel but that module has a crucial flaw while openpi excel can create and manipulate excel files it cannot do it while the excel file is running which is why you cannot use it to create games in excel with python xlwings however can do that just fine hence we are using that one and for the most part xlwings does basically the same thing that open pi excel does the modules are very similar and by the way you can also use python to work with word or powerpoint and i will make tutorials on that in the future as well so get subscribed to not miss those and for this video i will assume that you have never used excel wings before so the first part of this video is a brief introduction to the module so if you already know the basics i would recommend to skip that part and the second part then creates the actual game so with that we can actually get started and the first thing we need is to install it which happens in the usual way either in the powershell or on the terminal with pip so pip installed xlwings and then you should be good to go and just in case you have come across it there's also a paid version of excel wings that gives you a few more tools but in our case the free version is entirely fine to make the game so you don't have to pay anything for this tutorial so let's jump straight into the code and let's have a look at this here we are in a completely empty sheet of code and the first thing we are going to need is to import l wings and to make it a bit easier to write i have shortened into x w now with that we can use it and if you run the code just now you should not see any kind of message so the code just runs and finishes if you don't get an error here you have installed excel wings properly so that's a good start so now we have to figure out how to actually use excel wings and to fully understand how it works we have to understand the basic terminology of excel and there are three major parts you have to understand the most important one is an excel book and this is essentially a whole excel file and inside of this excel book you have multiple sheets so if you look at the bottom of any excel file you can see multiple sheets it's kind of like a browser tab except for excel and then inside of every sheet you have a whole bunch of cells and this is where you store the actual information you work with so we have to figure out these three parts to get a book to get a sheet and from the sheet to influence the cells and all of that is very easily done in excel wings so let's have a look here i'm back in the code and first of all i want to create an excel book and this happens first with xw and then the keyword book and here make sure that you capitalize the first letter kind of important and now if i run all of this we should be getting an excel file and there we go so this you can literally tell in the top is called book one excel so this is the book we have just created with this line of code now be aware if you have a slow computer creating this might take a couple of seconds so be patient and now at the bottom of this file down here you can see sheet one so what we have to figure out now is how to get from this book one to this sheet and that is also very easily done let me close all of this and the first thing i have to do is to store this book inside of a variable which well happens in the usual way so now i have this book available in the variable and what i can do now is to type book and then dot sheets and this is going to return all of the sheets inside of this book so let me actually print the entire thing and let's see what this gives us and it's going to take a second and there we go so what we can see in here we get our sheets and inside of that we have a list so this list here and right now inside of our list we have only a single sheet and that's this sheet here and you can see the name in the final part so this part here is the name then we also know that this sheet is inside of book one so that's this book one up here and then well this is a sheet but the really important information here is this sheet that's what we actually want to get and essentially all we really have to do to get the sheet let me remove the print statement so right now we know we have a list with only a single item inside so what we can do is get the index 0 and store all of this inside of another variable that i've called sheets and now if i print that so print sheet run all of this again now we can see that we have sheet book 1 sheet sheet1 so now we have access to this sheet and this actually allows us to make some changes so for example what we can do is change the name of the sheet so sheet dot name and then here you just have to add a string so in my case let's call it test sheet and now let me run this again and now in the bottom of this excel file you can see test sheet so we have renamed this sheet let me close it again so with that we can actually start to influence individual cells and for that we have to first pick out how to target one cell and excel wings has a ton of different ways of doing that now first of all i want to get my sheet again and now i can basically do something that looks very similar to indexing so i want square brackets and in here we can add a string that is a letter and a number let's go with a1 and this would give us the cell a1 i'm going to show you in a second where that is and now we can give this cell a value so let's give it a value of my cell and if i run this now we have to wait a second again and let me scroll in a bit to see this better now you can see we have the cell a for the column and one for the row and inside of that we have my cell so this is what this a1 here means that the a or the letter is for the column and the number is for the row and if you have ever used excel this should feel quite natural for the columns you have letters and for the rows you have numbers and i guess if you come to this from python there's one small complication that excel starts counting from one whereas in python we always start counting from zero this can occasionally be a little bit confusing so just be aware of that right so with that i don't want to save this we have one basic value now what we can also do is let me copy all of this we can also target a whole field of cells and this you do by adding a double colon and then the n cell you want to target so let's say in my case i want to go with d3 and let me add some different texts let's say just triple a just to have something and if i run this we can see let me scroll in a bit again so now we have filled a couple of fields with one string and our first cell was a1 the a1 we already have here but then we went to d3 or this d3 here which turns out to be this cell here and then essentially what excel wing does is it goes from the start to the end and fills the entire field with whatever we want to fill it with this could be a string it could also be a color we'll see that in just a second now let me close all of this again and there's one more thing that you could be doing and that is instead of a string you are passing in here a tuple let's say in my case let's go with three and seven and for the string just to have something let's go with let's go with bbb and if i run this now we can see if i scroll in a tiny bit so this is giving us the cell bbb in the column h and the row 4 and this might seem a little bit weird that our coordinates right now are three and seven so how is this getting us h4 and well let me explain essentially the first number is the row and the second one is the column and let me use a different color for that and let's start with the row and the problem we have here is what i explained earlier that in excel we start counting from one whereas in python we start counting from zero so essentially what we have done in the excel file is that this would be zero this would be one this would be two and this would be three so if we add a three in here we get row number four which well is kind of confusing but well it's a different ways of counting so this right here is essentially just the row and then the second number is for the column and this one is a bit easier so should be 0 1 2 3 4 5 6 and 7. and this would then get us h and if you combine those two we get 2 b b and b and that way you can also use two builds to get individual cells so with that we can target cells and change their values now excel wings has a ton more ways to do this the one you probably see a lot is called sheet and then the method range and then here you can also add a1 just like we have done up here and then give it a value and this value let's say let's call it ccc and if we run this now we can see in the top left we have ccc so the range method is also very powerful and does kind of the same thing we have seen with the indexing approach although it does work in slightly different ways but they really don't matter all that much to us so let me close all of this again and for the game i am not going to use this approach but you are going to see it quite a lot online so be aware of that now for the actual game there's one more thing we are going to need that's really important and that is how to change the color of a cell and that is actually happening in a very similar way so first of all we are going to need a cell again so let's say in my case i want to get cell let's say e1 and now instead of the value i want to change the color and for the color we need what is called an r g b tuple and literally all that means is that we get the amount of red the amount of green and the amount of blue and then we mix these three colors together and that gives us a color and the value can go from 0 which means no amount of that color or 255 which means the full amount of that color so if i had 255 0 and 0 we should be getting a red cell at position e1 so let's try this and there we go at cell e1 we get a red cell so let me close this again and now if i change this to let's say a zero and a 255 and the 255 we would get no amount for red all of green and olive blue so if i run out of that we should be seeing a very bright blue or turquoise whatever you call it doesn't really matter so this is then all we need for the basics although be aware this is a really basic introduction in fact we are going to see a couple more things in the actual game but for now this is a pretty good start but with that i guess we can go into the actual game and for the actual game i will put this into two separate parts the first part is all about setting up the board so all of this is going to be static and then only for the second part we are going to add a moving bit that is well a video game and for the second part we are going to need a fair bit of game logic so let's leave this one for now and let's start by setting up the main board and let me go through what i want to do in here essentially i want to create two sections one section is the actual game where the snake can move in i call this one the game cells then below that i am also going to add control cells and in there we have our control buttons and our exit button and these buttons also have to be placed by us and if you have paid attention in the first part of this video setting all of this up shouldn't actually be all that difficult although it might require some tinkering but i guess let's go through it together here i am back in a completely empty sheet of code and the first thing i want to do is to import xlwings as xw just like we have done before and now we have to create the book but since i have to move around quite a bit of data i want to put this entire game inside of a class which is going to make our life significantly easier down the road and inside of this class i have to define an init method and in here as always we need self and besides that i want three more parameters the first one is the speed so that's how fast our snake is going to move and besides that i want width and height and these two parameters are going to give us the width and height of our game field so the area the snake can move in and well with that for now let's just keep a pass in here so we can create an actual instance of the snake so let's call it snake we need snake and here for the speed i want to go with three and for now let's create a smaller field so it's easier to test and i want this to have a width of 4 and a height of 6. and if i run this nothing should happen so the code runs but nothing else happens because we are not showing anything yet but that we can work on now so let me get rid of this and let me add a comment to explain what we are doing in here and the first way i want to do in here is the book setup and essentially i want to number one create a book number two [Music] is select a sheet and then number three is rename the sheet to snake and this i want you guys to do as an exercise so create a book select a sheet and rename that sheet to snake let's go through it one by one and let's start with the book itself and here this should be an attribute so this has to be self and i've just called this book and to create a book we need xw dot and now with that if you're on my code now we should be able to see an excel file there we go this is already working nice now next up i want to select the sheet and this also needs to be an attribute so self dodge sheet and in here i want to get myself dot book dot sheets and then just get the one with the index 0. so this would then give us the sheet now finally i want to rename the sheet with self.sheet dot name and i've called this snake so now let's start off this and we can indeed see at the bottom we have snake so i can close all of this and this is then giving us our first part now next up i want to add another section and i've called this one the board set up and then here we are just storing some general game variables the most important one is self.speed and for now this is just going to be speed although we are going to change this later now next up i need my width and this is just my width and my self.height and this is just going to be my height so i know how wide and how high my game field is going to be and i can use this all throughout my class and with that i can actually start setting up the game board and this is going to be quite a few lines of code so i'm going to put all of this inside of a method and i call this board setup so let's create this method so self.board setup needs self and nothing else and now in here we have to find a couple of different things so let me add a pass in here for now and let me explain this right in the excel file so here we can see it again and essentially what i want to do for the cell i first have to find the top left cell and in my case this will always be b2 so this cell here is always going to be our top left now this i have done to have a bit of an offset between the left and the top of the field so we don't have the game in the top right that looked a bit weird so this b two cell we always have but from that we have to get our width that is flexible and our height that is flexible so essentially we have to combine these two and get a cell that is essentially let's say in this example somewhere here and finding this cell from this width and height of information is going to require a few lines of code but in the most basic sense all we are going to do is we are getting the entire alphabet so all of these column letters here and then select the one that has the right index so in our case this would be four and then for the rows all we really have to do is get the actual number here and from that select the right row so these two parts we have to figure out let me close all of this and let's go through this one by one and first of all i want to put all of this in a variable that i called game cells and essentially what we are going to create in here is what we created earlier so a string that always starts with b2 and then goes to some other cell let's say in this case just for the sake of the argument would be e5 and right now this coordinate would be wrong so we have to figure out how to get from a game width of 4 and a height of 6 to the actual coordinates of the final bottom right cell so let me get rid of this and instead i want to turn this string into an f string so we can run code inside of it and now i need some curly brackets and this curly bracket is going to be for the column so we need to figure out a letter and to figure out the letter we first need access to the alphabet and python has an entire module for that and that module is called string although i don't really want to all of the string module i just need one specific part so let me not import all of it instead from string i want to import what is called s key with a double e and then upper case and let me actually print this so print as key uppercase with proper brackets and if i run this now and we're getting an error because we have to add some code inside of our f string so for now let me just keep it at e5 so it's working and now for the upper case we get all the letters of the english alphabet in uppercase letters so this is literally all that this one here is doing so i can close this and now we can actually start working in our f string properly so essentially all i want to do i want to get my ascii uppercase letters and from that i want to select the letter with the index that corresponds to the width of our game field so 4 in our case and well literally all we have to do for that is add self dot width in here and let me actually demonstrate what this is going to do so print game cells if i run this we get from b2 to the column e so if i draw this let me scroll in a tiny bit our top left cell is always going to be b2 so this would be one cell then we have cell 2 3 and 4 and at cell number four we get to column e so we already know that this line here is working quite well so that is a really good start now i can close this and now we have to find the row and this is just going to be another curly brackets and in here to figure out the row we just need self.height and well let me run this now and we get e6 and let me scroll in a tiny bit to draw this in a bit more detail there we go so as always we are starting with b2 that's always our top left and right now our field would go to e and then to six now the problem is that for the column we do indeed get four cells so we get one two three and four so the width of our game already works just well however for the height we do have a problem that we have one two three four and five cells only but in our game we specify that we want six different cells so in here we have a problem and the reason is again what i talked about earlier that in python we always start counting from zero but in excel we always start with one and this is what causes the offset here but well that is very easily fixable literally all we have to do is to add a plus one so now if i run this again and let me scroll in a bit as always so here again is our start cell and now we go all the way to this cell here so we have one two three four five and six cells exactly what we specified in the height of our game so this is now also working really well and well with that we have the dimensions of our game so now what we can do is fill the entire thing with a color for that we are going to need a color and i have predefined a couple so let me paste them in let's do it right before the snake and then here we have all the colors we will need for the game and for now the board color is the actual color of the game board well that makes sense so essentially i want to fill all of these cells here with this color and this i think could be a pretty good exercise for you so select all of the cells we have for now and fill them with the board color all right so essentially what we have to do first of all we need this self.sheet so let me copy it and now i want the indexing operation and i want to get my game cells now next up i want to specify the color and the color should just be the board color so we just want to target this variable here so now let me try to run all of this and we can indeed see a color for the fields now obviously right now this field is going to be way too small but later on we can make this much larger but for now it is much easier to see what we are doing in a small field now next up we are going to need our control cells and this is going to be another string so we have a start cell and an end cell and i guess let me demonstrate what this is going to mean in excel so let me scroll in a bit again and essentially what i want to do that here i have my entire game cell and right below that so starting from this cell here i want to have a control panel and this control panel should be five cells high so one two three four and five and it should also cover the entire width of our game so this wide and as a consequence we have to figure out two cells again first one this cell here which right now would be b eight and then the other cell is going to be the one down here and this one right now is going to be e 12. so let me close all of this and don't save it and i want to go from b8 to e12 so now we have to figure out how to create this number dynamically depending on the size of our game field and there's one thing we already have and that's this b again at the beginning because our field is always going to start in that row however everything else we have to figure out one by one so let's start with the height of our starting cell and again we are going to use f strings for that and this could actually be a pretty good exercise for you try to figure out the top left and the bottom right cell so that you always have the full control panel that is 5 cells high and as wide as our game cells now first of all we have to figure out the top left cell and specifically the row here and this one is actually quite simple because all we really need in here is to get this cell and go one further down because the control cells are right below the game cells so i can literally just copy all of this paste it in here and change this plus one to a plus two and that is all we needed now next up we have to figure out the column and the row for the final cell and this also isn't all that difficult because the width we also already have and that is because our control cells and our game cells have the same width so we can just paste all of this inside of here so what i'm going to do is copy all of this paste it in here and we should also be good to go now finally we have to figure out the final row and for that it's important to remember we always want to have a height of five cells for the entire control panel so literally all i can do is copy all of this and paste it in here and now instead of plus two i want plus six and now this should be all we needed and as a matter of fact let's go with self.sheet get my control cells and for now let's go with value is equal to let's call it control and now let's run all of this and let's see what we get and this is looking pretty good and let's count what we got here so this is our top left cell we have one two three four and five cells in the height and the entire thing is as wide as our game cells so all of this is looking really really good and i guess there's one thing you might be wondering about let me move all of this to the side here's good so you might be wondering why did we have self.height plus 6 for this final cell and i guess the answer here is that when we specified this self.height plus two so this cell here we already included this cell so this would be two three four five and six and this is where this six is coming from and if we added a 7 in here we would have gone down all the way to this cell which is what we didn't want so now i can close all of this and we already have our cells now next up we need the actual buttons and again let me add some comments to explain a bit better what we are doing so this would be the background colors and next up i want to get my buttons oh and i did forget we should change the value to a color and the color we do want to get is the control color so i just want to copy all of this and paste it in here and now let's run this and this is looking significantly better and i guess while we are here let's actually talk about the buttons so for the buttons i want to have five different buttons in total the easiest one is the escape button which shuts down the entire game and this one should be in the bottom right so let's call this one the exit button now besides that i have four direction buttons and let me just draw in here where i want those to be so this one here should be left then there is up then there's right and then there's going to be down and let's talk about the positioning here now the exit button is always supposed to be in the bottom right of the control panel so if we are to expand the size of this control panel the exit sign would always be in the bottom right now besides that for the directional buttons so these four i always want to have a one cell offset from the top and the one cell offset from the left and that makes the game look a bit more open so this is also something we have to figure out now that being said other than that the position of these four buttons is pretty fixed because we always go from a directional point of this b2 point which stays constant because this is always the top left of our cell and because of that we always know for example that this left is going to have the column c and the up and down always going to be in the column d and the right one is going to be in column e so this way we already know the columns for each of the buttons but we don't know their rows this is something that depends on the height of our game field so this is something we do have to figure out but the columns we already know and we know this because well the game always starts at top left and we have a one cell offset from that and then we have our buttons so here so this is going to make our life a fair bit easier but all right that was a lot of talking let's actually go through this and i guess let's start with the exit cell that should be one of the easier ones and this has to be an attribute so we can target it throughout the class and i've called this one exit cell and in here again we are going to need an f string with the position although now things are a little bit easier because we only want a single cell we don't want an area so we only need a column and a row and actually we already know the position of both of these cells and this could actually be a really fun exercise for you try to figure out the position of this final cell that is in the bottom right of our control cell and this is something we have already talked about in here so pause the video now and try to figure out this position the answer here was actually really easy because in this control cell we first figured out the top left cell of the control panels and then all of this was the bottom right cell and that is where the exit button is supposed to be all i have to do is copy all of this paste it in here and we are good to go so now what i can do is self dot sheet and get self dot exit cell and now set the value to let's call it quit and now if i run this and i zoom in a bit we get the word quit now we do have to change the color of the text and of the background we're going to do that in just a second but for now we know that this is working so that's a pretty good sign let me close this again i don't want to save it now next up we have to get the direction cells and well that is going to become quite repetitive so let's go for it one by one the first one is the left cell and this one again is going to be an f string and in here what i mentioned earlier is we always know the start column in this case it's going to be c and now for the row i essentially want to have the top of our control cell so this part here and from that go two cells down so well what i have to do is copy all of this and change this two to a four and now i can do essentially the same thing i have done earlier so let me copy all of this and change the exit cell to a left cell and the value here should be left and now if i run out of this that looks pretty good so i know that this left cell is right in the middle of our control panel and there are two cells on top of it so this seems to be working quite well now next up my up cell should be here my right cell should be here and my bottom cell should be here and that way we would be getting a proper cross so that's the next thing we have to work on and i think this could be a pretty good exercise for you as well so try to get the cells for up right and bottom and fill them with the right text it's going to be done in exactly the same approach i have done for now all right let's do it together now and really all we have to do is let me copy the left cells and i want to change left to right so this should be now right the text should also say right and now we have to figure out how to change this position to get two cells further to the right and that literally just means changing this letter from a c to a d to go one to the right and then to e to go two to the right and the row is still the right one so now this is also looking pretty good so we have the position of the left cell and of the right cell so that's all we needed here now next up we have to get the buttons for up and down and let me copy these cells again and this is going to be changed to up that's looking pretty good cool so now i have to figure out this string here and well first of all the column we want to get right between c and e which is the letter d and next up for the row we want to get one up so this plus four should be a plus three and now let me run the code and that's also looking pretty good so now we start to have a proper cross for our game and then finally let me copy all of this one more time we want to get the down cells and this is going to have essentially the same position as the upsells except on two rows further down so i change the three to a five and now run out of this we have a proper cross like gamepad kind of thing and we also have our quit button so that's the position of all of our buttons now that we have that we have to add the button styling and for the button styling we have to change two things we have to give each of the buttons a background color and this we already have it's the button color here and we also want to change the text color of each of the buttons and that would be the text color here so these are two things we have to target so essentially all i'm going to do is i'm going to cycle through all of these different cells and then change the color for each of the cells and also the color for the text inside of that cell so let's go through it one by one first of all we need a for loop so let's call it for button in that's going to be a list and i just want to get all of my cells so i want my exit cell i want my left cell i want my right cell then i want my up cell and finally my down cell and now inside of that i again need self.sheet and now the button and first of all i have to change the color of the cell and the color i want is the button color now let's run all of this and see how it looks and that's already a massive improvement and besides that i also have to change the color of the text and that let me copy this line here that we can achieve with dot font dot color and in here i want to have my text color and if i run this now this should give us white text and there we go so this is looking significantly better and right now all of this looks really crammed up but once we increase the size of our field this is going to look significantly better actually let's do it right now so let me close all of this and now i want to change the size of our field to make it actually look like a decent game and in my case i went with a width of 12 and a height of 8. and now we run this again so now we can see we have our buttons in the top left of our control panel and the quit button in the bottom right but now we have one more problem for this styling that all of our game cells are way too wide and not high enough so that's also something we have to work on so let me close all of this and let me add another section in here and that's going to be the let's call it cell dimensions and to change the dimensions of a cell we first have to target the cell and let me just target a single cell just to illustrate this so self.sheet and b2 so our top left cell and now to change the width and the height of that cell what we need is either the row height and this needs to be an integer so let's say for now with 40. and if you want to change the column width we need well the column width spelling this correctly would also help and let's go for them one by one let's start with the row height so if we run the code now this row should be significantly higher and there we go now the row with b2 is drastically taller than all of the other cells now what we can also do is for the column width let's set this to really high numbers so we can tell what's going on let's set this to 100 and there we go now the cell b2 or rather the entire row for b2 and the entire column is really large so one important thing here to consider is if you change the row height or the column width of any cell you change the entire row or the entire column so be aware of that and what is important here let me demonstrate this by only working on the row height for now technically what we could be doing in here is adding in our game cells so what we created earlier up here our entire game field we could set this one up like this run the code now and this would be working the problem is this is also very very inefficient because essentially what we do we look at this cell here and we set the row height to something like this then we come to this cell here and we set the row height again to the same thing then we are doing the same thing for d e f g and so on and for every single one of these we are performing one operation that we didn't have to do and i guess along with that we are ignoring our control cells as well so let me change the code here a tiny bit and instead what i want to do is to only get my column b and then get the entire height of our game panel so we essentially want to go from b2 all the way down to b 4t and this is also not a particularly difficult thing to achieve so let me get rid of all of this and in here i just want to have this string and the string is always going to start at b2 and now we want to go to the end of our control cells and this is an information we already have it's literally just this self.height plus six so i can copy all of this paste it in here turn this into an add string and now if i run all of this we are getting an error because let me close all of this the error here is that i forgot the capital b and now that we try this again and there we go this is looking pretty good so essentially what we have done in here is that this b2 is very easy it's just this cell here but now for the second information let me use a different color for this we are still staying in the column b so we're staying in here and now we go all the way down to the bottom of our control panel so we go all the way down to here and then we are changing the row height for all of these cells and that way the next cells are normalized again which makes the entire game field stand out quite nicely which is what i kind of like now alternatively something i didn't mention earlier let me copy this line what you could have also done is to select every single cell inside of this column and this you would have done with the string b and b so this way you're selecting all of the cells inside of this column so if i were to run this you would get literally every single row would always have the same height now in my case i don't want to do that but well you could okay so with that we have a proper height for our row and i'm actually quite happy with the height and the width now so i'm not going to manually set the column width so with that we have set up our entire field didn't actually take all that long although it was quite a bit of logic so with that we have to start working on the actual game part of this game and this is going to involve a couple of things so we have to place a snake we have to place an apple we have to get user input and then once we have all of that we have to move the snake depending on what user input we are getting and then if the snake hits an apple we have to make the snake larger and if the snake hits either the end of the cells or itself we have to crash the game which in our case means we are just closing the excel file so that is going to be quite a few different things we have to work on and i guess for now let's start working on placing the snake and the apple and displaying both of them oh and let's do all of that straight in code so here we are back and in my init method i want to add another section and this i have called snake setup and in here i want to create a couple of attributes the first one i called self.body and this is going to be the body of the snake and this body is going to consist of individual cells in the beginning it's always going to be free so i just want to have a list with different cells so essentially for example one body part could be something like let's say b2 so this would be then one body part of our snake but in here we do have a problem because later on i want to update the position of each body part and then having something like b2 is going to be quite a pain to update so instead i am not going to use the string arguments and instead i'm going to use the two bolts so i want to place one body part of the snake for example in row three and column four and that way i can just add a plus one to this part here and then move this cell one row further down and that is going to make the math significantly easier now with that i have to figure out three body parts of the snake and let me actually display the game again so we can see what we are doing so essentially what i want to do is i want to place the snake when it starts right in the middle of the game field somewhat to the left so really all i'm going to do is i'm going to get the entire width of the game divided by half and then take the integer of that and place the snake wherever that happens to be and then i guess give it a few pixels offset to the right and then we should be good to go shouldn't actually be all that hard so i want to get a tuple again and in here i have to get the row and the column and for the column we can just use an integer let's say for the first part let's go with a column of 5 and now for the row i want to get my height and divide this by two the problem now though is that right now our height is eight so if we divide this by two we would get four but if our height was 9 we would get 4.5 and then we would get an error because we have to use an integer here so let me put this back i have to turn this height argument into an integer and well with that we have one cell of our snake now what i really want to do is to copy this two times and then change the column so this one here should be four and this one here should be three and with that we have the body parts of our snake they are not visible right now but that comes in just a second actually let's do it right now and i'm going to do all of this in a new method that i'm going to call display game elements that seems like a decent name and in here literally all i'm going to do is i'm going to cycle through every body part of the snake and then draw that part of the snake so it's literally a pretty simple for loop so let's say for cell in self dot body and in here self dot sheet and then we want to get the cell and change the color to i put this as body color and that is literally all we needed so now in our snack setup i can run self dot display game elements and if we run all of this we can see our snake so this is looking quite good now there's one problem we have right now that the color of the head should be different from the rest of the body so it's a bit easier to tell where our snake is going so let's work on that and i actually have a body color and a head color and now we have to figure out where the head of the snake is going to be and this actually isn't all that difficult so if you look at the list of our snake body in here we have three elements so we have zero one and two and well the head is always going to be the list item with the index zero so as soon as we know the index of each of these items we can always tell which one the head is going to be it is always going to be index zero and the index in a for loop we can get with the enumerate method and this one is going to return an index and then the actual information so now in here all i need to check is if index is equal to zero then i want to do something else and if that is not the case i want to fill the sheets with the body color and if we have the hat let me add the proper indentation all of this code is still fine but now i don't want the body color instead i want the head color so i can just replace this and now let's run the code again and there we go now our head has a different color or more precisely inside of this list the item with the index 0 is going to have a different color than the rest of the body so really all you have to understand here is that this cell is this head with the index 0. and next up i also want to have an apple and the apple i also want to draw inside of this method so i have to create the apple before i run that function and to create the apple we need a couple of lines of logic so i'm going to create a whole new method that i called create apple let me create a whole new method create apple we don't need any arguments and in here we have to do two things number one is we have to get a random cell inside of our game cells and this would then going to be the position of our apple however we also have to check that this apple isn't being spawned on top of the snake because that would be kind of weird so we have to first get a random cell and then check if this cell isn't on top of the snake first of all i want to get a random cell and i want to get a random row and a random column and to get random numbers we need another module so from random import rent int i want to get a random row and a random column and for that i need to rent in module and in here get a start cell and an and this i have to do for both the row and the column and now here we have to think about what numbers we are going to get and well the start is actually the easiest part because they are both going to be 1. so 0 and 0 would be the top left of the excel sheet so a1 but in our case the game always starts in b2 which in a tuple would be 1 and 1. so the start part is always very easy to get and well for the end part it's also not that much more difficult because we just want to get self dot with or self dot height or more specifically the numbers we passed in here earlier that's literally all we really want so with that we already have a random position and now technically what we could be doing is just get self let's call it apple position is going to be the tuple with a row and a column and now once we have called that we can inside of our display game elements let me actually add a proper comment so this would be the snake display and then before that i also want an apple display and for the apple all we need is self.sheet then get myself dot apple position and then i want to change the color to the apple color it's going to be this and now if i run this this should be working except now we are getting something very strange that our apple color is down here which uh not ideal and that isn't exactly what was intended and the issue here is that i messed up the width and the height so but row we want the height and for the column we want the width and now let's try this again and there we go now we have an apple in the top left that's looking pretty good let's try this a couple of times that's now an apple all the way on the left and now we get the apple all the way on the right and i don't know why the apple is always at the corner that's a bit strange ah and now we have another problem so now you can't see the apple at all so if i go up and down you can't see it and the problem is is that the apple is somewhere right below our snake which is actually a very happy accident because that's exactly the problem we have in this code right now and that we are going to fix in just a second but first of all let me run this one more time and now i hope the apple is somewhat yeah now the apple is in the middle of the field so we just got some weird random numbers but all right the problem we have right now if we are spawning the apple somewhere randomly there's always a chance that the apple is right below the snake which would be kind of strange so we have to account for that so let's call this check if apple is below snake or on top of the snake on the same position as the snake well you get the idea and in here this is going to be a while loop and what i'm going to check is if the row and the column is in self.body and then inside of that if this while loop is triggering i want to reassign both the row and the column so literally all i have to do is copy all of this paste it in here and then essentially what we are going to do is in here we are creating a random row and column number and then we are checking inside of this statement here if this position is inside self.body and if that is the case we are creating a new coordinate and we are going to keep on creating this new coordinate as long as this row and this column are inside of self.body so once they're not inside anymore we are stopping this while loop and then once we have that we are setting the position of the row and the column so with that we make sure that the apple is never going to be inside of the snake or outside of our game field so now i can minimize this method here and not think about it again actually display game elements we can also minimize because we don't use it anymore now with that we have drawn all of the game elements so with that we can finally come to the actually interesting part of this game that we are getting user input and use that user input to move the snake and let me explain how this is going to work and to make all of this work we need to understand one key concept and that is called a game loop and if you have followed my pie game tutorials this should feel fairly familiar to you but let me explain it if you haven't followed those tutorials a game loop is essentially how all video games are going to work and it essentially consists of three different parts number one we are getting some user input so in our case we are pressing one of the five buttons number two we are using that input to calculate where stuff has to be on the screen so for example if we are pressing right our snake keeps on moving to the right and then finally after we have all the information where stuff needs to be we are drawing everything so in our case we are drawing the new position of the snake and the new position of the apple and then this we keep on doing forever so after the loop finished once we keep on going all the way back to the start we check again the user input we then use the user input to get a new position of the snake and then we are drawing all of this and we keep on doing this as long as the game is open so we're only really going to stop this if the player fails the game and i guess then the really important question is going to be how can we create this game loop in excel with python and it's actually not all that difficult in the most basic sense we are just using a while loop and this is going to be well true so this is going to run forever but this while loop by itself would be way too fast so we have to slow it down and for that python has another module it's called time and this module has the sleep method and this one can well make our code sleep for a certain amount of time and this we can then use to slow down our while loop to give it a certain kind of speed and well that was quite a bit of talk let me actually implement it here we are back in the code and the first thing i want to do is to create a new method and i've called this one let's call it run doesn't need any arguments and in here i just want to run wild true and for now let's just print game and now further down in the code i can run snake dot run and if i run this we are going to see this statement printed a lot so if we run this we get um a lot of game in our output so um well at least we know it's working now the problem is that all of this runs way too fast so if we were to update the snake position every single time this one loops our snake would move something like 100 cells every second so not something we can work with so we have to slow this one down and for that we have to import another module or one part of a module and this one is from time import sleep and all that sleep really does is that it pauses our code for a certain amount of time and how long that is supposed to be is defined by our speed so essentially what i want to do is inside of this while loop i want to run sleep with self dot speed so now if we run this we can see our excel file and nothing happens for now but there we can see we have one game if we wait a bit longer we get another game and eventually we get another game and there we go this is going to keep on going the problem we have right now is that whatever integer we pass in here our code is going to be paused for that amount of time in seconds so right now we would wait three seconds for this while loop to continue which for the game would be very slow so instead what i have done is our speed is going to be 1 divided by the amount of speed so in our case right now our speed is free so our actual game speed would be 0.33 and then the higher this number would be let's say if it is 5 then the pause we'll make between each while loop would be 0.2 and that way the higher our speed is going to be the faster our game is going to run which is exactly what we want to achieve this sleep is only going to sleep our code for a third of a second so never run out of this this feels like a much more natural speed for our game so this is going quite well cool so now we can continuously update our game next up we have to get our player input and let me explain what we are going to do and actually let me run the code so essentially every time we are running this while loop i want to get what field we have selected so right now i have selected the up cell then left then the down cell then the right cell right now i have the quit cell and i want to get the position of the selected cell and then depending on where the selected cell is i want to do something in my code so if the upsell is selected i want to move my cell upwards so essentially i have to find some code to figure out what cell i currently have selected and this i'm going to do in another method and let's call this input it needs self and nothing else and to get the selected cell we need self dot book dot selection dot address and this is going to give us whatever cell we have currently selected and let me print what we actually get to see what well what we get so instead of printing the game i want to run self dot input so if i run this now we get a 1 because right now we have a1 selected but if i click on up we get d11 because d11 is the cell we are working with right now the same for quit this would be m14 and the head of our snake right now would be f5 so this is working quite well so i can close all of this and with that we are getting an error let me close it but the error we only get because we are trying to get the input while we are getting a cell so um that's just something we have to live with for now but we are going to fix this later on now this address i first want to store in a variable so let's call it selected underscore cell but there's also another problem because if you paid attention when we got the cell we didn't just get a one or something like that we always had a dollar sign between them and this i do want to remove so i'm going to add a replace method afterwards because this address is just going to be a string so we can run one string method which is called replace and replace just takes a character we want to remove in this case a dollar sign and then what we want to remove it with in our case just an empty string so now if i print my selected cell again i get a1 i get f7 e12 and so on so depending on what i have selected i am getting different kind of output and this we can then check for example if i'm on the up key i want to do a certain thing in my code so this is already working really well and again we get the error code that's kind of annoying and actually while we are at it we can implement the exit button and the exit button i want to have in a separate method so let's call it exit game it needs self and nothing else and what i want to do in here is to get my selected cell again and now really all i want to check is if selected cell is equal to self dot my exit cell so what i specified in board setup it was this self.exit cell in here if this is the cell i have selected then i want to end the game and ending the game is going to consist of two separate parts first of all i want to get myself and the book and then close it and let me actually run this this should work although it should give us an error message so now if i click on quit it's not going to work because i forgot to call this exit game in my while loop so self dot exit game and now let's try this again so now if i click on quit our game is going to end but now we're getting an error message quite a long one but let me explain what the problem here is so the problem is after we have run this code our book has been closed but that doesn't mean our code has ended and that's really important because this while loop keeps on running but now since we closed our excel book none of this is going to work anymore because we don't have an excel file to work in and as a consequence we are going to get an error message that python tries to work with excel but we don't have excel open anymore so essentially what we have to do is we have to close the while loop and this we could do in two different ways one could be we could replace this true with some kind of variable and once we are calling this we are changing this variable to false but this would mean changing quite a few things so instead i'm going to do something else and this is going to be another module so i want to get from sis import exit and if you have ever used pygame this should be a very familiar line essentially sys is a system module that you can use for lots of system functionality and exit is a command that terminates any kind of code so once you run exit you usually terminate whatever code it's run in and this is exactly what i want to do so i just want to call exit and this would end all of the code we are running and this would also include this while loop so now if i run this again we can see our game is still working now if i click on quit everything's stopping our code is finishing and we are good to go cool so i guess i can remove this comment here minimize the exit method and we are good to go now you might be asking why not combine the input and the exit game because in both cases we get a selected cell and i will come back to this at the end of the code but in the most basic sense it is really important where we are running code inside of this while loop so our game could change if we run input before or after our sleep method so if we run input here or here is going to change how our game is going to work and same with game so if we run this before or after self.sleep is going to change how our game is going to work and in the worst case it might even crash the game so we have to be careful here i'll demonstrate this later on in a bit more detail but essentially what i want to do is i want to run self.x again before we have sleep and then i get the actual input and i show you later how it's going to look if we change this it's quite a drastic effect you'd be surprised but right with that i want to actually move the snake so let's talk about how the logic of the snake movement is going to work and i could actually do this straight in the excel file so let me open it again and let me scroll in a tiny bit now right now our snake consists of three different cells let me call them one two and three and every single time this while loop is running i want to move all of this in a certain direction and essentially what that means is i want to get my first cell and move it in a specific direction that we are going to define depending on what input we have so if the input is going to the right we'll move this first cell to the right if it's up we're going up and if it's down we are going down so with that i am moving the head of my snake so let's say for the sake of the example i'm going to move my head to the right but the problem is now how can we move cell 2 and cell number 3 and the answer here is actually quite simple essentially all i'm going to do i'm going to take cell number two and move it where cell number one used to be and then the same for cell number three i'm going to move it where cell two used to be and that way even if our head were to move downwards so let's say if our head moves here eventually the cell behind it would also move downwards because it always follows where the next cell was going to be so i hope that makes sense it's going to make much more sense once i actually implement it and let's do that right now actually okay so first of all i have to get a direction and the direction is just going to be a tuple so in my init method self.direction so right now for example my direction could be zero and one and just like with our actual body positions the first item inside of this tuple is the row or well y and the second one is going to be x or the column so right now in this case we will move the snake to the right and now that i have that i can create another method and let's call it move snake it needs self and nothing else and in here i want to do a couple of things first of all i want to copy the entire body so new body is going to be self dot bar d and we just copy with the indexing operation all of the body cells so right now we are just copying this entire body now next up i want to get the position of my new hat and all i'm really going to do here is i'm going to get the first item in my snake and then add the direction towards it and this i've put in another method just to organize this a little bit better so in here i've created another method that i called add direction and this one takes new body and zero so this item here essentially and then our current self dot direction and we are going to create this method in just a second but first of all i want to get my new body again and then insert this head into it so this is going to be my new head and this new head has to be in a position of index 0 in this new body so this is going to be 0 and then the new head and then finally self.body is just going to be the new body and this way we are first moving our head in a certain direction then next up we are inserting this head in the first position of our body so this way the previously first item so the head would now become the item before that and then we are doing this for all of the cells so what we have to do now is to actually create this add direction and this is going to need self we are going to need our cell and we need a direction so these are the two arguments we passed in here already and really all i want to do in here is to get a new row and a new column and then return the row and the column and well for the row all i want to get is the cell and the first index of that and towards that add the direction and the first item of that and now i can just copy all of this and change this to a one and a one and this might seem quite complicated but let me explain essentially all we are really doing here is we first get this first item of self.body this one has a row and a column and towards that we are going to add our direction so essentially i'm going to take this row here and then add this number to it and then i'm going to do the same for the column and add these two numbers together and this is going to give me my new position of the head and this is what let me minimize those methods here and this is then what these two methods are going to do so this is what the entire method here is for and we are using this one in this line now next up then we're going to insert this new head in the first position of our snake and that way we are getting a new head and then the cell that used to be the head is now the first part of the body and well all we have to do now is to actually call self dot move snake so this way we will get the input and we'll be moving our snake however now we do have a problem let me minimize those two methods for now because the problem is we are not actually drawing a new frame all we have done so far is in our init method we have drawn the snake but after we have updated the snake we are not redrawing all of this so well what we have to do is to cut this display game elements out of here and place it inside of our while loop so every time this while loop triggers we are updating what we are displaying in our game and well now let me try all of this and we are getting an error that cell indices must be integers or slices not a list and the problem is our display games and i actually just saw what the problem is that for this new body insert it's not new body it's new head so now let's try all of this again and now we can see our snake is moving but we do have a problem that the first part of the snake doesn't disappear so let me close all of this and the problem here should actually be quite obvious that we are first copying the entire part of the snake then we are giving a new direction and we are adding a new part so we always add a part but we don't remove a part and because of that our snake keeps on growing now this is actually very easy to fix because when we get the new body we don't want all of the body instead we want the entirety of the body minus the last part so now let's try all of this and our snake keeps on growing again and that is because now we have a different problem so our snake body does work at least as long as we don't eat anything the snake body always contains free cells the problem instead what we have is we are drawing over all of these cells and after we have left the cells we don't redraw them to the background color but in reality we are just drawing on a certain field and we don't change that color back so that's something we have to work on so let me close this again and what i want to do now is i want to get the lost let's call it the lost cell and the lost cell is just going to be self.body and negative one so the one part we have gotten rid of earlier and now what i can do is to get myself dot sheet and then get my lost cell and change the color back to my board color and now let's try it off this again and there we go now we have a snake that moves properly and let me move this line of code all the way to the bottom i guess that is the most logical setup um yeah whatever works for you so now if we run out of this again the snake is looking pretty good cool so that is working very well so now all we really have to do is given on what input we have we have to change this self.direction and this happens in our input method so let me minimize the other parts and let's open the exit part again because we are going to do something very similar so in my input method all i really want to check is if my selected cell is equal to for example self dot let's start with the right cell right cell and if that is the case i want to change myself dot direction to zero and one the one we already have because by default our snake is moving to the right however now i can add an l if statement that if my selected cell is equal to self dot and let's go with the left cell here and if that is the case self dot direction should be zero and negative one and i guess we haven't done an exercise in a while so what i want you guys to do is to also add the if statement for up and down movements and that's going to be very similar compared to what we have already done all right so all i really need is another lf statement and if selected cell is equal to self that's a terrible spelling self dot let's go with upsell and if that is the case self dot direction should now be negative one and zero and finally i guess we have the down cell and if that is the case it should be one and zero for the direction and if neither of these are the case then we just keep on the direction we previously had and that is literally all we needed so now let me try to run out of this code the snake is still moving if i press down we are moving down and this works with all the different directions now right now we can also move left and right through the snake itself but that we're going to fix in just a second along with that we can also go over the apple and it doesn't really do anything but this is something we can work on but it's already looking really good so let me minimize both of these methods and now we have actually most of the game done a few more things we need is to check if the snake has hit an apple and if there's some kind of failed state so if the snake hit itself or the borders of the game field and both of these are fairly easy to do let's start with another method let's call this one check apple collision and really all we have to do in here is to check if the head of our snake is in the same field as our apple so this is a pretty simple if statement so self.body n0 is the same as self.apple position and if that is the case i want to create a new apple and now my game loop i also have to check this ideally before we are drawing everything otherwise you might get great results so self dot check apple collision and now let's try all of this again we get our game again and let me go towards the apple and there we go now we have a new apple and let me try this again just to be sure and yeah this looks pretty good now with that we have one problem that our snake is not growing once we are eating an apple but this we can fix actually quite easily and let me open the move snake so right now we are running this to destroy the last part of our snake when we are moving around and all the logic we really are going to need is that if our snake has collided with the apple i actually want to keep that last part at least for one loop of our game and that way our snake would be growing by one cell once we are eating an apple and to implement that once we're eating an apple i want to have a new method that i called self.eden and once we have collected with an apple this should be true and in our init method let's add this here self.eden is going to be false and now in our movesnade method i can check if self.eden is true then i want to grow the snake so here i want some new code and then if that is not the case so if we're just moving around i want to do these two lines of code actually let me remove the white space here so in here i can also add changing the background color because this we only want to do if we are destroying the last part however if we are not doing that then the new body is just going to be self.body and we are getting all of it and once that is the case self.eden is going to be false and well now let's try all of this and see if it's working so the snake is still moving that's looking good and if i had an apple it's growing by one cell and this keeps on working nice okay and this is then getting pretty close to an actually working game now i guess let me go through this really quick because i think the move method of the snake is the most complicated part of this tutorial but essentially all we are going to do is if our snack has eaten the apple then we are copying the entire body of the snake and to that down here we are adding one more field so our snake is growing by one cell and then we are setting all of this as the new body of our snake now if that is not the case so our snake has not eaten the apple we are not getting the entire body instead we are only getting the entire body minus the last part and then where the last part used to be we are drawing that cell in the background color so that way it disappears entirely and that way we have our snake movement logic now this is probably something you want to go over a couple of times it's getting slightly more complex but well for our purposes i can minimize this and not worry about it again now finally we need a failed state so let's call it check fail mean that our snake either collides with itself or our snake is moving outside of our game window and for all of this essentially we want to check where our head is going to be in relation to the game and the rest of the snake so for example if we are checking if the snake is going outside of the screen the player can only move the head of the snake so all we really have to check is if the head of our snake is outside of the game dimensions and if that's the case we are failing the game and the same is kind of the case to check if the snake collides with itself all we really have to check in here is if the head of the snake is somewhere in the body of the snake and that is also fairly easy to get first of all i want to be a bit more specific with my variable names so i want to create a specific head of my snag and that's going to be self.body and index 0. and then besides that i also want to get the body and that's going to be self.body and this is going to be from index 1 all the way to the end and you didn't necessarily have to declare these two variables but they do make our life a bit easier because now we have to create a pretty long if statement and first of all we want to check if the head of the snake is inside of the body and well um here python is really nice because all we have to check is if head in body and if that is the case i want to just close the game so self.book.close again and then also sys.exit and this we could actually already try so in the game loop i also want to check self dot check fail and i guess we can also put this before the display part and well let's try all of this and now here my snake is moving to the right if i press left the game ends and i just have made one error i only imported exit not sys itself so now let's try this again so now if i press left the game is just ending so we know that this is working and later on i guess i can test this a bit more thoroughly but this is all we need to check if the snake collides with itself now besides that we have to add a couple more statements i want to know if the head of the snake is too far to the left two for up two for right or too far down so essentially this is going to be four different statements and let's go through them one by one straight into code first of all let's check if the head of the snake is too far to the left and this we can check fairly easily because we know the left part of the game field ends at index zero so once our snake is on top of that we want to destroy it and well all we need here is the position of our head and of that i only want to get the column so the first one and this i want to check if this is smaller or equal to zero and if that is the case i want to end the game and of course this shouldn't be an end this should be an or so now let's try this and now let me go all the way to the left and we should end the game once we're leaving the screen cool so this is working so this is going to cover the left side of the screen now with that we can also check the right side of the screen and here again i want to check the first item of my head so the column and in here literally what i want to check if this is greater or equal than self dot width although there's going to be a minor problem but let me run this and you're going to see very quickly what the problem is so check where the game ends and the game ended one cell too early and this we can fix by just adding plus one so now if i run this again we get our snag again and i can move all the way on the right however if i go further than that the game ends so this is also working quite nicely so with that we have the left and the right side of our collision mechanic now finally we have to do the same thing for the up and the down movement and this could be a really good exercise for you so try to do the same collision mechanic for the up and the down movement it should look really similar compared to the collisions for the left and the right side since it is going to be very similar let me just copy all of this and let me edit here now for this part we want to check the first row so this one has to become a zero and everything else stays the same so we are checking the row of our snakehead and if this becomes smaller or equal to the index 0 we are crashing the game and row 0 is the first row so this should then be quite easy now besides that for the bottom part we still want to check the row and now this shouldn't be the width it should be the height and that should be all we needed so now let's try this the game is still running that's always a good sign if i go too far down the game ends and let's try the same thing by going up and this also works perfectly fine and well with that i can minimize all of this and we have a fully functioning snake game so let me play this for a while and let's see if it is actually working and i guess along with then we can also check if the snake can collide with itself properly so let's try this now and the game does indeed work cool and with that we are basically good to go now there's one important thing i do want you guys to think about and that is inside of this run loop or specifically in this while loop here because where we execute code in here really matters and i think the most obvious one is if you put the input before the sleep cycle now think about what's going to happen essentially we are first calling this input and then we are making our code sleep for a third of a second and while this doesn't sound like a big thing if i run the game now and it should start any second there we go now as soon as i press down there's always this delay between my input and my actual movement of the snake it's very difficult to see when you just watch the video but by itself this is a problem because we first get input then we wait and only then do we make some updates so this is very weird to play hence we have to keep it after the sleep part and the exit game has to be before and let me demonstrate why although it might be a bit difficult to see so now let me just quit the game and let's try this a couple of times if the exit game comes after this leap there's a potential error some very cryptic error message and the essential problem here is that we are trying to do too many things at once so here we're getting lots of input and here we are using all of that which well causes potentially problems and this is why i get something like this i'm not gonna lie i'm not entirely sure what's causing it but if you move self detects the game before the sleep part this is not causing an error so in here you do have to play around with the while loop to make this fully work but it is certainly doable but once you have all of that it's actually fairly straightforward so well with all of that we have a working game so i hope all of that was helpful and i will see you around
Info
Channel: Clear Code
Views: 5,159
Rating: 4.9836736 out of 5
Keywords:
Id: kayebcQ8pFw
Channel Id: undefined
Length: 98min 13sec (5893 seconds)
Published: Tue Sep 21 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.