Make 2048 In Python | Full Python Game Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody and welcome to another Python tutorial where I'll be showing you how to build the game of 2048 in Python now this game was one of my favorite games as a kid and it's actually very interesting to code out I won't lie to you it is a little bit complex but I think that's what we actually make a great video I'll teach you some more advanced python techniques and how you can actually structure a game like this so we'll go through all of the steps coding out the grid combining the tiles Etc and by the end of this video you'll have a fully finished game and you will have learned quite a few python features last thing to mention this video is not designed for complete beginners you should have some knowledge of python already but don't worry if you don't know pame which is the graphics Library we'll be using here anyways with that said let's dive into the video and learn how to build 2048 in Python all right so let's begin here by just walking through at a high level exactly what it is that we need to do and kind of come up with a bit of a plan before we just jump into to the tutorial so as you can see here we have a grid right we actually have a 4x4 grid so we have at most 16 tiles that can be inside of the grid now these tiles can either be twos or fours we always start out with two twos on the screen and then anytime we make a move we will add one tile to the screen that will randomly be a two or a four when the tiles have the same values and they hit each other so in this case if I go down they'll merge so you can see that we had those fours turn into Eights pretty simple in terms of the rules here and eventually you will lose the game if there's no more room on the screen to add more tiles and you can't merge any of them together now this might seem like a simple game but it's actually a bit complicated because of the movement of these tiles and making it looks smooth and animated so what we'll Begin by doing is setting up the general grid we'll draw all of the lines we'll pick the different colors we'll start being able to generate some different tiles and then what it will get a little bit more difficult is when we need to move and merge the tiles together so for now let's start by setting up the screen we want to work on actually creating this grid system that you see here and then having some representation for our different tiles so we'll pick the different tile colors Etc kind of get the drawing and hook up some of the different functions once we've done that then we'll actually go over to the Whiteboard and I'll explain to you exactly how we do the movement of the tiles and some of the more complex logic which I think is really interesting and you guys will get some value from so let's hop in to our code editor here I am using visual studio code feel free to use whatever you would like now the first thing we need to do here is install the P game module which is what we're going to be using for all of our Graphics so we're going to go into our terminal and in this case I'm on Mac so I'm going to type pip 3 install py game obviously this assumes you already have python installed now that should install the py game Library I already have it installed so I'm not going to run this command if you're on Windows you can try pip install py game if you're on Linux it'll be pip 3 install P game and if none of those work you can try python hyphen M pip install P game or Python 3 hyphen M pip install py game I also have two videos that I'll leave on the screen that will show you how to fix this pip import so for some reason it says pip is not a valid command follow those videos and they should show you how to install pame okay now that we have pame installed we just want to test this so I've opened up a new file here in vs code and we're going to start by just importing pame so we'll import pame and then we'll simply run our file and we'll just make sure that we don't get any errors here it says hello from the pame community which tells me that we are good to go okay so now that we've imported pame we'll import a few other modules that we're going to need to use so we're going to say import random and import math because we're going to need those and then we are going to say py game. anit this will just initialize all of the different features that we need now that we have this what I like to begin by doing is defining some different constants on my screen let me just make this a little bit bigger so we can read it it easier and these constants are values that are not going to change but that we'll need throughout the rest of the program so we'll Begin by writing those variables and we do these in capitals to represent that they're constant so first we're going to set the FPS now the FPS is the frames per second and this will allow us to dictate how quickly the game is running and to regulate the speed on different devices so we're going to type FPS equal 60 we then need to specify the width and the height so I'm going to say width comma height equals 800800 because I just want this to be a square we then are going to determine the row size so we're going to say rows is equal to four and columns are equal to four and what's nice about this approach here is later on we can very easily change the width and the height and we can adjust the number of rows and columns we want if we want to make the game more complex or a little bit different now the next thing we need to do is determine how large a tile is going to be or one of the rectangles is going to be that's inside of our grid so the way we do that is we'll say the with all capitals rectangular height is equal to the height of our screen divided by the number of rows that we have right in this case we have a height of 800 four rows meaning each tile will be 200 pixels tall we're then going to say our rectangular width is equal to the width integer divided by The Columns the reason we're doing integer division is so that we get an integer rather than a floating point value now there's a few colors that we're going to Define that we'll need for right now so we're going to say our outline color is going to be equal to kind of a nice gray now I've already found these RGB colors so I'll just type them out and you can copy them with me so this is 187 173 160 whenever you're defining colors in pi game you have the option to use RGB which stands for red green blue first value is the amount of red second is the amount of green last is the amount of blue these values can be in the range of 0 to 255 if we had 0 0 0 that would be black if we had 255 255 255 that would be white next we're going to say in all capitals again the outline thickness is equal to and then this will be 10 we can adjust this later this is how thick the lines will be on the screen and then we're going to have the background color and this will be equal to a different shade of gray which will be 205 192 180 don't worry too much about the colors again I already just found these next we're going to say font color this will be the color of the text on the tiles I'm going to go 119 110 and 101 for kind of a blackish grayish shade there okay so now that we've defined some of our constants we're going to create a py game window so whenever we're coding in P game we have a window the window is where we can draw objects and it's really representing the canvas of our screen so we're going to say in all capitals if I could toggle the Caps loocks button for some reason is not working okay window is equal to py game. display. set underscore modee and inside of here we're going to pass a tupple that contains the width and the height okay so this will actually create a pame window for us so again py game. display. setor mode then pass a tble make sure you don't forget the enclosing parenthesis there and by the way all of this code will be available from the link in the description in case you are getting confused or you want to copy a specific area next we're going to say py game. display. setor caption this will be the title of the window and I'm just going to call this 2048 which is the name the game okay last we have two more constants that we need we're going to have a font now a font is something that we can use to render text onto the screen so we're going to say font is equal to pame do font dot with a capital Sy font like that then we can put the name of the font I always use comic Sands we're going to put the size of the font which will'll go with as 60 for now and then we'll say bold equals true because we want the Bold version of the font lastly we're going to define a VAR variable here we'll use later called move velocity this is the speed at which the tiles will move and I'm going to go with 20 pixels per second okay so that is most of the constants that we need we Define our FPS width height rows calls rectangular height and width and then the different colors we need as well as set up the P game window just to make this a bit cleaner I'll move this down here so it's the last line we have our font and we have our move velocity and now we are ready to start coding out some more components of our game so the first thing we usually do when we're working with P game is we create something known as the main Loop now the main Loop is an event Loop that's going to run constantly and check for things like button presses exiting the screen it's essentially what will just run the game okay it's the main Loop that's handling all of the different events so we usually put that inside of a function so we'll simply say Define Main and then what we need to do is obviously call this function so we're going to go down to the bottom of the screen and we're going to say if underscore name is equal toore maincore uncore then call Main and what we're going to going to do is actually call this with the window object and we're going to take in window as a parameter here inside of the main function so we're just specifying okay where do we want to run the game well we want to run it on the window that we just defined as a variable here and if you're wondering what this does this simply means we are only going to execute this function if we are running this file directly I'm not sure if that makes a ton of sense but essentially if another file were to import this file this would not run whereas if we actually run this file directly which is what we'll be doing then this will be true and we'll run this window that's all this name equals main does just protects you in case you're reusing some functions in here and you don't want to actually run what's known as the main line okay so there we go we have main now inside of main we need to create a loop that's going to continue to run so the first thing we're going to do is set up a clock object this will allow us to regulate the speed of the loop so we're going to say pame do time with a capital. clock block we're then going to have a variable called run equals true which will set to false when we want to exit the loop we'll then say while run and we'll say clock. tick and then we're going to tick based on the frames per second which is this now this tick will just make it so this wall Loop is only going to run at most one time every 60 seconds it could run less than that but the reason we put this here is so that people that are running on different speed of computers don't have the game running at a different speed if you didn't have this clock here what will happen is you'll simply run the loop at whatever the fastest speed is you can run it at which means someone on a really powerful computer is going to see the game a lot faster than someone on a slow computer so always good idea to have this clock now that we have the clock what we're going to do is create a simple event Loop that's just going to listen for all of the different key presses and events that could occur so to do that we're going to say for event impy game. event. get this will Loop through all of the events that have occurred and we can then then check the event and handle it so we're going to say if the event. type is equal to pame dot with all capitals quit then we will say run in lower cases is equal to false and we'll break out of this Loop now what that's going to do is simply say okay if we press the exit button that's what this quit event is we're going to set run equal to false so this Loop will stop running we're going to break immediately out of this event Loop so we don't handle it and then what will happen is we'll come outside of the loop and we'll run the command py game. quit which will simply quit the pame window for us so that is now the main Loop and what should happen is if we run this code we should actually see a window appearing and if we press the x button we should be able to cleanly exit so let's go ahead and try that and you can see we get 2048 we get the window of our size 800800 and I can click exit and I cleanly exit the code all right so now that we have that let's move on to doing some drawing operations so that we can actually see some stuff up here appearing on the screen now I typically like to separate the drawing from the event handling just so it's a little bit cleaner so the way I'll do that is I'll Define a function here called Draw you'll notice that in my code I'll write a lot of functions just to make sure everything is clean readable and easy to debug and we can quickly figure out where something's going wrong by just isolating it to a specific function this is good practice and something you can kind of take note of while I'm coding so in the draw function I'm going to take a window and what I'll do for now is simply set the background color and update the screen so I'm going to say window. fill and this allows you to fill the window completely with a background color so we're going to say window. fill and then background color if we look at background color here this is what it is so we're essentially just kind of painting the entire window this color then what we can do is say py game. display. update now the way the pame works is we do all of these drawing or paint events and then as soon as an update is called we'll actually apply all of those on onto the screen in the order in which we wrote them so what that means is that we're always going to fill the screen first because what that will typically do is it will actually override whatever was on the screen by before Sorry by painting over top of it then we'll do any other operations to draw the updated screen and then we'll update and then when we do the update we'll actually see that being performed on the screen I know it's a little bit abstract right now but it's just like we do all of these paint operations then we update then they're all applied at once rather than happening one at a time so now we just need to call that function so inside of this Loop make sure you're inside of the wall Loop here at the bottom we're going to say draw and we're going to pass that window object and now we should be getting the background color on our screen so let's try this out and you can see that now it fills with the background color okay great so now that we've done that we want to start drawing the grid so to draw the grid we're going to write a different function and we're just going to say draw underscore grid like like that okay and inside of here we'll take the window object again okay so for drawing the grid what we'll need to do is we'll need to draw horizontal and vertical lines to represent the separation between tiles and then we want to draw kind of a border around the entire screen so that we get that nice border effect so let's begin with the border to draw the Border we can simply draw a rectangle that's positioned at the edge of the screen so to draw a rectangle say pame do draw. rectangle like that with re C t for this we need to pass where we want to draw it so we want to draw it on the window we need to pass the color we'd like to draw it you can see I'm getting the auto complete here so we want the outline color and then we need to pass a rectangle that represents where we should draw the rectangle so the way that we pass a rectangle is we give the x coordinate y coordinate and then the width and the height of the rectangle now the X and the Y represent the top leftand corner where we want to start drawing the rectangle from now this will get into the Pam coordinate system which I'll discuss in a second but let's go 0 0 and then width and height now as well as that we have the option to either have the rectangle be filled completely in or to be an outline so in our case we want it to just be an outline we don't want it to fill in entirely we don't want to draw a s solid rectangle Sur we want one that's Hollow so what we'll do is pass what's known as the width or the thickness so I'm going to say width and then this is going to be the outline thickness which in our case I believe is 10 pixels so before we go any further let's draw this on the screen just so that we can see what it looks like so let's go here and in our draw after we draw the background we're going to say draw grid and we're going to pass the window so let's run this now and you should see that we're getting kind of this outline it's a little bit faint on my screen but I think you can probably see it maybe not with OBS recording but I can see it at least here and we do have an outline filling the screen okay so that's how that works now actually let's run this again one thing to note here when we're talking about coordinates and XY values in pi game we always start at 0 0 which is the top left hand corner of the screen so rather than starting at the middle which is typically 0 0 it's the top left meaning as you go to the right your x value increases and as you go down your y value increases so if we look at the bottom right hand corner that would be 800800 in terms of the coordinate grid in pi game so just keep that in mind um you you'll see as we go through here how we kind of do the positioning Okay so we've drawn that now we actually want to draw the outlines uh sorry so like the grid lines right so we can start by drawing the horizontal lines so we can say four row in range and then in all capitals rows so we're going to draw a line for every single row that we have and what we need to do here is simply calculate the y coordinate of the row or of the line Sur that we want to draw so we're going to say Y is equal to row multiplied by the rectangular height now the way this will work is we'll start start with row being equal to zero and then it'll become 1 2 3 and then it will not be equal to whatever the last row is which is fine and in fact we can actually do one comma rows because we don't need to draw the very top line because that will already have been drawn by the rectangular outline that we drew anyways what we're going to do here is draw a line the line will go from the x coordinate 0o to the width of the screen and then what we'll do is adjust the y-coordinate so we're moving the line down every time the loop happens so we take whatever the height of one tile is and we multiply that by the current row and that tells us the y-coordinate for this line so we're going to say pame do draw doline similarly here to the rectangle we're going to pass a window we're going to pass the outline color and then we're going to pass zero and then y y is our Dynamic value and when we draw a line we pass the starting position and the ending position so the two points essentially for the line to be drawn between so next we're going to say width and then y so so we're constantly always going to have the line starting at 0x and with X so that way we're filling the entire screen horizontally and we're just adjusting the y-coordinate so vertically where that Line's going to be drawn now again we need to specify the thickness we're going to put the outline thickness here also known as the width of that line so now if we actually go here and refresh you'll see that we get our vertical lines appearing or sorry horizontal lines so now we can copy this exact same thing and paste it here and just adjust it for the vertical lines so we're going to say for column in range one comma calls now this is going to be column times the rectangular width and we're going to change this to be X so now we're going to keep the Y values constant and adjust the X so this is going to become X and then zero and this is going to become X and height so you can see that we always have two fixed values right where we want to draw between and then what we're adjusting is the X position whereas here we were adjusting the Y position and where we make that change is with call and the rectangular width versus row and the rectangular height now in this case the rectangular height and width are the same uh however they could be different which is why I'm doing this in two Loops because if we wanted to have actual rectangles not squares then this code would adjust to that appropriately okay so let's run this and you'll see here that now we get our grid okay so now that we have our 4x4 grid what we want to start doing is actually representing tiles in those grids and then drawing the tiles on the screen once we're able to draw the tiles on the screen then we can start moving them on the screen again uh as I said this a bit more complicated so we're going to create a class here called tile now I want to use a class just because there's some methods related to each tile which will fit nicely inside of this object or inside of the class um so it just makes it a little bit cleaner so as a class variable I'm going to specify colors now what I'm going to do is paste a bunch of colors in here I don't want to write all of them out because it's a little bit tedious and these are the exact same colors that are used in the real 2048 game now these colors represent from like 2 4 8 16 32 64 Etc so as we go up it just multiples of two or whatever double the last value is okay so that's kind of how I'm doing it I'll show you how we index the colors in a second and if you want this list of colors obviously you can pause it and type it out or you can just view the code that's Linked In the description and rather than looking everything you can just copy this colors variable okay so again in the description you can find all of the code there should be a GitHub link and just go ahead and find the colors and paste them into your code if you're following along with me step by step so next we're going to define the initialization for our tiles so we're going to say Define uncore nit uncore uncore we're going to say self value row and column now for each tile we need to know what the value of the tile is so is it a two is it a four is it an 8 Etc we also need to know its position positioning in the grid so what row is it at what column is it at and that will allow us to determine the X and Y position of where we want to draw the tile it also allows us to know what tiles we can merge with so that's why we're storing that value so we're going to say self. Val equals value and create that attribute and we're going to say self. row is equal to row self. column is equal to column and then at the same time we're actually going to set what the X and Y coordinates are for drawing this specific time so we're going to say column times the rectangular width and self.y is equal to the row multiplied by the rectangular height now how does this work well if we were in row0 column Z then we would simply start drawing this tile at the position 0 0 right that's the very top left hand corner of the screen if we were in row 0o column 1 then we would want to start drawing this from if I can calculate this correctly a y value of zero but an x value of 200 because that's where we want to draw the tile that's in that First Column when I say First Column I really mean the second column it's because in programming we're starting indexing or starting counting at zero you'll see what I mean and actually I can just run this to explain it to you like if we want to draw a tile that's where my mouse is here I hope you can see it in the position 1 one so 1 one is you Row one column one as opposed to 0 0 here then what we're going to do is start drawing it at the top leftand Corner position of this which is what we're calculating when we're doing the X and Y so we multiply the column by the rectangular width which brings us over here we multiply the row by the rectangular height which brings us here and then we would draw the rectangle in this Square you'll see what I mean as we go through the code but hopefully that's an okay explanation okay so now that we have the initialization and we have some values that we need we want to start writing some other methods related to this object so before I write all of them we'll specify what they are so we're going to say well we want to be able to get the color that we're going to draw this tile in and that's going to be based on its value we also want to be able to draw this so we're going to say self and window because that's what we need to draw and what else do we need to do we need to be able to move this so we're going to take in and some Delta which is how much we would want to move this by and I don't know what just happened there on the screen and then lastly we'll have another method called set position which will allow us to actually determine let me just pass this here what position this uh tile is currently in while we're moving the tile we'll use some of these methods later on but I just like to stub them out so we know what we're about to write so let's begin by writing the get color and the draw methods which are the ones we'll use for now so again we need to be able to determine what color out of this list of colors we're going to use for the tile and that's going to be based on what the value of the tile is so we need to have some kind of function that can essentially give us the following values so we have a value of two we want to get the zeroth index which is the first color which is what the color of the value two should be when we have the value of four we want to get index one when we have the value of eight we want to get index 2 and when we have the value of 16 we want to get index 3 so you can follow this pattern here and you can actually come up with an equation which will allow you to get this specific mapping of value so anytime the value of X or the input doubles we want to then get the next value uh in our sequence hopefully that makes a bit of sense I'm sure this is bringing you back to math class well how do we do that well we have this wonderful thing called a logarithm which will actually allow us to figure out what the power is that's required passed on some value to get some other value right I'm sure you guys are familiar with logarithms I'm not going to explain how the logarithm works and that was pretty poor explanation but we're going to say the color index is equal to the math of log base 2 of our current value now if we look at the logarithm function we can see that if we pass F of two that actually gives us one however we want this instead to be zero so what we'll need to do is simply subtract one from whatever the value of the logarithm was that's returned now just to ensure we're always getting an integer value and not a floating point value we'll first convert the result of the logarithm to an integer it will always be a whole number anyways but this will just strip off any decimal point that might be there and then we'll subtract one so now we have a function that takes in whatever our values are and Maps it to the correct index in our colors list so now that we have the index we want to access the color so we'll say color equals self. colors at the col index okay and then we will return the color like that so this now will give us the correct color based on the value of this tile okay now we want to draw the tile on the screen now when we're drawing the tile on the screen what we need to do is draw a rectangle for that tile we also need to then draw on top of the rectangle the value of the tile so what we'll Begin by doing is drawing the rectangle and then we will draw the text on top of it so we're going to say that the color we want is equal to self. getet color and this is going to tell us the color that the rectangle should be we're then going to draw the rectangle so we're going to say pame do draw do rectangle and we're going to draw it on the window what color do we want to draw it well the color that we just got and then we want to draw this at the self.x position the self.y position and with the rectangular width and the rectangular height and that's it we want this to actually be a solid rectangle so this time we won't provide a width which means it will fill in the entire rect that we provided here now that we've done that we want to generate some text that we're going to draw in the middle of the rectangle so to do that we're going to use our font object so we're going to say say text is equal to font. render so the process whenever you want to draw text is you use this font object and you render some string into a surface is what it's called that you can then put onto the screen so we're going to say font. render and what we pass for this is the value so we're going to put an F string here or actually we can just do string of self. Val so we convert our numeric value into a string so that we can actually draw that we're going to pass one for something known as anti aliasing don't worry too much about that and then we need to specify the color now the color is going to be the font color that we specified earlier now that we have the text object what this has actually done is created a surface that contains the text and now we need to specify where on the screen we want to put the text so to do that we say window. blit blit is how you put a surface onto the screen so it's a bit different than drawing the rectangles now what we pass is what surface we want to put on the screen in this case I want to put the text surface and now we need to place this in the middle of the rectangle now to place this in the middle of the rectangle we need to determine the top leftand Corner position of where we should start drawing the um what do you call this here the text so in order to do this there's a little bit of math that we need to perform I don't know if I have a drawing tablet or maybe an ink thing that I can use here on Mac let's see if there's like a drawing surface or something okay I just found like an online drawing program that we'll quickly have a look at here just so that you can kind of see what I mean so let's say we have our rectangle right kind of a sketchy rectangle now we want to draw our number in the middle of the rectangle what we need to do is figure out the location that we want to draw it in now naively you might think okay well if I want to figure out the XY position let me just figure out whatever the XY position is of this and then we'll just take whatever the width of the rectangle and we'll start drawing it directly in the middle right so you'll just take okay we have W and we'll just take W over 2 and that's where we'll start drawing it the issue is if we do that then we're going to start drawing here and the number is going to go to the right because it's the top leftand Corner that we're drawing from so we actually need to do is offset this by the by half the width of the object that we're drawing so what I mean by that is we want to draw like this right so let's say the number is kind of in this box like in this bounding box we want to find this location that's where we want to start drawing the number from so the way we actually do that is let me just clean this up a little bit I know it's very messy here we have some W right this is the width of the rectangle so we start by taking W over 2 which is going to give us this position so w over 2 we then want to make sure that the number is perfectly centered so we say okay well we have the bounding box of the number and this has some width as well we can just call this uh I don't know a okay so what we actually do now is we take a over 2 and we subtract that from W over 2 and that gives us this position here which is the top leftand Corner position of where we want to start drawing this object from so quick clarification right we go to the middle of the screen we then subtract from half the width of the object we're going to be drawing and that means when we draw the object out it will be perfectly centered in the middle of the screen the same thing applies in the y direction so that's exactly what we're going to do here now I know that was really sketchy but hopefully that's an okay explanation all right so now that we have that let's start doing our little bit of calculation here so we're going to say okay well we'll start drawing this at the self. exposition of this current rectangle and then we're going to add to that what we just specified so we're going to take whatever the rectangular width is okay because that's the width of the rectangle that we're drawing inside of and we're going to divide that by two that gives us the middle of the rectangle but now we need that top leftand Corner position so we're going to say text. getet uncore width this gives us the width of the text object and then we're going to divide that by two this now specifies that this is the X position that we want to draw now next we're going to do the Y position so we're going to say self.y plus and this is going to be the rectangular height if we can get our cap locks to work some reason my caps locks button doesn't want to work very well so this is going to be the rectangular height over two minus the text. getor height over two okay and that's all that will actually blit this on to the screen for us okay so now we have the ability to draw our tiles now also notice the order in which we did this we first drew the rectangle and then we drew the text on top of the rectangle it's important you do it in this order otherwise the text will be hidden because you'll be drawing the rectangle after so now what we'll do is call that function so inside of our draw function we're now going to take in all of our tiles now we don't yet have any of those tiles but we will create them in a second and what we'll do is before we draw the grid we'll draw all of our our tiles and that way the grid lines Will Go On Top of the tiles and it will separate them and make make it uh pretty easy to see so we're just going to say for tile in tiles and then we'll just say tile. draw and tiles is actually going to be a dictionary so I'm just going to say tiles. values I know seems a bit weird because we haven't yet created the tiles but we'll just do a quick test and I'll show you kind of how it works all right so now we have that for drawing now we just need to make some tiles then pass those to our draw function so we're going to say tiles is equal to a dictionary the reason we're going to use a dictionary is that we want to be able to index or locate all of the tiles very quickly by their row and their column so there's multiple ways that we can go about indexing our tiles or storing them but what we want to come up with is a key that kind of represents the tile and then the value will be that tile class itself that we can index in here so to do that we'll simply say the following for now we're going to say 0 0 which is representing the row and the column so like you could have zero hyphen zero but in our case we know we're always going to have uh what do you call it less than 10 or on digigit rows and columns so we just go 0 0 so we'll say 0 0 colon and then we'll create a tile now for a tile we need a value a row and a column so let's go with a value of four and then let's go with a 0 0 for the row and for the column okay so now let me just change this to give you another example let's say we have the tile 128 now we want this to be at row two column Z so that would change this to be 20 0 okay the way this works again is that we have a two-digit string the first digit represents the row the second digit represents the column and then that's associated with the tile object itself that we actually want to be representing and drawing this way we can always index a tile given its row and column and we can find it instantly inside of the tile's dictionary this is opposed as if we made a list if we made a list and we wanted to locate a specific tile we need to potentially iterate through all of the tiles in the list and check the rows and columns to find the one that we want whereas here we can always have instant access to a tile so kind of an efficiency thing that's why we've written it this way okay now we're going to pass tiles to the draw function and just make sure they draw correctly on the screen so let's run this and we go on errow it says drawing is missing one uh required positional argument window okay so we're going to go here to tile. draw and pass window all right let's rerun this and now we should get our tiles on the screen and we get them at the positions we specified right so this was what 20 and 0 0 we can do one more tile just as a test so let's go here and we'll say maybe 02 and this will be with a tile and this will be let's go 64 and then 02 okay let's run and you see now we get the 64 tile appearing in the correct position okay so that's great however we don't want to actually start our tiles with some fixed ones on the screen we want to randomly generate two tiles that have the value two that will begin as our tiles right so let's write a function that can do that let's say generate tiles now for this all we're going to do is just randomly pick two positions that we can put the tiles um in okay and we'll just make sure they're not the same so we're going to say tiles is equal to an empty dictionary we're going to say 4 underscore in range two if you're unfamiliar with the underscore this is a placeholder value that we can use when we don't actually care about the variable we put here normally you do something like 4 I in range two but in my case I don't actually want to use I I just want to do something two times so I'll just say 4 underscore in range two we're now going to say row column is equal to and we're going to call a function which is get random position and we're going to pass our tiles and then we're going to say tiles we're going to do an F string and this is going to be at row column if we can do this is equal to a tile and then this is going to be two row call we're then going to return our tiles okay let me slow down a little bit to explain what we just did so we have an empty dictionary where we're going to store our tiles we're doing something two times and what we want to do is generate a random row and a random column to place our time inside of now we want to make sure that we're only doing this for a tile that does not yet exist right we don't want to create a tile that's in the place of another tile so that's where this function will come in which we'll write in a second it will make sure when we are randomly picking the row and column we don't pick one that already exists then what we're doing is saying okay tiles well this is a dictionary so we need to set the key the key is going to be equal to first whatever the row is and second whatever the column is so we use an F string available in Python 3.6 and above which allows us to embed inside of curly braces here any values that we want to be converted to a string so we're saying okay well we just want the row and the column which are numbers they're going to convert it to a string that's going to give us the correct key and then we're going to make that equal to a tile object which has the value of two because we always want to start with twos in the row and the column okay now let's write our get random position so we're going to say get underscore random underscore pause this needs to take in the tiles that we make sure sure that we are not placing this in a position that already exists so we're going to start by saying row equals none column equals none because we don't yet know what we want and now we're going to say while true and we're going to continue to randomly generate rows and columns or a position for this tile as long as this position already exists so what I mean by that is as soon as we find a position that does not yet already exist inside of our tiles then we will use that one otherwise we're just going to keep randomly generating positions so we're going to say row is equal to random. random range and this is going to be in the range zero to rows when we use Rand range it means we'll generate up to but not including whatever the value is here which is four so we'll generate a random value between 0o and three inclusively we're then going to say column is equal to random. Rand range and then zero columns okay so we're just picking what the random position is for what it should be what we're going to attempt and then we're going to say if and same thing we're going to do an string here row column is not in and then we can just say tiles like that then we're going to break now this is another advantage of using the dictionary we can instantly check whether or not this key exists inside of the dictionary because of that property of the dictionary we have instant access to see okay does this key so does this position row column already exist if it uh does not sorry which is what we're checking here then we're going to break right so then if we break we're going to return the row and the column from the function that we generated otherwise we're going to continue to do this until this condition is true allowing us to break out meaning we found a random position great okay so now that we've done that we will go over to our main and we'll say tiles is equal to generate tiles and that should generate two random tiles on the screen for us so let's try this now and you see that we get a randomly generated tiles let's run it again we get more randomly generated tiles Etc okay so there we go we've now generated the tiles and placed them on the screen okay so at this point we've written quite a bit of code and we have the main structure of the application setup now what we want to start doing is moving the tiles around so let me hop over to the drawing tablet and explain to you that process it is a little bit complicated then we'll begin implementing it all right so I'm on the drawing tablet now and I'm going to explain at a high level what it is that we're about to do now I can't cover everything conceptually here but I'll give you a sense of how to think about this problem now if you are someone who likes these problems feel free to try to solve it on your own uh first of all but you will see that it's a little bit complicated because of the fact that we actually want to animate the tiles and we want to move them on the screen so moving them is actually the difficult part doing the merges is not so hard to figure out what the new position should be it's more about getting to that new position and how we iterate and move so that it looks smooth anyways let's have a look here so we have a few different edge cases that we need to handle and we can go through them one by one so let's say we have the number two this is our tile and we decide to make a movement to the left keep in mind all the movements effectively are going to be handled the exact same so we can just look at a case in which we're moving to the left but the exact same thing would apply if we're moving to the right there's just a few variables that change so we're moving to the left and we have this tile now there's a few things that can happen the first thing that can happen is there can be nothing to the left and we can simply shift the tile that's the easiest case right there's nothing to the left of us so we just move the tile until we hit the Border pretty straightforward we take the X position and we just shift it over and then once it gets inside of this Square here we just change the tile's position so then rather than being at 1 one it's now at 1 Z okay so that's the important thing to also keep in mind here we have an X and A Y which is the location in which we're drawing the tile and we also have a row and a column which will represent with r and C which tells us the current location of the tile in the grid so these values are linked together however while we are moving the tile the r and the column is kind of in between right for example at one point in time my tile might be in between two rows and columns in that case we don't know its exact location and we need to wait until it reaches some kind of boundary point to then reset the row and column to be the correct position based on the X and Y value so I just want to say that one more time because I understand it's a little bit confusing we're going to have a tile that's going to be moving could be up right whatever while it's moving this row and column we don't necessarily know what the correct value is so at some point we need to adjust this so that it represents where its location actually is on the screen and that's typically when the tile is no longer moving okay so anyways that's kind of the basics there so this is the first case we just simply move the dial over to the left now the second case is when we have a blocking tile that is in the direction of which we're moving so again we're moving to the left that's where we've shifted and now we see that when we move to the left well this tile exists and it doesn't allow us to move so if that's the case we just simply stay put right there's no movement that occurs for either of these tiles now it gets a bit more complicated right where we have this tile here so now in this case we move until we reach a tile that is blocking us okay so obviously I think that makes a bit of sense now the next instance is when we are moving in a direction and we have a tile that contains the same value as us if that's the case we actually want to take this tile we want to move it so it kind of merges with this tile and then we need to update the value of the tile to the left so this becomes four and remove this tile so let's kind of do an X here so we no longer see it on the screen so this is the merge instance now the thing with this is that there's kind of two stages to this merge the first stage is while the tile is actually moving into the position of this tile so to keep things looking smooth we don't just want to instantly merge the two tiles as soon as we see that they are going to merge what we want to do instead is we want to take this tile and we want to kind of move it inside of the other tile and then as soon as it's fully uh emerged in that tile is when we remove it from the screen and then we simply update this one so it now becomes the new tile value so those are those two situations right the first situation okay we know we're going to merge we need to keep moving it so it looks smooth then the second situation is okay we've already moved it inside of the other tile so now we'll merge it together so those are pretty much all of the edge cases again we have a situation in which there's no tile to our left or in the direction of which we're moving we just move the tile we have a situation where there's a blocking tile where there's no movement that occurs and we have a situation in which there's a merging tile where there's two phases the first phase is to move into the square where the merging tile is and then to merge the two tiles and remove the other tile so that's what we need to handle however doing this is a little bit easier said than done because of all the things that could happen for example let's say we have something that looks like this right we have like 2 two 2 two well what we we need to do is actually make sure that we move the tiles in the correct order such that the merges happen appropriately so in this situation where we have four twos we want to ensure that we don't accidentally merge the two middle tiles because if we were to do that we would be left with a result of 2 42 which is incorrect what we want instead although I guess you could Define this behavior however you want is that after we do this Movement we end up with two fours right so we delete delete and we have 44 so what that means is that we need to make sure that we're going to start moving the tiles from the direction in which we're moving so if I'm moving left we're going to check the first tile then the second tile then the third tile then the fourth tile and at one step at a time move them to the left rather than moving the tiles from the right first because if we move the ones on the right then we're going to merge in the wrong order so the merging order is important there's a lot of other factors we need to consider there but I think that's enough in terms of the high level EXP explanation so let us now get into the code and I'll start explaining it and again feel free to pause it Go reference some of the other code if anything's going wrong and ask any questions you have in the comments down below all right so we're back now and we're going to start handling the movement so what we'll do is we'll Define a function move tiles which is going to allow us to move them so we're going to say window tiles clock and Direction and this will be one function that will actually handle the movement of the tiles in all of the directions now we'll start by just doing One Direction dire so you get the gist of it and then we'll handle the other directions which are just slight variant of one of them right so what we're going to do is create a variable called updated equals true and we're going to create something called blocks which I'll Define in a second pretty much this blocks set is going to tell us which tiles have already merged in a movement because we don't want to be merging multiple sets of tiles I can show you an example of what I mean in a second when we actually run the code but we create this set here so that we know which tiles already had a merge operation occur so we don't allow them to merge again which means we don't get this like huge chain of tiles merging in a row which is not how the original game behaves you can obviously change the behavior if you want but that's not what I want to do here okay so now what we want to do is just handle what direction it is that we're moving so we'll just stub a little if statement here and we'll say if direction is equal to left we'll say l if the direction is equal to right and let's just do a pass here we'll say l if the direction is equal to up and we'll say l if after we pass just so that we have a stub there the direction is equal to down okay so now we're handling all of the directions the first Direction we'll go into is left so what we need to do is Define a few functions and variables that we'll use in the main kind of block of our code so this is going to seem very abstract right now when I write this out but just bear with me and I promise you it will start to make more sense so we're going to say our sort function and we're going to use something called a Lambda if I could type this so we're going to say Lambda X and then X do column now remember that we want to move the tiles when we're going left for example from left to right so the first tile we move is the one that's furthest on the left and then we go to the right and then move the tiles in that order that way we merge the correct order so we need to start actually moving from that left side so that means that we need to actually sort the tiles so that we know which tile we should move first because right now our tiles are stored in a dictionary and we're not going to necessarily have them in a sorted order so we're going to take the tiles and we're going to sort them into a list and then we're going to move all of the tiles so that's why I'm setting the key here equal to the column so I'm saying okay we're moving to the left which means we're going to sort the tiles by their column now if you're unfamiliar with this Lambda this is a oneline Anonymous function and it works the exact same as any other function so this that I just wrote right here is the exact same code as this uh oops not Funk Define Funk X and then return x.com okay it's the exact same thing it's just so you can write it in one line and you don't need to define a name for it when you don't need that name okay so that's kind of all that does this is like okay we're making a function this is our parameter and this is what we want to return from the function it only allows us one line but that's fine that's all we need okay then we're going to have reverse equals and this is going to be false now this is going to tell us whether or not we want to sort an ascending or descending order so we could actually change this to just be ASC like that standing for ascending uh or no that's going to look a little bit weird we'll do reverse instead sorry this is just again telling us okay do you want to sort in reverse order or correct order because when we're going to go in the right we want to sort again but we want to sort in reverse order so we start with the largest column Elements which are on the furthest to the right okay next we're going to have a Delta now the Delta is going to specify how much we want to move each tile by each frame in this movement function so the Delta is going to be negative move velocity and then zero so we're specifying how much in the X Direction and how much in the y direction we're going to move in this case I want to move negative in the X Direction which will move us to the left okay so reducing X moves to the left next we're going to have a boundary check now this is going to be a function again and this is going to be Lambda we're going to take in a tile and we're going to check if the tile. column is equal to zero now if the column of the tile is equal to zero that means it's already as far left as it can possibly go so we're not going to move it any further to the left because it's hit the bounds of the screen so again same thing Anonymous function just tells us okay have we hit the boundary or not next thing we need is a function that can get us the next tile so this is the tile to the left of the current tile we need to check that tile because based on its value we're either going to be blocked by it or we are going to merge into it so we're going to say get next tile is equal to a Lambda function and this is going to take in a tile and it's going to say tiles. get and we're going to say f and then row and then column minus one so what we're looking for and sorry this needs to be the tile. row and the tile. column so we're looking for or is the tile to our left the tile to our left is the tile that has a column that's one less than us now we do dot get because we don't know if this tile exists so we don't know if there's actually one to our left or not if there is one this will return that tile for us which allows us to use this indexing scheme otherwise it just returns none okay next we're going to have our merge check now this is a Lambda function again and we're going to take in our tile and our next tile now what this is essentially telling us is whether or not we should merge the tile based on the current movement of this tile because you'll see what we're doing is moving the x coordinate of our tiles until we reach a certain position in which case we then do the merge so we're going to say that the tile dox is greater than the next tile dox and then this is going to be plus the move velocity so what we're checking okay the tile that we currently have so the one that we're moving to the left we're going to check if its Exposition is greater than the next tile's Exposition plus the velocity that uh we're about to be subtracting as we move what this is telling us essentially is okay have we moved far enough left that it now looks like we're inside of that other tile if we have then we can go ahead and merge if we haven't which is actually what this is checking story then we'll keep moving the tile you'll see how we use it a second but this is checking okay are we in the position to merge or not that's pretty much what it's telling us okay next we're going to have a move check now this is going to be for when we're moving and there is a tile to the left of us however that tile is not the same value as the tile that um what do you call it that we're moving so this is going to be Lambda tile next tile and this is going to be tile dox is greater than the next Tilex plus this time the rectangular width plus the move velocity okay so why are we doing it like this now so in this instance if we're moving to the left and we have a next tile we want to stop moving as soon as we reach the border of that tile now the border of that tile is on the right side of the tile that's to the left of us so to get that position we take the next tile dox we add the width of that tile and then we add the velocity which we would be mov moving if we were to continue the move um again you'll see how this works in a second I know it's it's fairly abstract okay lastly we're going to have seal is equal to true now this essentially tells us whether or not we should round up or round down when we're determining the location of the tile after a move I know a lot of code very abstract but these are the different things that will be adjusted based on the direction that we're moving so you can imagine we're moving to the right some of these things are going to change right like the move check the merge check the sort function is going to be a little bit different the reverse function okay so that's kind of what we're doing here in terms of this and then we have some general code which we're about to write which will perform the move based on these functions so this is kind of the cleanest way to write this so what we're going to do is say while updated now the idea is while we've performed some kind of move update we need to kind of update the screen and redraw it so it looks like we're moving as soon as we're in a position where nothing has moved we're going to stop this W Loop so when no update has occurred which is what's going to be indicated by this variable here then we'll break out of the loop so now we're going to say clock. tick and then we're going to tick by FPS and we're going to say updated equals false so it's our responsibility as we go through this Loop to update this variable and make it equal to true if an update operation has occurred so now what we're going to do is we're going to sort the tiles so remember I said we need to get the tiles in a sorted order such that we're moving them in the correct um order so that we get the correct moves so we're going to say sorted tiles is equal to a sorted function of the tiles. values we don't care about the keys we just want the values and the key is going to be equal to a sort function okay like that and then reverse is equal to reverse so the sort function we defined here reverse we defined here we're now using these to sort the tiles in the correct order we're then going to say 4 I comma tile in enumerate and we're going to enumerate over the sorted tiles this simply means get the index of the tile as well as the tile object itself first thing we're going to check here is okay we want to be moving these tiles so we're doing this for every tile right we're going to check if the tile is at the boundary so if the boundary check of tile then simply continue because if we're at the boundary there's no movement that needs to occur for this specific tile so we can move forward next thing we need to do is get the next tile so we're going to say the next tile is equal to get next tile and we pass the current tile that's going to give us the tile that is in the way of which we want to move so we're now going to say okay well if we don't have a next tile so if there's no tile in our way then we can continue to move because we're not at the boundary and there's no tile next to us so let's just move our tile so we're going to say tile. move by our Delta and before I forget let's go and code out this function so move is right up here and the way we move is the following we say self.x plus equals Delta 0 and self.y plus equals Delta 1 and that's it very straightforward again if we go look at our Deltas here you can see that we just have the components of how much we want to move in this case we're just going to move backwards in the X Direction because if we add Z to the existing value here in y doesn't do anything okay so that is move now we get into the more complicated cases so we say all right well if there is a tile beside us we need to check something we need to check first of all is this tile the same value as us so we're going to say LF the tile. value is equal to the next tile do value if it is now we go into those two cases so I don't know what I just did there where we need to determine okay well if it's the same value we're either we're going to be merging with it right so we're either in the process of merging with it or we've just merged like we've moved the tile enough so we're going to say if merge check and then tile if we can type this correctly and next tile then we're going to say tile. move and then Delta so this is checking okay are we in the process of merging if we are we can continue to move the tile now if we are not then we need to do is actually perform the merge operation so the merge operation looks like this we're going to take the next tile we're going to get its value and we're going to multiply it by two we're then going to remove the tile that merged with it which is the one that we're moving so we're going to say sorted tiles. pop at index I which is the index of this tile in the sorted tiles list we're then going to say blocks. add and we're going to add the tile and we we are going to also add the next tile or sorry we don't need to add the tile cuz we just removed it we're just going to add the next tile now what this is doing here is saying okay well we've already okay so what this is doing here is simply saying all right well this tile just got merged with another tile so we want to make sure it doesn't merge again so we're just adding it into the blocks so that we can then use that set to ensure we don't do a kind of double merge operation now where we'll actually use that is right here we're going to say and tile not in blocks and the next underscore tile not in blocks when I save that we'll get the auto formatting but what we're doing here is making sure okay well if the tile. value is equal to the next tile. value so if it's the same and that tile and the current tile that we have has not merged with another tile go ahead and we can perform this operation now if it has merged with another tile we don't want to do this we don't want to merge with it so we're not going to initiate that operation okay next thing we're going to do is we're going to say LF the move check and this is going to be tile next tile then we're going to say tile. move by the Delta otherwise we're going to say continue all right so let me just quickly break this down here what we're doing is we're getting the next tile if we don't have a next tile we simply move now if we do have a next tile and that tile value is the same as this value we're going to go ahead and initiate the merge operation which we discussed now once we reach this LF we know okay we do have a x tile the next tile's value is not the same as ours so what that means is that we should move this tile until we reach the border of that next tile which is what's checked by this function so we move until this is false right until it you can no longer move we're going to continue to move otherwise if none of that is true then we just say continue and what that means is we're not going to do anything and when we don't do anything no update occurred so now we're going to go down here and we're going to say updated equal true so unless we were in this case or we were on the boundary we're going to reach this variable and we're going to say update equals true and that's going to tell us to initiate another loop here and continue the movement process because something did actually move as soon as this variable never becomes equal to true we stop the W Loop and we exit now there's a few other things that we need to do but that's a good start to our function all right so let's continue here as I was discussing while we move these tiles their row and column are going to be adjusted based on their X and Y position so based on where they're actually moving in the grid because as they move uh enough then they're going to be in a different row and a different column so we need to actually adjust that so to adjust that we're going to use this if we can write here set position function now the set position function or method whatever you'd prefer to call it is is simply going to look at the current X and Y position of this um what do you call it tile and then adjust it sorry adjust the row and call based on that X and Y position so we're going to say seal is equal to false and this is a variable that's going to tell us whether or not we should round up or we should round down which is going to be important based on the direction in which we're moving so we're going to say if ceiling so simply if we're rounding up then we're going to say self. row is equal to the math do seiling which is always rounds a value up and then we're going to take the self.y and we're going to divide that by the rectangular height so let's say the Y position is 600 right we're going to take six so let's say the Y position is 599 we're going to take 599 divided by the rectangular height which is 200 that's going to give us like 2.9 something we're then going to round that up to three telling us that we are currently still in the third row okay we're now going to say self. column is equal to math do ceiling self.x divided by the rectangular width and then for the else so if we're not rounding up we're going to round down so we're going to say self. row is equal to math. floor and then the exact same thing here right so this is going to be the Y value and then self. column is equal to math. floor self.x / by the rectangular width okay so that is just going to adjust the row and column as we move and what we're doing is we're essentially with this determining at what point will we move to the left or to the right that we want to set that row column value so when I go with ceiling that means as soon as I move fully past the bounding line or I'm right at it then I'm going to adjust this as I'm moving to the left whereas when I'm moving to the right it's actually going to be the opposite um because of the kind of directions in which we're moving it's it's difficult to explain this but you'll be able to see in the code here how we change this based on if we're moving to the left or to the right so that we know what row and column we're actually in to check for the next tile okay so now what we'll do is we'll go over here to updated and either before after updated doesn't actually matter the order in which we do it we're just going to set the tile position so we're going to say tile do set position and we're going to pass that ceiling value which we find here so we're moving to the left ceiling is true we're moving to the right it's going to be false okay now this is all good however you'll notice that we removed some tiles but we only removed them from the sorted tiles list now this is not actually where all of the tiles are stored it's just where they're temporarily stored while we're in this updated Loop so what we actually need to do now is adjust the tiles object itself which is passed in here to remove any tiles that were then removed from the sorted tiles um and to kind of adjust them so what we're going to do is inside of the wall Loop here but outside of the for Loop so make sure you have that indentation correct we're going to say update tiles and we're going to take the window the tiles and the sorted tiles now all this is going to do is essentially Loop through our tiles and it's just going to remove any of the sorted tiles that no longer exist from tiles so we're going to say Define update under _ tiles and we'll take in the window the tiles and the sorted tiles like that and we will go ahead and write that function so the way we can do this is we can just start by clearing all of the tiles so we're going to say tiles. CLE just removes everything from the dictionary and then we'll just say for tile in the sorted tiles and then we're going to say tiles and we'll create an F string again okay and this this is going to be tile. row tile. column is equal to the tile that's it and then we'll just do a draw operation here so we can actually see what's going on and we're going to draw the window and the tiles so update tiles is going to as I said update this tiles dictionary so it only contains the ones that are actually still there and it's going to draw all of the tiles on the screen as they move so we can actually see that movement operation occurring so I think that's okay last thing we'll do here is we're just going to call something known as end tiles now notice that this is happening outside of the wall Loop so as soon as we're no longer updating any tiles we're going to call this function so we're going to say Define end tiles like this this is going to take in the tiles and what this is going to do here is just check whether or not the game is over uh and kind of do that last cleanup operation so what do we want to do here actually let's call this end move cuz that makes a bit more sense okay and then inside of here we're going to say if the Len of tiles is equal to 16 then we're going to return lost so if after we did a move we have 16 tiles uh that means that we can't move anymore because the en entire board is well full of tiles uh and that way we lost so we'll just say we lost and then we can handle that later on if we want and then what we also want to do is we want to add a new tile to the screen right so every time we make a move a new tile gets added so we're going to say row column is equal to get random position and this is going to be tiles and then we're just going to say Tiles at the F string of row column is equal to tile and then what we need to do is randomly select whether or not we want the tile to be a two or a four so we're going to say random. Choice and then in an array two four just randomly pick between two and four then the position is going to be at row column and we'll just return continue so we know know that we can continue the game now from here we're also return and move and then what we'll do is we'll just go to main here and we'll actually start calling these functions that we wrote and then if we get a like end game returned then we'll simply end the game right we can send a message to the user we can do whatever we want in fact I'll actually let you guys handle that but we'll talk about that in a second okay so we've now handled moving left the other movements will be fairly straightforward I know that was kind of complicated let's actually test this though so what we want to do is we want to check for the different key presses right so if you're pressing Left Right Etc so we need to first check okay did we press a key so to do that we're going to say if event. type is equal to py game. key down so did we press a key down if we did we're going to say if event. key is equal to py game. Kore and we'll start with left so if we press the left key then we're going to say move tiles and we're going to pass window TI clock and the direction which is left okay so we're checking all right did we press key down if we did let's check the key that we pressed if it's equal to K left which is the left Arrow key you can also do like k a if you wanted to do the a key so Kore a but in our case we want the left Arrow key which is denoted by this then we're going to call the move tiles function pass the window pass the tiles pass the clock pass the direction of left let's copy this four times and handle the other directions Okay so if the key is right then we just change this to be right in lower cases otherwise we'll do up and down and then adjust this so that's up and that's down okay so now we have all of the directions however only left is going to work right now so let's go here and let's move left and you'll notice that they merge together and we saw a new four got added to the screen now when I press left you'll see that even though there's no movements happening a new thing will add onto the screen and you can see that as we move them they will move and they will merge accordingly okay so we can only currently move left and you'll see that now at this point the game's over because we can no longer move or merge any more tiles although I guess we could go up or down or whatever but in this case that's fine okay so that's it for left now we just need to handle the movement in the other directions and then we're done so to move in the other direction we pretty much just need to copy all of this and then adjust it for the different directions so let's go with right now so we're going to copy all that and paste this inside of here so to move right is going to be very similar we're going to keep the column key the same we're going to change this to be true because now we want to sort in reverse order the Delta now is going to be positive so moving in the right direction and the boundary check is going to be if the columns is equal to column minus one because that is going to be uh the kind of right boundary right if we're equal to whatever the number of columns is minus one well then we're in the last column now getting the next tile we're just going to add one not subtract one and now the merge check will look a little bit different so here we're going to change the sign to be less than and we're going to subtract the move velocity cuz now we're moving right and now for the move check again we're going to need to adjust that as well so this is going to be tile dox plus the rectangular width plus the move velocity is less than the next tile dox okay so we kind of just flip this around again because we're moving right that should now handle right and then we're going to say sealing is equal to false because we actually want to round down when we're moving to the right side okay let's run this and let's check left and right so we can now move to the right and we can merge as well as moving to the left okay looks pretty good obviously we could you know make the movement more fluid but I think this is actually pretty good so far okay let's see what happens if we go and merge and you see now that game is done all right so let us now do the up and the down okay so how do we do this well for up we're going to copy the exact same thing and actually we'll copy it from left because it's going to be a little bit more similar to that one and paste that here now for the sort function we're now moving up and down which means rather than using the column we're going to use the row now for reverse this is going to be false as well and for the Delta we're going to change this now so it's going to be zero and it's going to be negative move velocity because we're moving up in the y direction for the boundary check this now will be row not column so if we're at the zero with row that means we're at the top of the screen and when we get the next tile we're looking above so it's going to be row minus one and then the call will stay constant for the merge check now it's going to be similar but this time we're moving up right so rather than using X we're going to have to use y so we're going to say tiley is greater than next tile. Y and then this will be plus the move velocity for the move check similarly again we need this to be y so we're just going to adjust this so that rather than uh X it's Y and we're just going to change from rect width to rect height okay if we're sealing that's going to be true as well and now we're going to copy this and we're going to do the same thing for down okay so down this time reverse is going to be true cuz we're moving downwards the move velocity is going to be positive the boundar is going to be rows minus one when we look at the next tile we're looking down a row so we're going to add one and for the merge check again slightly more adjustments here so we're going to say tile. y we're going to change the sign and this is going to be less than the next tile. y minus the move velocity and for the move check same thing it's going to be next tile doy we're going to change the sign and and we're actually going to take this and we're going to put this on the other side okay so we're going to go like that plus the recti plus the move velocity less than the next tiley and the ceiling is going to be false okay now if we run this we should have a finished game so let's go ahead and do this and you can see that we can move up we can move down we can move to the right and we can merge our tiles and we can play the famous game of 2048 I don't know if if I quite know the strategy maybe as well as some of you guys but there you go functioning game now as I kind of play through this I will mention that there are a few like kind of tiny little bugs or things that you could adjust here for example it doesn't handle when the game is finished that's actually something I intentionally wanted to leave for you as homework we already kind of set it up so it should be fairly straightforward to add it and there's a few other like kind of small movement things that you might notice if you play this a long time but overall I think it's pretty good and it's not really worth it to fix them right now because it will add a significant amount of time to the video and I think most of you are going to be pretty happy with this implementation that we currently have now another thing to note is that if you get too high up you're going to run out of colors so if we look at this here I only added uh my quick math is what like 10 colors nine colors so that means we're only going to be able to go up to two to the exponent 9 or actually I think two the exponent yeah two the exponent 9 so you're going to need to add some more colors if you want to handle larger values than what ever two the exponent 9 is I don't actually remember what that value is so uh you can add more colorss you'll see that you'll get an index error if you go above that value but that's a pretty easy thing to fix okay a reminder all of the code will be available from the link in the description I hope you guys enjoyed this video if you did make sure to leave a like subscribe to the channel and I will see you in the next [Music] one
Info
Channel: Tech With Tim
Views: 36,378
Rating: undefined out of 5
Keywords: tech with tim, python tutorial, pygame tutorial, python game development, tutorial, 2048 game, python, how to code, 2048, programming, Python Game Development, 2048 Game Python, Tech with Tim, Python Tutorial, Game Programming, Python for Beginners, Full Game Tutorial, Python Projects, 2048 Game Tutorial, Coding 2048, Learn Python, Python Coding Tutorial, Python Game Tutorial, Building Games in Python, Python Programming, Create 2048 Game, Python Game Design, Coding Tutorial
Id: 6ZyylFcjfIg
Channel Id: undefined
Length: 75min 52sec (4552 seconds)
Published: Tue Apr 09 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.