all right hello world this is cs50 live
my name is Colton Ogden in case you're
tuning in and you're not sure what cs50
is cs50 is Harvard's intro to computer
science taught by David Malin and this
is sort of our offshoot livestream
format but if you'd like a more
traditional introduction to computer
science as taught here at Harvard
University definitely check out our
youtube channel youtube.com slash cs50
where you might actually be watching
this video now and check out David's
lecture series we do a lecture series
every year but check out the latest one
or go back in time if you want to see
some of the earlier p-sets and other
lectures that we did but anyways this is
a separate sort of series from that this
is where we do live programming and we
talk about technology and do all sorts
of other things and today in particular
is part 3 of a series that we've done
recently on a game called 2048 which is
a sliding tile game and we're
implementing this in Lua and love 2d and
so shout out to all the people that are
live in the chat there bella cares juban
3 i saw a few other folks beforehand but
I think the the twitch chat it got
refreshed because I brought it up op out
my name but say hi if I didn't shout
your name out and I will say hi back I'm
gonna switch over to my laptop screen
here like this and interestingly it is
wait why is it showing up like that that
is weird it is an outdated screen for
some reason unless I am ELISA I'm just
trippin uh-oh is it set to a second
monitor that might be it hold on one
second let me just confirm that that is
indeed the case displays am i not
mirroring displays I am marrying
displays why is it being weird like that
it got fro error sorry let me just
unplug that and replug it in it looks
like it got messed up when we were
testing things out give it a give it a
sec and that looks more a queue up and
now it's not mirroring displace because
I think I turned that button off so let
me get let me unseat it again let me hit
mirror displays and where is that at
it is displays color mirror options in
the menu and available this is this is
whack sorry everybody going to we start
off so strong and then and it just kind
of got destroyed there because my
he's an HDMI connection got really wacky
gather windows arrangement mirror
displays and if we're lucky
everything should now be mirrored
awesome so what I meant to but I meant
this segue to was they love 2d sort of
website here because this is the game
framework that we're using to implement
2048 and if you're tuning in now it
might be better to tune into the prior
two streams on 2048 just that you can
see where we've come from from the very
beginning we implemented sort of the
grid on the first stream a little bit
and then the second stream we got to the
actual numbers sliding and then
combining together and today we're gonna
actually take everything to the very end
and talk about getting the numbers to
properly combine and move around and
then also calculate winning and losing
and also sort of deriving an arbitrary
score formula where we've taken to
consideration how many times the user
has made a move before they've gotten to
the number 2048 and I did a little bit
of prior work on this just to prevent
this from going into a part four and
wrote in advance a sort of series of
notes here and actually a separate
github branch so if we go over to the
repo I'm gonna actually go to my
terminal here I'm gonna LS I'm gonna do
a git poll because this repo is a little
bit out of date and I should now be able
to get checkout complete which I'm
already on it turns out oh I might have
actually done this in advance and if I
go ahead and run this in my editor which
is here just make sure I'm in the right
place run this should be able to move
everything and it actually I think it's
not even I don't think it's currently up
to date yeah no this doesn't look
accurate for some reason so let me go
ahead and get status or you get log
action just make sure that this is the
right Oh interesting it didn't actually
pull the correct it didn't actually pull
the correct stuff so let me go ahead and
get check out or get fetch and then get
status
I should have probably tested this in
advance yeah this this is for some
reason nah it didn't actually pull the
code from github so I'm gonna I'm gonna
just pull the repo completely see you
can see stable moving and combining them
as was my last commit so what I'm gonna
do is I'm gonna actually just fresh
clone this I tested this on my other
account not actually my test account and
then I zoomed to get pull was going to
work but it doesn't look like that's
actually the case so I'm going to CD
backwards and I'm just going to delete
this go ahead and get clone if you get
clone the repo now from github it should
just work automatically and then I can
check out complete actually have to CD
into it first 2048 get checked out
complete and complete is not a accurate
sort of word to describe this branch it
is the combining of numbers is complete
but rather the branch name was just to
sort of be farther ahead than the stream
itself and we will be today sort of
working backwards from the well we'll be
working backwards as much as we'll be
looking at the prior code from last week
and sort of getting it up to date with
what's in complete the branch if you're
not familiar with github and get
branching branches are sort of two
different alternate paths that your code
splits off to when you're programming
using git which is a source control a
form of source control and the master
branch is usually what's ever in
production so you have sort of your your
main sort of timeline of git snapshots
you know where you've sort of saved your
code you can always revert back to a
prior snapshot or commit that's your
commit history and branch is sort of
deviate from the master branch and they
sort of are all sort of like alternate
timelines almost and you can switch back
and forth between them as you want to
and then even merge prior branches into
the master so you can actually have that
branch up or below your your master sort
of come back into master at some point
and then become part of your production
branch and I created a separate branch
just so that we could go back to the
prior code from last week while also
having a sort of firm point at which we
know we're working to
words if that make sense so I'm going to
now open up the code I'm going to quit
vs code and I'm going to reopen the repo
in vs code here which now if we go to
main dot Lua and we go to the very
bottom we'll see that things have
definitely changed you can see that I've
actually brought out a few of the
functions separately from the all those
individual move up move down move left
move right commands I've taken out some
of the code that was common to those and
we'll take a closer look at this one we
were in fact revert back to the main
branch but it's allowed me to shrink
down the functions the move functions to
not too long still a bit long I didn't
spend enough time to actually turn this
into an abstract function that would
take care of all directions in one
function but you could visualize you
know possibly a way to do that certainly
with enough work but here are some of
the the small functions that last week
we actually separated out merge tween
and was it merge tween and maybe a move
tween I think it was these two functions
and I added make merge and make move
these were just blocks of code that were
in the move up move down move left move
right functions but were repeated and I
just basically parameterize them a
little bit just to make it a little bit
easier so if I run this code now if I
move everything you can see that it does
behave correctly which is nice so it
does there is a part of this where it'll
actually if there are three like numbers
on the same row or if there are two like
numbers that mix together and then the
that larger x - number is to the left of
those or wherever and they all move
together it will combine up to three
numbers there there is a way to protect
against that but currently the code does
not support that but we could we could
we could add that without too much
difficulty but you can see that it does
work now all of this stuff is nicely
mixing together which is nice so you see
right there it happened here at the very
bottom there was a four there were two
twos and a four here so the two twos
mixed into a four and then that four
mixed this into an eight now
on your philosophy maybe that's a
feature and not a bug it's kind of a bug
if we're looking at it from the
perspective of the original code base
because I don't believe the original
code base worked that way but all we
would really need to do is set a flag on
that tile to say that it's already been
involved in a mix operation so we could
set the flag to maybe mixed equals true
and then when we actually test for that
merge we can say if the tile that we're
merging to or we potentially moving to
dot mixed is equal to true or false then
merge accordingly so we can say only
merge if mixed is equal to false and
that would prevent the behavior that
we're just that we've just observed okay
so let me just go ahead and read guy
white says morning Colton will you be
facilitating cs50 gaming at Harvard
summer this year thanks for these
learning so much I will be yeah course
instructor for that for the gaming
course this summer yes if that's what
you mean if there is another meaning to
that I definitely do do write that in
the chat
Nadya says hi Colton how are you I'm
doing great thank you very much feeling
uh feeling pretty sprightly M
Cloppenburg hello everyone berries and
cream says hello
Abhinav three three nine eight says yo
hello Abhinav good to see you and yeah
so this is what I did last night
to get us sort of up and running oh jl
97 says love the podcast awesome thank
you so much we'll be releasing another
episode very shortly potentially even
today depending on we're basically
waiting for the RSS to spread up to
Spotify and iTunes so whenever that's
all done we'll we'll pub the next
episode of the podcast but yeah that
one's good I think this this last
podcast episode was pretty good and
we're filming another one tomorrow
actually did I push these changes to get
up as well I did so you'll see all of
the changes in github and specifically
these are located in the complete branch
which is right here so if you want to
download all this code clone it as
normal and then run the command that I
did which was get checkout where did I
do it complete right here so that will
actually switch you into a branch if it
already exists and if it doesn't exist I
believe you have to actually do it get
check out or get branch
and then the name and that'll actually
come that'll take your existing code and
create a new branch but named that
that's that you can then develop in and
it won't affect your master branch your
main production branch so to speak but
yeah that's cool yeah it works
everything is great and this gives us
the framework now upon which we can
start adding checking for we can check
for whether the user is unable to move
we can check for one of the numbers
being equal to 2048 we can check their
score so on and so forth but we'll walk
through the code that I implemented last
night and however find it and then we'll
add those additional features after
that's all taken care of and in order to
do that the first thing that we'll need
to do is actually go back to master so
all I have to do is get checkout master
and then what will happen is you'll
notice that the code is now the more
complicated worse code that it was last
time last week so we'll work through
that I added a quite a bit of
refactoring to this in order to shrink
it even though it's not completely ideal
it's still much better than it used to
be so if anybody has any questions let
me know otherwise we will dive into
looking at how I fixed up the sort of
functions that we're using last time and
thankfully I have some handy-dandy notes
here so that I can remember exactly how
I did it the downside to doing some of
this stuff live on stream is that
especially for the more complicated
stuff it doesn't get engineered the most
efficiently and so we end up we end up
sort of coding and not the most ideal
way however it's a nice opportunity for
us to look about reef look at
refactoring code two so there is a plus
to it I suppose
and it also kind of depends on my mental
state that day if I'm actually capable
of thinking well earlier in the day I
tend not to be as good as I am in the
evening so I did all this like last
night at like 1:00 in the morning
so I was actually pretty sharp but
that's that's just me different people
are gonna some people work well the
morning some people work well in the
evening I tend to work well after the
day is
gun bye usually okay alright well if
there are no questions we can proceed to
the actual refactoring of the code and
sort of one of it one of the first
things that I did was I actually noticed
well it looks like we have a little bit
of work to do here because I don't think
we actually have no we don't have some
of this isn't actually refactored out so
one of the things that we need to do is
there's a there's a few there are a few
little small functions that should be
refactored out let me just make sure I
have my notes here sort of in order and
a couple of those functions are the
actual merging and the moving of the
tiles you'll notice that for example
this code and sorry you know this code
and this code sort of what we're setting
and clearing the tiles and where we're
actually doing the tween operation and
then same thing with this code here
where we're doing this merging and I
actually thought that we did this last
week the separating out of the merging
of stuff so I might be tripping a little
bit Oh unless I didn't oh you know what
it might be I think I might not have
committed those the last couple changes
actual merging of the tiles and moving
of the tiles so that's okay I mean we
have again we have the completed branch
to go up to so if worse comes to worse
we'll switch over to complete and then
we'll add the features rather than try
to reverse engineer but I'll talk about
all the code that I did and we can at
least understand how everything works
then we'll add well add layers on to
that so one of the first things that we
probably want to do there are a few
functions like I said related to the
moving and the merging so I'm gonna
write a function here called merge tween
this is the this is the actual merging
stuff here so this right here where
we're actually sort of adding a tile
what we're doing is we're moving a tile
removing a tile that's you know if we're
moving up it's one of the lower ones
left right up or whatever and we're
moving it to the new tile that's the
same number but where do
leaving the old tile and we're just
multiplying the other tile by two right
source and specifically one of the
things that I realized is that in order
to get this working we need to change
its number right away so that two twos
don't merge into the n/2 because they
think it's the same number we have to
actually set the internal number right
away
two times two but we need to keep it
displaying the original number so it
doesn't switch to four right away for
example it still waits until that merge
finishes right which is the behavior
that the original game sort of has so we
need to do is keep two numbers inside of
the inside of the tile data structure a
number the actual number that it's
holding inside of itself and then the
number it's displaying so I called it
displaying them and so what we needed to
end up doing for that is actually going
into here and adding to the tile class a
self displaying them which is equal to
its own num by default and then we if we
ourselves set display num and them later
on in the merge function down here in in
main.lua
and let me just go ahead and finish
writing this tween so this will take a
tile and it's essentially going to be
this code here but a little bit more a
little bit different so I'll just write
it out here so what we do is we get a
tile first if I'm doing this correctly
all right yeah yeah so we get tile dat
tile X and then tile tile Y dot num and
then this is what we're doing we're
setting that equal to x two right so
this is that so we're merging towards
the tile that we care about right which
we pass into this function well that
will end up passing that into this merge
tile function so we're sending the
actual internal number the value of that
tile which allows us to calculate
whether the towel should merge into it
or not but we're not adjusting the
display number yet so that it'll still
stay safe
for example it'll still keep the number
two displayed on the front and I realize
one crucial piece of this is in the
actual tile down low we need to set this
to
splain um to render the display no I'm
not the actual number right and then
after that we can do our usual timer dot
tween we're doing it over the span of
1.1 seconds and then it takes in a an
object a table and it's gonna take the
tile right and it's going to set its
grid equal to grid grid tile that tile Y
tile that tile X dot X and then Y set to
grid grid at tile dot tile Y tile dot
tile x dot y right so that's this is
between object sort of the list of key
value pairs at which were tweening the
Vella the object towards so we're taking
the tile object and then we're tweening
the the Quran that we care about in this
case the X and the y so we're taking the
tile we're tweening its X towards this X
the tiles Y and tile xx the actual grid
part of it and then we are after that
what we do is we wait for that whole
tween to finish before we set the
display number correctly so when our
finish takes in a anonymous function to
execute once it's done so once the timer
has actually tween it's done its thing
over the span of 0.1 seconds it's going
to execute this block of code so it's a
function on the timer dot tween object
timer and up tween actually returns an
object that has functions associated
with it which is pretty cool
and Adam to answer your question between
the library is knife so there's a knife
and it it has a timer function within it
so it's err struck slash knife err
struck knife whoops I spelled it wrong
err struck knife right here it's
specifically the timer module within the
knife library and Adam also said work
for to work for two 12-hour shifts the
past couple of days not happy happy to
be
I well I'm glad that you happy to be
here I'm sorry they were to 12 power
ships that sounds pretty miserable
Hugo says a quick question if you had to
make and publish a 2-d game would you
prefer to develop it in love 2d or unity
2d that's a good question
it depends on the game I really like
love 2d and I feel like I have more
control over certain things in love 2d
but unity is pretty good unity has more
coverage for platforms than Lua and love
to do well then lived love 2d does for
that reason I would probably use if I
were going to go super commercial and I
wanted it to be available on like the
switch and like all over the place I
would probably try and fit my code base
into unity somehow and do it that way
and I also as an intellectual exercise
would like to get more acquainted with
unity
I think unity is a pretty cool platform
that said love has an appeal for me
personally and so I I find it more
enjoyable to program with love than I
than I enjoy programming and unity so
far that might change in the future I
haven't done a lot of 2d game
development with unity which is a big
part of that it's a little bit harder to
do certain things I remember having a
tough time getting pixel perfect retro
resolution working in unity but I was
able to get it working in love with the
help of a library very easily and it was
amazing so it has a special place in my
heart but I think honestly and
pragmatically unity would probably make
the most market sense so that's probably
where I would say I would say probably
probably learned that unless you like
the API for Lua and for love 2d and you
want to get involved with that
where were we right we were back at the
code we were writing this function here
so once it has actually finished
tweening we want to set can move equal
to true so what happens is can move get
set to false use usually and actually
let me see oh right this this actually I
think gets set into a different function
I make AI made
a little function here which actually
calls the merge thing so we're actually
not calling merge anymore the merge
tween function anymore from within the
move up move down left right move
forget move the left move right move up
move down we don't call merge tween
anymore so we're actually going to make
a second function that takes in this
information and then calls this code
here
well the between itself so that was one
of the other changes three factors that
I made to the code base it actually made
sense because I was able to parameterize
it a little bit also land mining thank
you very much for writing appreciate it
and Hugo you are welcome the was I
saying the merge tween we're just making
a function for the tween operation
itself we're not really concerned about
the game logic but this function as much
so I'm gonna set can move but we aren't
concerned about a couple things so once
the tween is finished we're setting can
move to true remember can move is the
flag that lets us actually perform tween
operations that lets us actually move
tiles left right up down though chuka
nice and hello land mining so when we
said can't move back to true remember
can move at least in our is it here I
think it's here it's this flag here
which allows us to actually test for the
key being up-down and left-right in our
key pressed callback function and so
this is an important thing this
essentially pauses our input when we set
can move equal to false so when we're
finished with the tween we set it equal
to true and then what we do after that
is we call get tile again now this is
where we're actually taking the display
numb remember we we edited the regular
number the internal number that that is
responsible for the math for the
combination of tiles but now we need
it's time for once the tween is finished
to actually update the display number so
to actually change what's being shown on
the tile itself which is important so we
kind of do the same thing that we did
before we're going to do tile a tile X
tile that tile Y and we're going to grab
the display number and we're gonna set
it equal to the same
thing tile that tile ex tile tile why
and then we're gonna set that equal to
the number the internal number so
essentially just doing an update we're
taking that tile and we're setting it
equal to its internal number and then
once that is finished with we can say
tile dot remove is equal to true and
grid remove deleted tiles now I believe
this is this part we've already done in
the last yeah we already done that this
just clears the tiles from the grid from
our second table because remember we out
we can have two tiles that are
potentially or rather tiles that are not
actually part of the grid but are still
existing while they're tweening
right because essentially what we do is
we take the tile when we move it we
remove we clear its prior space and but
while it's merging it still exists right
because it's still moving towards its
destination but all we end up doing is
keeping the tile at the destination and
then after the tween we just multiply
its number by two right so we're not
actually getting rid of the tile from
the grid oh well we are getting rid of
the tile from the grid but we're still
maintaining a reference to it so we can
still move it and we can still see it
right we don't want to delete it because
if we delete the tile we won't see it
Twain it'll it won't exist it'll be set
to nil so that's why in our grid we
actually have a separate tiles table
here which is responsible for keeping
track of the references to the
individual tiles HDM Town 97's is hi
from Vietnam hello HDM good to see you
and berries and cream duck purple rocks
thank both of you for the follow missed
that earlier so let me go ahead and
clear our clothes out the grid class
this is our merge tween function now we
also need a move tween function so this
this happens when we don't actually
merge but we do still move the tile so
in this case we're not doing any of the
number calculations we're not
multiplying the number by two we're not
doing any of that but we are moving a
tile from one spot to another spot and
we're tweening it in the process and in
order to do this it's essentially just a
timer tween zero point one and we take
an object and then we set tile equal to
X being equal to grid grid tile that
tile why tile that tile X X and then
we'll just go to another line down here
let's set y equal to grid grid tile tile
Y tile tile x dot y boom and then after
that again this see this right here
we're not actually setting like we did
in this other function we're not setting
the number x 2 because we're not doing
any combination we're just moving one
tile to another this is for example this
is if a tile moves to an empty spot at
the end of the grid or before another
tile that's not the same number so just
moving from one spot to another spot
most we finished we have a callback
function this callback function in this
case we'll just set can move equal to
true very simple compared to the merge
tween function and then we'll be able to
go back here remove a lot of these
functions and remove a lot of these
redundant blocks of code rather and then
shrink down our functions now the a
couple of the other functions that I
ended up doing to actually abstract on
top of these two where a function called
make merge like this and you'll notice
that for example before we actually do
the merge there is a lot of this code
and then before we make the move there's
this code without the print right but a
lot of this is all redundant we don't
need any of this stuff and Adam for Adam
fighter hello good to see you but a lot
of this is redundant and we can
parameterize it we can we can abstract
this out into functions that just take
arguments and then reduce these six
lines or however many lines of code down
into just one function call and this is
a big part of what shrinks down the code
base ultimately it makes our up-down
left-right functions a little bit
smaller so if I say make merge is gonna
take in a tile it's gonna take in an old
X and an old Y as well as a new x and a
new Y right because the merge is going
to actually it's gonna do the it's gonna
clear the old tile and then it's going
to set the old tile to the new X new Y
or rather it's going to multiply
it's gonna do a merge on the new X and
the new Y right so what we do is we say
can move equals false so this is one of
the for example one of the lines of code
that was up above in our up-down
left-right functions remember this
prevents us from actually entering in
keyboard input so it's just setting that
flag which you can see remember after
the merge is done or the move is done
this gets set to right here it gets set
to true again so we can move again right
so we said can move equal to false we
then set tile tile X equal to new X and
then remember tile X and tile why are
the grid coordinates not the actual x
and y coordinates the X and the y
coordinates are tweened remember we do
that here we actually we set the grid we
we figure out you know the remember the
grid maintains an internal reference to
those pixel coordinates we calculate
those in advance I believe if we pull
that up we can actually see that happen
here and initialize grid we do all of
that here remember we take into
consideration the padding the window
width window height grid tile size blah
blah blah every grid spot maintains an
XY position that we then set tile we we
reference it here we go we in our in our
actual tween we set the X and the y of
the tile to grid grid that internal grid
at Y X and then we get the actual x
pixel value and Y pixel value here so
that's what that that's what's going on
there
so we said tile a tile a tile x2 new X
and tile that tile y equal to new Y
right because it's going to move to that
new tile coordinate that new grid
coordinate specifically so this is
between 1 & 4 and then when we index
into new X new Y on the grid and we get
dot X and dot y that'll be an actual
pixel value and then after that we say
grid clear tile old X fold why because
when we're merging we take the old tile
we essentially get rid of it but we
maintain a reference to it and we tween
it to the tile that we're merging into
and then once that's done we flag it as
deleted here as you can see we set it to
remove
equal to true and then we call grid
remove deleted tiles which will actually
remove it from our tiles table right
hopefully this is making sense it's a
it's a little bit of work a little bit
of engineering not it's not too bad it's
it's just a really all it is is taking
it's abstracting a lot of the redundant
code that we've had and parameterizing
it a little bit once we have called
clear tile we're not actually setting
any new tiles in this case we're just
reusing the tile that's existing at that
position we're tweening toward and we're
just flipping it where we're multiplying
it times two so what we do is we say
merge tween tile and that's it right and
then there was one other function that I
created and this is this is the similar
in spirit to make merge but this is if
we're just making a move and we're not
actually merging so this actually takes
care of setting the new tile right
because if we're moving to a new
position on the grid not only do I have
to clear the old tile but we're moving
the tile and then we're setting it again
so we have to actually set the tile in
the grid correctly because remember the
grid maintains a reference to each tile
as a taught tile attribute which here we
can look at here again remember we have
this tile is equal to nil by default but
this maintains a reference to whatever
tile is currently seated at that grid
index so that's what's happening there
so I'm going to do make move I'm going
to it takes a very similar signature to
the old function actually or to the make
merge function in this case so in this
case though what we're going to do is
we're going to set same thing we did
before can move equal false tile that
tile X is equal to Nu X tile that tile Y
is equal to new Y and there's actually a
little bit of repeated code here so
there is an opportunity to even maybe
abstract that out to a small function
but that's you know that's maybe going
overboard we're going to set the tile in
this case to new X new Y and we're going
to set that to tile so that tile we're
moving we're actually going to set at
the new X new Y and then we're going to
clear the tile at the old X and the old
Y
and then we're going to move tween tile
right because we're setting the new X
and the new Y so when we we do move
tween that'll just between its XY values
to match up with whatever's at the grid
at the tile X and tile Y so if anybody
has questions let me know
all this essentially does is break out a
lot of the redundant code a lot of the
redundant stuff that we're doing across
all of our functions and make it a
little bit simpler but this gives us now
the groundwork we can sort of almost
completely rewrite all this code now
what I'm gonna do is this the shell for
this is still accurate so the move right
a lot of this code is kind of busted and
now a lot of it has been abstracted out
into those smaller functions so what I'm
going to do is I'm going to delete
basically all of this starting from here
we're gonna we're gonna keep the
farthest X bit but I'm gonna delete all
of this code here just like that so now
we're we have this move right function
and I'm going to consult my handy-dandy
set of notes for the actual new move
right function and we can use this as a
template upon which we can write the
other move left move down and move up
functions so once we get the farthest
tile I can say check the tile beyond for
the same number and merge it so what
we're gonna do is essentially if the
what we're gonna grab the farthest X and
we're going to check to see if the tile
beyond that farthest X remember the
farthest X because this is how we wrote
our rightmost topmost leftmost
bottommost functions it will return the
nearest empty tile and sometimes this
could actually be our tile did actual
tile that is that the of the tile that
we're checking to move on or because
remember we're essentially iterating
over our all of our Y in the case of
move right so we're going every every
row one by one and then for every column
we're essentially starting since we're
moving right we're essentially going to
and this is
verse for you I'll try to do this this
is right right for you so we're going
we're working our way from the rightmost
tiles one by one to the left and we're
just seeing where the nearest open right
tile is and it's the exact same function
the exact same algorithm for every other
direction
it's just flipped or wrote or mirrored
or flipped 90 degrees and what happens
is the functions that we wrote these
leftmost topmost bottom most etc
functions they'll just essentially start
at a given XY or YX and they will give
us the the nearest empty spot on the
grid and if there isn't an empty spot
it'll just give us wherever we started
right which is the exact same tile upon
which we're beginning to loop through
the rest of that axis right if we're on
the x axis we'll move along the x axis
if we're if we're you know we're trying
to move right we'll move to the right if
we're trying to move left we'll go to
the left up and down down and if we are
if we get to an empty tile first of all
that means we can make a move and we
need to also check to see if the tile
beyond where we're moving is the same
number as the tile that we are because
if it is we can not only move we can
move to that tile and merge with it if
it's not the same then we'll just move
to that empty spot but if it is the same
we want to move to this spot afterwards
and we want to also restrict ourselves
from not moving trying to move past
above the edge of the grid so we go we
only go until you know four spaces or
one if we're going left or up right so
we stay it within the grid boundaries
but we do check to see plus one on
farthest X if it's within the boundaries
to see if it's the same number as the
tile we're moving because we want to
make that merge happen if so so we do
that if it's not the same then we if
it's not the same we just move to the
empty tile but if we if we do get the
same tile like if the nearest tile or
rather the farthest empty tile is our
tile meaning that we are jutting up
against another tile if it just returns
the current tile we can still make a
move because let's say that we are
let's say we're we're a - and we're
stuck against another - rightmost is
going to return our index because the
next tile is filled but we should still
be able to merge into it so we also need
to take that into consideration we need
to move one beyond our current tile even
in that situation as well so we need to
check for a merge regardless of whether
we're butting up against another tile
which is one of the mistakes we made
last time I weren't actually checking
for that and I think that was one of the
things that we ended up trying to figure
out so that's where that's what we're
gonna do here we're gonna get the
farthest X and then we're gonna check
the tile beyond it to make sure that
that it is not the same number and if it
is we want to merge into it so what I
can do is I can say if farthest x + 1 in
this case is less than or equal to 4
because remember we all move we want to
check for one beyond it but not if it's
greater than four because if it is that
means we've gone past the edge of the
grid which would be an error because
there are no spots in the grid at that
indexed right then so if it's the case
that farthest X plus 1 is still within
the grid boundary what we'll do is we'll
say local for this tile is equal to grid
at get tile farthest X + 1 + y so this
is going to actually get the tile that
is one beyond the empty space that we're
trying to move towards so now we have a
reference to whatever tile is one beyond
the nearest empty space this could be
either this could be an empty the one
tile beyond an empty space or if there
were no empty spaces you know it's just
the tile one to the right of us because
that means that we returned our current
tile spot and so what we're gonna do is
we're gonna say if farthest tile num is
equal to tile Nam well this means that
this means we can actually make a merge
happen right so all I say is make merge
of tile tile X now this remember it
takes in the old x and y and the new x
and y tile
xy4 this x + 1 + y so we're actually
going to do a merge operation we're
going to get rid of our old tile x + y
and we're going to move it to far this x
+ 1 + y and we're gonna wear this
specifically is going to be a merge
right else if the farthest X is not
equal to X we want to do is want to make
a move right we want to do just a
regular move tile tile ductile X Y and
then farthest X and then Y so where in
this case we're just getting the the
farthest X not farthest X + 1 so and
then in this case here we're checking to
see if far this X + 1 is less than or
equal to 4 now if it if it's the case
that farthest X + 1 is actually 4 or 5
then we can still make a move it's still
going to be an empty tile but there's no
possibility of making a merge so what we
want to do in this case is just say
otherwise
we want to just make an ordinary move
right so this is moving to the edge of
the of the grid so we just say else and
then make move at tile tile at tile X Y
farthest X Y and also the one thing we
need to do is I think am I missing a
continue statement in here I think we
are oh did I get rid of continue I might
have completely gotten rid of it
actually and then I just didn't update
my source code to do so yeah cuz I don't
I don't think we need to continue do we
yeah I don't think so
let me just sanity check let me save
this let me check out get make sure that
it didn't I didn't flub this let me get
check out master and then let's go over
here
oh it looks like I got rid of continue
here but it didn't get rid of oh wait
not master get check out completely
oh I got a commit okay that's fine
get commit started refactor okay cool so
now we'll check out master complete I
think I might have just goofed and not
yeah cuz there's no more we don't we're
not using go to continue anymore because
they refactor the code in such a way
that we wouldn't need it so yeah I'm
just gonna get rid of these I messed
that up
again I was finishing this at like 2:00
in the morning so that might be part of
it but that simplifies the code a little
bit cool I'm gonna go ahead and just get
commit cleaned up continues which is
nice because I actually don't like I
don't like having to use the go to if I
don't need it I mean it's kind of unfair
that Lua doesn't give you a continue
construct like you get in most
programming languages but that being
said still it's preferable I think not
it's preferable to avoid go to gets a
little bit
it's very assembly like it's not you
know it's not clean there's a reason
that people say don't use go to it can
be very hard to track everything I'm
going to go ahead and get check out
master again and then now we have where
are we we need to go down here right
yeah so now we have this function it's
very clean right this compared to how it
was before this is like half the size of
the prior functions and we can do this
same exact thing for the other four
functions I think to save us a little
bit of time I might cheat because now we
have the idea right we have the idea
that this is how it works
all we're doing essentially is taking
these functions and we're just copying
the exact same thing back to move left
and then move down and then move up
they're all
same just the parameters change a little
bit and then I shot us to David in the
chat David Malan who if you're not
familiar again with cs50 is the course
instructor for cs50 the professor rather
of cs50 definitely check out those
lecture videos on YouTube they're
amazing yeah so what I was saying
previously was that I don't think it's
worth the time for us to since
everything's already laid out to just
manually go through these functions and
refactor them the same way I Ellis
trated here how we refactored the move
right function but the same process
exists for a move up move down move left
so what I think we're gonna do is I'll
just go back to the complete branch and
you can check this out on your machine
if you have downloaded the repo you'll
have access to this but let's see how
many lines have do we save so we're at
2:34 on the complete branch and if we go
back to master we're at 3:28 so we save
almost a hundred lines of code from the
refactor which is pretty cool
could save theoretically a bit more if
we wanted to take the time to actually
refactor the up-down left-right
functions into one function a mono
function I guess you could say but no we
won't worry about that too much so now
we have this code we can run it
everything sort of works the way that we
expect it to yeah pretty awesome yeah I
will say I'm I'm pretty happy after
after it feels like we've been on a long
journey after you know however many
weeks it's been in getting this actually
working I'm see if we can get the let's
see all right let's see how high we can
get let's let's enjoy the fact that we
got to this point right and see how high
of a number we can get there are a few
core functions that we're missing before
we actually have the game finished and
that Ignite says yeah cool it's working
finally we are still copy pasting
meaning we saw a chance to factor it out
yep that is correct that we do have a
chance to refactor it it's going to take
a little bit of work it just because
the we are doing an access flip in 90
degrees whenever we do want to if we did
want whenever we're moving left and
right versus up or down we're doing an
axis flip and so the inner the inner and
outer loops get flipped so we'd have to
abstract those loops out and it would
just be a little bit of work that I have
enough time to do or think too hard
about it works now and it works good and
it's it's much better than it was last
time so we'll stay with it but I welcome
your effort in maybe doing a better job
of abstracting it so let's see how how
high can we get let's have a little bit
of not as productive time here actually
playing the game that we've worked so
hard on completing let's see I have a
couple 16s there we go there's one okay
there's a thirty-two there's a 64 128
cool things are working I'm actually
doing not not horribly right now I don't
know if it's easier to do it with the
way it's coded now because again it
actually will multiple multiplicatively
combined numbers if they if to get
calculated is the same and then they
have another of the higher number that's
on the same axis so it's really what it
does is just saves a move I don't know
how that affects the game balance it
probably makes it a little bit easier so
we'll say as much and we'll just say
that I'm cheating a little bit maybe I
honestly don't know I have to imagine it
makes it somewhat easier I want to get
these two thirty twos together there we
go
sixty-four okay I have to do another 32
here I'm not very good at this game
either so bear with me a little bit say
we have okay with those this is gonna
turn into Colton plays Colton plays 2048
games looking Primos as Adam thank you
very much appreciate it I think it could
look a little bit better we haven't
really spent much time styling it at all
but it's pretty cool I'm pretty happy
about it I always get a really huge
sense of enjoyment out of finally
getting a game to work after spending I
mean this is just programming generally
speaking
see right there at collapse there was a
32 when it created a 32 and so it made a
64 totally I think okay but it's a sort
of a bug slash feature okay
okay okay
almost that I mess myself up there for a
second oh well I'll go
maybe I'll go until I lose cuz I feel
like I'm gonna lose here pretty soon
there's a strong likelihood I'm gonna
lose again I'm horrible at this game let
me see so if I move that okay thank that
and then let's see do that
shoot oh I lost so there we go I lost I
got the 256 which is a it's not terrible
like maybe for somebody who's horrible
at the game but yeah it's pretty good we
we have the core functionality of the
game now what we're missing is one
scoring that's kind of an important
thing to we're missing the ability to
win and three the ability to lose these
are all pretty important things so why
don't we why don't we spend some time
implementing all the above so the first
thing that we can probably do is
actually implement a loss condition and
Babic actually suggested an interesting
approach to solving this problem last
time which was just take every grid
number and check all of its neighbors
and see if there if it's the case that
there are any tiles that have an
equivalent neighbor if they do that
means that you haven't lost yet right
because you can make a move but if you
have if there are if it's the case that
every grid has no identical neighbors
then you've lost you cannot make a move
so we'll do that we'll say make a
function called grid and this is all
from scratch this is not any of the prep
I did last night all I wanted to do last
night was figure out the actual
combination logic because that was the
trickier part that I was struggling with
slightly on stream my brain was not able
to function appropriately during
to stream episodes unfortunately there's
an argument to be made about whether it
functions appropriately ever but we
won't we won't dive into that so grid
calculate loss I'll just say and this
will be essentially a loop so we'll say
for y equals 1 until 4 do 4x equals 1 2
4 2 and we're gonna get the tile at that
particular index so we'll say local tile
is going to be equal to self grid at Y X
tile now there might not be a tile there
so we want to do is we want to say if
tile then well rather what we can do is
we can say if not tile right then we
just return false right so this is going
to do is is gonna say the calculate loss
is going to effectively return if we've
lost so if there's not a tile and a give
an index on the grid that means there's
a space which means obviously we haven't
lost so I can return false here and then
we'll assume that
I guess well we'll assume that we've
lost and then we'll just return true if
any of the neighbors aren't true are the
same so I'll say for or rather what I'll
do is I'll say local tile left is going
to be equal to or rather we want to also
avoid the issue of the here we'll write
this out will say check top check bottom
check left and then check right and what
we're going to do is we're going to say
if Y is greater than one then local tile
top is gonna be equal to self grid Y
minus 1 at X dot tile and then we'll say
if not tile then return true or rather
return false else if tile dot or whoops
I should say tile top and then else if
tile dot or if tile top dot num is equal
to the current tile which is tile num so
if they're the same then I can return
false right so this is essentially the
case
so we're basically saying if no tile
above we can move if tile identical in
num we can we can merge so in this case
we haven't lost because we have two
situations in which we can make a valid
move we can move into an empty space or
we can move into a space with the same
number as this current tile cool then
what we want to do is essentially copy
and paste this for all of these again
not the most elegant coding but it will
get the job done for now so if Y is
greater than wait did I do this wrong y
is greater than one right if Y is less
than four
then this will be tile bottom this will
be y plus one and then that's pretty
much it cool tile left is going to be
reverted X or inverted axis so we'll say
if X is greater than one and then we'll
do Y and then X minus one cool easy and
then we'll do this exact thing but it'll
be four if X is less than 4 then X plus
one cool as far as I'm aware that should
work that should calculate our loss
appropriately you can make a get
neighbor function which returns
neighbors that L can have was in the
grid I did in that way and mine soon for
all neighbors using a nested for loop
yeah we get we can definitely do that
that would be an opportunity to make a
probably a cleaner function ok cool so
let's go ahead now and when we actually
calculate the loss we're gonna do that
when we when we move so we're going to
say if do you want to move up first or
do want to call it after the merge has
happened
I think we can do that or operator
sustained nine nine six port Oh is there
an opportunity for me to do an or
oh sure I guess yeah we could have done
that if not tile top or oh right yeah
because it would have lazily evaluate
area with a short-circuit evaluate in
this case so we wouldn't have to worry
about indexing into dot naman tile top
and having it be a indexing into a no
value yeah we could do that the nice
thing about this is it does break the
functionality up and makes a little bit
more readable and commented so there is
that side of it but that would be the
ultimate really argument to not doing it
as just a yeah or wood circ well
actually no because and would
short-circuit but or in this case
wouldn't what a short-circuit
yeah would short-circuit yeah it would
it would short-circuit yeah cuz or would
evaluate this would evaluate to true and
then it wouldn't actually do this stuff
cuz it doesn't need to because it's an
or statement um yeah we could do that
absolutely
readable is better than smart true
absolutely sometimes I would rather have
code that looks like this then have
everything all in one line it may
depending on the circumstances my
philosophy on that changes because there
are certain languages that make it nice
and easy but yeah after new towels
appear on the grid we can check for loss
yep exactly so that's we're gonna do
we're going to go over to where is it
down here I think on where do I actually
call the code it's been it's been a
second grid spa Oh grid spawn tile yeah
yeah yeah so we can say if grid what did
I call it calculate loss yeah
if grid calculate loss then you know
we've lost in this case we need to set
game over to true well just use a simple
flag in this case we won't do anything
too fancy so we'll do this
[Music]
I guess we could just add it to spawn
tile though
yeah we could do that yeah why don't we
do that actually well no because you
don't have a global yeah we don't have a
that's the thing about like classes
really shouldn't have game logic stored
within them super like that's why we've
put most of the stuff in main da lua in
this case because that's our game logic
it feels a little bit as as much as it
would save us some code if we put it in
here right if self grade calculate loss
we don't want to necessarily put the
actual game logic in there so what I'm
gonna do is I'm just gonna bring it out
here into these as as redundant as it is
I'm just gonna do it here and then if
game over is equal to true I'm gonna
wrap the whole thing actually
so if game over is equal to if game over
rather then I'm gonna just go ahead and
I want to make all of this and else I'm
gonna do else if so we're gonna do I
don't want to do um love graphics top
printf game over will start at 0 will go
window width as our or actually what was
0 a little bit will do it at the middle
virtual height divided by 2 - I think 32
pixels is a font that I did and then
we'll actually know we'll make a new
font for game over so I'll say game over
font is equal to love graphics that new
font and this one will be 128 pixels
large so it'd be nice and huge and then
we'll say love graphics dot set font -
game over font and don't make any
different color - I think I do love
graphics set color will make it sort of
a reddish I think so I'll do - well 255
and then I'll do like 50 v neg 12 and
then one like that and then we'll do
this make sure we set everything to
white and then also I want to make sure
that I set my font back to the original
font size so set font back to what did I
call it font just regular font should
probably call it like normal font or
something and then this will set - it's
not a virtual height that's window
height and this will be window width
that would be the center column size and
it'll make it a center thing there and
then this will just trigger here so if
it's a game over we'll go ahead and we
will just draw this text here right
right in the middle of the screen game
over nice and huge set the font back to
normal and then set the color back to
normal
otherwise we'll move all of our stuff
here so let's go ahead and let's like
populate our grid with a ton of numbers
just so we can test really easily so
we'll say where am I actually
initializing it oh okay here so we'll do
we'll do 16 right so I'll spawn a tile
I'll spawn 16 tiles and maybe we'll set
spawn tile equal to where is it at
[Music]
all right because we're using the tile
constructor the default constructor so
we'll modify this right now well set
this equal to math dot random six times
or rather um there's not an easy
I think it's math dot Pao to to man
thought random 6 so 2 ^ 1 to 6 I'll do 8
actually just keep it random and here
now we have a random grid sort of all
laid out now we can make a move so we
don't have a game over yet because we
have two eights that are next to each
other and two 32s that are next to each
other so I can actually move those
collapse them move that collapse that do
that I'm just gonna do a bunch of random
oh it didn't actually work yet
interesting ok so we're not actually
printing out all the we're not actually
getting calculate lost to work properly
yet okay so something is wrong and I
actually gonna set this to 10 at work
yeah now my guessing 1024 is on there
okay so let's figure out why that's not
working should be on the grid okay let's
see calculate losses
okay so why is greater than one
am I not doing a true thing here Ulta
tile top num is equal to okay now that's
fine why is the sin 4x is less than X is
greater than 1 and then X is less than 4
we are returning true at the end of all
of that so that should work and we're
doing if grid calculate loss right then
game over is equal to true okay so if
game over oh because well it shouldn't
be because I didn't set game over equal
to anything but well we'll do that by
default say game over is equal to false
not that should matter because it gets
set as a global within those um it gets
set here so it was know already so is
actually technically working I think
should have been working by default all
variables that exist in Lua that don't
have the local qualifier are they are
global so even if they're within a
function or within an if statement if
you declare them as not local you'll
have access to them as global variables
so I'm tell you sure why that's not
working um hey I got 2048 though look at
me I'm I'm pro but yeah this isn't this
should have a game over set for some
reason it's not working so we are going
through each of these we're looking to
see if its neighbors are empty or if its
neighbors are the same number and if
either of those is the case we'll return
false
but we return true at the end of all of
that and it's not the case that any of
these have an identical neighbor or that
they have an empty spot next to them so
I'm not sure why it's not working
right unless I'm unless I'm tripping
super hard let's see - 64 window width
it takes an x and a y then it takes the
column width it takes in the center that
should be correct setting the font to
GAMEOVER font the color is getting set
to like a reddish color so this is
getting set to white
oh wait unless it needs to be no no cuz
you didn't know it though the one is
correct yeah this one is correct so what
is something must be wrong with my
calculate loss function then so if I say
so let's go into main here let's see if
it's actually returning true so I'll say
print loss is or game over I'll say game
over and I'll actually run this to the
terminal so I'll say I love dot move
this until I can't move anymore okay
cool so now the terminal should say game
over but it still
oh it's drawing out all of the I added
this this print function to show me the
grid which was interesting I can remove
that section don't need that but it's
not actually it's so it's what's
happening is it's not printing out the
game over the game over is showing as so
what one of these things is returning
false so there's some logic here that is
messed up so what logic is that
let's see based on what I understood it
seemed like it was correct so if not
tile returned false
I have this correct right so why
self-taught grid @yx
tile yeah if Y is greater than one so
we're gonna get the top tile and this is
copy pasted for all of these so we get
whatever tiles up above the dot tile
right so if that's not a tie if there's
no tile there so if it's nil it means
it's empty so we can return false we
haven't lost if the tile top num is
equal to the tile um meaning that so the
two numbers are the same they can merge
we still have it lost we can still make
a move so return false right it does
this for each of these so calculate top
doing the bottom oh wait okay yep yeah
so y is less than four then we want to
do this so thanks to that was fire 705
off those 13 comma 33 and nephron
double-oh-seven
appreciate the follows let me see what
is going on here if anybody catches the
bug if anybody sees it let me know
sometimes it's hard to see what's right
in front of your face when you're
programming only junior programmers
write one-liners because they don't get
that reading code is the hard part not
writing true clearly that's clear that's
being demonstrated at this very moment
what is he doing web app or a mobile app
this is a game so this is a desktop
application in this case but there are
ways to get this sort of thing working
on the web and on mobile is it reaching
the return true statement well
apparently not Babic that's the that's
the problem that we're running into so
based on my understanding of the logic
we should be getting to the return true
but I must have an issue I must have an
issue with this and Adam actually to
your point I thought about playing
background music on stream before but I
think I got some people were saying that
it was kind of bad so I'm not or at
least it was distracting so I'm not sure
if that's I always thought in my mind
that it would be pretty nice having
background music on stream now there is
an argument to be made about actually
yeah I was just gonna say the viewers
play their own not if I don't play my
own music then you get to choose the me
so maybe that's actually better in the
long run because you copy pasted that's
why
well I copy pasted Babic but I adjusted
everything as you can see but I mean the
names need it oh you know what it is
that's what it is that's what it is got
me
silly variable miss naming let's try it
now
okay it still doesn't work
interesting oh wait
tile top yeah
tile bottom tile left tile right you
know I I swore that that would have
fixed it but that didn't fix it does
anybody know what font or theme this is
um I I don't remember offhand actually
what theme I'm using I thought I was
using noctis am I not using Noctis um
how do we go into this color theme
what am I using Oh musing Dracula well I
like knocked us a little bit better
oh wait am I using Octus oh I think I am
using noctus never mind Dracula is
pretty cool to you though I'll show that
oh whoops it's a little bit purpley it's
not bad is giving up an option if so I
have a suggestion
I don't think giving up is an option
we're so close we can't give up at this
point okay what is the problem here tell
right that's how all right is that if
not tower right return false yep because
obviously if there is
if there it wait Oh is my logic you're
messed up in some way oh no it's not no
I don't think so yeah because we're
still if we're at the very far right we
will still check the left because we
will say if X is greater than 1 blah
blah blah
dang I wanted to contribute wouldn't it
be cool if the towels had color at
numbers that would make it more
complicated but fun to look at says
Cynthia Elise yeah no I mean we have
time we might be able to implement that
actually if we can just figure out how
to get the the lost condition actually
working functionality and then we will
make it as pretty as we have time to do
0 Droid and ec2 thank you very much for
the follows hmm what could be the
problem I was like a hundred percent
sure it was the oare are we getting a
game over now actually maybe we're
getting the game over oh it looks this
nice to me I need to get rid of this
print thing too where are we printing
you're putting down here right
oh you know what I think I'm doing it in
the actual yeah we're doing it in here
well get rid of squid print it's
clobbering the output just a little bit
great print was a cool little debug
function I wrote that let me actually
see what all the numbers were on the
grid at any given point in time you can
see however that I didn't actually test
it for numbers greater than 2 digits
wide so not the cleanest not the
cleanest approach so let's go ahead
let's do this a bunch of times until we
lose see if the terminal
oh it's getting to game over okay but
it's not okay that's great
it's working but it's not printing the
it's not printing the game over for some
reason why is that what
[Music]
what in the world okay
XY so do I have this wrong don't mind
forgetting the arguments on this so it
takes in a string takes the X and the y
takes the column width and then the
styling let me just confirm that I got
that signature rec maybe I messed up
that signature oh you know what it's in
tile here let me see printf yep XY yeah
that's correct
returned yet its returning true so once
it's returned true then
yeah this is weird okay so if grid
calculate loss then game over is equal
to true
now what if I did what if I just printed
what if I just printed game over let's
see what let's see what that actually
shows okay let's do all this song and
dance
boom game over is true okay what the
heck is going on okay if game over then
set the color which we're doing
oh you know what you're right you're
right Babic you are right we need to
print this out shoot
that's silly that's a silly mistake
honestly Wow shame on me shame on me
okay if can move and not game over and
they will say if game over I already
have that boom
what a what a silly mistake okay let's
try that again
boom game over there we go look at how
lovely that is and it's just the right
color of red that it doesn't look
obnoxious
it's like slightly orange so that
actually looks pretty good okay cool
we did it we got that part so let's
figure out a win condition so game over
equals false Lane equals false here's
another thing that we need to do so if
grid calculate win so game over or so
we'll say we'll just keep that when is
maybe equal to false but then we'll say
else if grid calculate win game over is
equal to true and win is equal to true
and this is going to be this is going to
be important so we'll just do this this
whole song and now just like that so a
little bit of this all belongs in a
function but that's okay as long as we
all know that it can it could go into a
into another function somewhere that's
important yeah shout out to Bhavik for
the for the tip there clearly I am
slightly not with it enough to know that
to remember that the render function is
we're drawing stuff goes I don't know
what I was thinking
drawing stuff in the in the callback
function not the right move definitely
don't do as I do draw everything in the
render function where it belongs so okay
so calculate win that's another function
that was that what it called it
calculate win yes
calculate win so we're gonna create a
function this one's easy
because all we need to do is say for y
is equal to 1 for 4x is equal to 1
or going to return false by default but
we're going to say if self dot grid @yx
tile and self dot grid Y X dot tile num
is equal to 2048 return true that's all
we need to do so
oh and then if we want to actually
display the win so that's we're gonna do
down here we're gonna say not in here
sorry in Maine dot Lu at the very bottom
we're going to say if game over
then if win then we'll say local text is
going to be equal to game over and we'll
say if when then text is gonna be equal
to you win
and we'll say set color here to this
else
we'll set this color this color is going
to be like a greenish color so we'll set
this to like twelve on the are the G is
gonna be 255 and then we'll do 50 on the
blue so a little bluish green and then
this will be 'text and that should be it
so now see if I can get it to see if I
get a 2048 in here there we go awesome
you win oh it's actually not even that
bluish green pretty amazing right pretty
cool and that's that feature so while we
have the core functionality sort of
written oh I need to get rid of that
print statement as well let's see where
is that at print what am i printing that
I printed
oh I'm not running it through the
command line that's why it's showing
that so if I say okay what's the status
here get status git commit winning and
losing I'll push that so now everybody
will have access to at least this far
right pretty cool
check if we can still play after the win
oh yeah that's true yeah we could do
that that's a little bit more of a
that's a little bit more advanced
because we need to display it we need to
have a display thing but we need to keep
going so maybe we'll save that after we
actually do the we'll save that for we
want to have a score mechanism I want to
say you win with a score of X and some
people also requested that we styled the
individual tiles too so maybe we want to
do that before we actually do that
feature but that's a good recommendation
and in fact if you would like an
exercise at home maybe consider how you
would implement that I'm sure you would
do an amazing job Babic okay let's go
ahead and figure out a score this should
be pretty easy honestly so what we're
gonna do is we're going to say not in
the grid in main we're going to say
score is equal to zero and then we'll
make a will do one point for every we'll
do a basic score
that's 1.4 how does it work in 2048 is
it the higher the score the lower the
score the better I think it is right
just like golf so we'll say that the
lower the score the better so we'll do
one point for every move that we take as
just a basic score I'm not sure how they
do it in the normal game I think it's a
little bit more complicated and I think
they take into consideration actual
merges two that Vic says I would
struggle more than you I'm not sure
about that Babic I think you would do a
good job I think you would do just fine
okay so in the actual move let's go
ahead and score equals score plus one do
the very just this very basic thing and
down here in our render function I'm
just gonna do a love graphics dot printf
of score two string on the score it's
going to start at zero and zero it's
going to take the window width as its
column size and then I'm gonna write
align it and we'll see how that looks
okay score is zero and movie scores one
two three four five cool so that's
working so we ended it with a score of
seven in this case so I mean this is
good enough we don't need to go too
fancy with it we can just say that okay
score is equal to seven that's fantastic
now for the actual tile let's actually
render this a little bit differently so
all the logic that we need to change the
colorization lies in here when the
actual game they do consider all
additions merge for score yeah I imagine
they probably did so I probably won't go
into that we will again that's an
exercise for the view
at home if they would like to do that
the will probably end this after like
this will be like a two hour stream
roughly probably so we have about 30
more minutes but within that 30 minutes
one thing that we can add that was
requested and I think would actually
help the game's polish a lot is
colorization of the tiles and this might
be a little bit more time-consuming but
why don't we figure out how to color
this so what I'm gonna do is I'm
actually going to create a table here
called tile colors and I'm gonna set the
I'm gonna do it based on number so I'm
gonna say 2 is equal to that 4 is equal
to that 5 is equal or not 5 8 is equal
to this and I think this ending Babic
actually see just has suggested
something similar to this last time so
we'll let all credit go to Babic for
this idea we did something similar to
this in my match 3 assignment in my
games class 2 we actually set we have a
color display that where colors rotate
and we do something similar to that you
can make each value equal to a number
yeah yeah that's essentially what we're
doing here unless you're referring to
something else so we're just doing this
based on powers of 2 512 1024 and we'll
just do we'll just consider up to 2048
for now since that's what we're ending
it right now but this is something that
you could easily tweak yourself and each
of these is actually going to have two
different things gonna have the fill
color and the the font color so we'll do
this this is completely off the cuff but
this seems like it's probably a solid
way to do this so we'll do something it
will be something similar to this so
it'll have a the fill it's gonna be
equal to another table and then font is
gonna be equal to this table and then
each of these are gonna have R is gonna
be equal to some
number G is gonna be equal to some
number and then B is gonna be equal to
some number and Cynthia is saying with
the color of the border could be a
darker or lighter gray that's possible
we won't go that in depths I think we'll
just stick with the I think we'll just
stick with the basic colors for now well
let's go to 2040 a game just so we have
all the colors set here so I'm gonna use
it looks like white is it looks like
it's the case for everything but the
base color it's um it's white
interesting
okay so I'll use my handy dandy colors
application which is super nice we'll go
to this the little dropper and then I'll
click on this so 237 224 200 so keep
that up to 37 224 200 and then that's it
we don't need to keep track of the Alpha
because that's always consistent and
then the fill color is gonna be equal to
or the font color isn't equal to 119 110
101 so 119 110 101 just like that cool
so that's fantastic
so oh wait it was that for oh that was
for for my bad so it's a copy these over
here and then we'll change these these
values are for the two so let's go back
to here so this is a tedious part it's
not the most fantastic way to do it but
it works
what IDE do use is genk ax i use vs code
Visual Studio code which is free and
open source so definitely take a look
whoops this know what I want to do is
let's do this
grab the background to thirty eight to
twenty eight to eighteen to twenty eight
to eighteen
our is equal to and then this is going
to be the font color here which i think
is gonna be the same actually is it 119
110 101 yep this is gonna be the same so
I just copy this over here like that
awesome so let's get the 8 now so I'm
gonna grab this so the 8 background is
242 177 121 242 whoops 242 177 121 and
then the font color is going to be equal
to so not the most riveting experience
for all of you I apologize but it is a
it is a necessary thing did I get that I
might've accident on one of the side
pixels on that we need sure that one -
yeah - 49 - 46 - 42 so - 49 - 46 - 42
I think that was it yes awesome
let's get a 16 I might not be good
enough to actually get the right colors
for this for the later values so we'll
see we'll see how that goes
16 is 249 149 100 245 149 100 so it's
just copy as copy these and replace them
245 149 150 Kim let's try that see ya
that's the same color so now we'll get
the 232 or the 32 246 1 24.95
246 32
I know all of you are enraptured by this
right now it's very exciting
246 124 95 but hey welcome to welcome to
game programming crawlspaces hey color
themes name this is Dracula if anyone
has an idea for a color picker tool like
this for Windows oh man I actually don't
know there's probably a free one that
you can download let's go to 64 grab my
color picker 246 94 59
now the trickier part is getting the
colors for the other values so I might
cheat and look online for them I'm again
I'm guessing the approach red like flat
red that's probably the probably 2048 it
looks like it's getting redder and
redder with each one let's look and see
2048 color numbers
oh this is interesting this is for call
actual colors okay now what I wanted
oh they're using this hit this is cool
they using the same Jekyll theme that a
cs50 uses that's pretty cool
oh and they wrote this in Elm too which
is interesting okay
they have any screenshots nope let's go
to the go classic google images see if
they have the colors here oh it looks
like they don't actually use um they
don't use they don't make a redder and
redder they actually just use some icky
yellow instead that's okay we can do
that okay so 128 is 242 216 106 242 oops
let's get that over here 216 106
the picture doesn't have 256 on it
oh it well it's right here interesting
leaves so weird that they don't really
change the colors that much they oh it's
the it's a jiff - that's just great
thank you much appreciate it love it I
guess try that again
there we go got it 237 204 237 - Oh 498
237 204 and 98 bit weird that they don't
make the colors that different between
128 and 256 all right let's try 512 this
one has its own color scheme which is
kind of cool
let's go ahead and get colors 512 4096
is like a green color - 29 192 42 - 29
190 is it 192 42 yep 192 42 1024 is oh
did I grab the wrong color
I think it did I grabbed that one I
meant to grab this one wait I did grab
that one okay 226 185 19
again just the most exciting possible
twitch experience Elam is a functional
language sir rule
where's 2048 oh that's 2048 they don't
use very exciting colors for you the
actual 2048 I'm not gonna lie it's a
little little disappointing wow I love
how you can just get real crazy with it
that's not even is that even the power
of to 130 107 oh I guess it probably is
right so one of the rare ones that you
never see
right you see 4096 8192 16 384 and then
32768 I guess but then times 2 and then
times 2 is 131 Oh 70 which is an
interesting number all right where's
2048 there is that's the important one
that's the one we care about this one
right here
236 196 to 236 196 to awesome
and the last thing that we should do is
set this to 2 again math dot random 2
equals 1 and 2 or 4 there we go
so that will give it a chance to be
either a 2 or 4 like some folks
recommended we actually do all right
cool if anyone has an idea for color
picker tool plenty and adults for
Firefox all right I think that's
everything so I think we can run this
now and if I'm not mistaken so oh oh
right one one important thing that we
know and also another important thing
that I need to do is not generate 16
tiles generate 4 tiles
and I need to go into tile class and
actually change how it references how it
actually grabs these colors because it's
not actually doing that so what I need
to do is I need to say local fill color
is going to be equal to it's gonna be
tile colors at self dot num and then
we're gonna set and this specifically
self dot num at fill and then we can say
a fill our up fill color our fill color
dot G and fill color fill color dot B
and we do the same thing here we say
local font color is equal to tile colors
at self num apt font and then we set
this to font color dot our font color G
and font color dot B boom and there we
go cool seems to work the numbers are a
little bit small but the problem is that
they don't we don't have auto scaling of
the numbers yet but you know s rule says
oh why learn programming when you can
just use Python plus tech overflow
that's a valid that's a valid point
Stack Overflow is pretty amazing what is
cs50 C's 50 is Harvard's intro to CS so
it's taught by David Malin we have a
series of lectures on YouTube so check
it out youtube.com slash cs50 if you
want to know about computer science and
the art of programming and problem
solving it's pretty sweet course David
doesn't awesome he has an awesome style
of teaching so it's pretty fun and this
is kind of an offshoot where we do
things that we don't have time to really
cover a lecture we talk about
implementing projects particular
projects from
from scratch most of the time I do games
but we have other people that come in
and do other things and yeah she's a
little fun experiment
and it's nice it's bi-directional people
interact in the chat we are cs50 content
on YouTube is mostly mono directional
and that we broadcast content we've
lecture we provide videos but it's not
you know it's not interactive in the
same sense that twitch is interactive
the live stream format is a little bit
different lets us do some cool stuff so
uh definitely check it out
and what we just did was we added colors
we can see that we got two fours
randomly generated and we got two two is
readily generated and their coloring is
correct so let's go ahead and bring
these over and combine them pretty
awesome
looks like it's working so far let's
move these over do that with the sixteen
over yeah this is this is good this is
cool this is working just the way I
hoped that it would Wow we've come a
ways this is always such a thrill when
this when this ends up working this is
why I love game programming in
particular because everything feels so
satisfying in a in a different way than
it does with a lot of other realms like
the visual aspect of games has always
been something that really appeals to me
and just like tangibly seeing your stuff
on the screen I think is super cool so
we we did it I mean that's this is
largely it now we'll see how good of a
score I can get it's not going to be I
anticipate it's not going to be very
good this is getting a little trick you
think I might
hey there we got a 128 nice ah dang it
I gotta game over score of 88 so it's
gotten pretty good right this is this is
pretty awesome I'm gonna push this to
github actually because we basically
finished it I don't know how much we
don't have a ton more time and I'm not
sure how much we can get done and
whatever time we have left
so what I'll probably end up doing is
spend the next few minutes just taking
questions if anybody wants to talk about
anything I'll push the code people can
start experimenting with it you can add
your own features to it which is great
so if you do you know let me know I
think it's pretty awesome let's go ahead
I don't think I added any files so I can
just say final stream version probably
and this will be sufficient and shout
out to Babic for his contributions today
Babic was the MVP the color table idea
was very smart and the other bug we were
having with the variables came in that
was awesome
chrome as in the color eyedropper
extension colorzilla ooh I like that it
reminds me of FileZilla no more run says
but yeah you can grab that code that is
on the it's on the complete branch so I
think we can say I forget offhand this I
usually do this in github but merge
branch into master I forget the actual
git command
[Music]
if I go if I get checkout master and I
do get merged complete what conflicts do
we have we have a conflict in here
well you know what since I know it works
get forced merge or get a overwrite
master with branch this is
get merge - s Oh strategy hours okay so
get merged s ours
test that work I'm not test complete no
see how would we do that
get checkout master maybe a lot of these
commands I forget offhand here's a
here's a really crappy get lesson for
everybody how do you revert okay get
River merge roll back and get merge get
reset hard alright get reset hard I need
the actual commit which where was the
actual what was the commit that is not
correct
I don't know at this point I don't even
want to mess with it I just want to say
probably just going to what I want to do
this is where it gets messy cuz offhand
I forget the commands that you need to
do to do this you can find the commit
before merge with get RIF lot ref log o
get reset hard head at one there we go
I'll do that I think that'll work get
reset hard head at one think that's
right
final stream version oh okay is that it
done
easy peasy
easy peasy I guess okay am I still on
the master branch yep okay that was easy
get reset hard head at one don't
probably don't do that most of the time
it gets seems to be you super user
friendly this tifo a lot of the I forget
I have to always do it because I don't
do a lot of get merging I do for my
personal projects I pushed a master a
lot which is not good
because I do games and usually I don't
have a bunch of branches in my games I
just have one master branch that I'm
messing with but uh
cs50 we have for all of our main
projects we do have multiple branches
and so occasionally I will be forced to
figure out how to merge appropriately
but usually we just use PRS and we
manually merge and you know on github
for a lot of it but some of it I mean
depending on the complexity we will use
the command line to do the actual
merging em Koppenberg says reach 2048 so
I will do my absolute best I've just
realised just now that we've never
seeded the random number generator so
I'm actually into that right now
math dot random seed OS dot time because
the numbers are always the same so now
they're different now there's four of
them cool let's see let's see if I can
play this a little bit smarter okay
someone do this we're just gonna do that
it's gonna turn into eight three eighths
apparently it's gonna be 16 that's gonna
be eight sixteen thirty-two okay so
we're gonna do this and this than this
do that and that that that that that
okay
let's see if we can do this I'm again
I'm horrible at this game but I'm going
to give it my very best shot I can see
why it's fun though
128 there we go
I'm starting to feel a little bit
dangerously close to losing here
you can tell I'm very focused on ah dang
I'm horrible at this I don't know if I
could I don't think I could actually get
to 2048 with a bunch more practice
I was super focused on it I'll try one
more time try one more time okay got to
250 I think did I ever get to 256 I
think I did with a score of 1 for 55
that must be horrible
I should add a restart button so that I
can trigger playing it again but you
know next time all right got 16 okay
I know this is just riveting for
everybody
dang this is hard I mean I'm obviously
awful but there's probably I mean I
haven't looked up strategies so there's
probably like a consistent strategy for
this that makes it somewhat easier like
a general heuristic you can follow to do
better but if there is I don't know
about it I mean obviously
some of the people in here probably
played this a bunch at some point and
are like super good at it and are
wondering why I'm so terrible
dang it my best run so far was 256 we
can make an AI as Andre mentioned last
time to solve his oh man I don't know if
I'd have to spend a lot of time thinking
about a good way to do that I mean
there's probably always a best move and
it's probably not too hard to calculate
so if you just always go about whatever
the best move is that being said there's
probably also always like a set of moves
that will lead you to a best outcome so
kind of like in chess where you have to
think a few steps ahead you probably
want to do it that way and then the RNG
kind of messes that up a little bit so
then you have to recalculate that best
four moves ahead every single time so I
don't know make a cheat code I don't
know if I want to make a cheat code what
I want to do is I want to actually I
want to actually get to a good point on
this you know I was just I was just
trying something there because I'm
curious if it's like in your best
interest to kind of like stall one
direction like accumulate a group of
numbers right well if I was playing that
well no well clearly that didn't work
that with that strategy was not viable I
feel like I want to avoid getting boxed
in which I'm not doing a great job of
whoo that was nice
okay
that's rough yeah I don't know I'm just
horrible at this game so I think I think
we're gonna end it on that there are
more features that we could implement
there's a lot that can still be done
with this like adding a restart button
adding the ability to keep playing
forever are there could there be
decision trees that could win it yeah
probably we need to spend a lot of time
programming programming an AI for this
sort of thing but all of you now have
it's kind of neural network that will
win the game you know I'll have the code
base and the ability to take this and
add new features to it if you want to so
I encourage you to do that it's all in
github and if you're not familiar with
where it's located
20:48 stream and the master branch
should now have all of the code that we
care about the it's no longer just in
the complete branch it's now on master
as well so just cloning that you should
be able to just fire it up and it'll
work and hopefully you're better at
playing the game than I am it was a
blast programming it and honestly it's
pretty fun to play but I need some
serious practice before I can hope to
actually get 2048 on on camera I don't
see it happening at least not with a lot
of practice but yeah that was 2048 it
took us three sessions to get here and I
had fun it was a lot of fun actually
seeing it all come together and it was
worth the time I put in last night
actually making sure that we had a
smooth stream today because the last two
streams I was kind of disappointed in to
them being quite honest in the amount of
progress that we made but that being
said it was great it ended up fantastic
it looks great it reminds me of when we
finally finished minesweeper which was
also a tremendous amount of fun
Cyril says hope you get to 2048 sometime
me too
honestly I have my own implementation I
can play too which is which is pretty
cool thanks Abhinav for saying awesome
stream and Babic thank you very much and
also for your contributions throughout
the stream process and dzifa's on thank
you says thank you
estriol says no i didn't i'm not sure if
that's a reference to thank you so much
for giving us some of your time have a
good day thank you thank you absolutely
no it's my pleasure this is a lot of fun
for me too it's more fun when I actually
finished coding it and we we make good
progress on stream I will say but no
this was great and in Bella says thank
you for these streams again my pleasure
it's a fun time we get to make some
pretty awesome stuff and I think you
know the trajectory of where we've gone
from snake has sort of evolved with time
which has been pretty cool chuka niece
asks friday python tutorial how's it
gonna go it's uh it's gonna go pretty
cool I think so on Friday me and David
are gonna do a python tutorial together
it's gonna be catered towards absolute
beginners so if you have never coded
before in Python or if you haven't even
coded before period you'll probably get
a lot of value out of it we'll be
talking a lot about syntax and very
basic stuff you know talking about
variables talking about conditions
talking about loops and functions that
sort of thing all the all the bare-bones
stuff in Python specifically and that if
we have time we will get into things
maybe like list comprehensions we
probably won't get into object-oriented
programming at all because that is a bit
advanced and I actually be Babic to
asking the question there says will you
be reaching olp but Babic as you know we
have a stream that Brian kindly led in
the past on object-oriented programming
which actually used Python so check that
out if you're interested this will be a
little bit more on the beginner friendly
side no objects no object-oriented
programming at all chat learns Python
says kooky nice as a as an appropriate
naming for the stream and we'll probably
implement a few small toy little little
scripts along the way and yeah be a good
time Natasha says for sure was a lot of
fun thanks Colton
learned a lot awesome and then viv az3
says have you tried Godot before I a
long time ago looked at it briefly but I
have not spent too much time actually
learning how it works but I see it's
been gaining some steam recently and
several other people have asked in the
chat already so it's seems like it's
something worth checking out maybe and
maybe in the future at some point but
yeah tune in on Friday 2:30 p.m. Eastern
time this Friday for the Python tutorial
with me and David it's gonna be a lot of
fun
yeah and next week I'm not gonna be in
town I'm actually flying out to Japan
next week so there will not be any
stream as next week most likely so we'll
have a nice break period where you all
can rest and sort of get a chance to I
don't know maybe tinker around with the
2048 code base a little bit I'll still
be here for Friday so I'm not I'm not
going away for the week yet that I will
be I will be away all of the next week
and we will not be having any streams if
we do I will be involved in them so
somebody else will be here maybe David
or something if they want to still host
the stream so thanks all of you says
have fun in Japan sub Cloppenburg thank
you very much have a safe journey since
Bewick night much appreciated
the belt kisses have fun thank you so
much all right well this was 2048 we
finished it it looks great in my opinion
it's fun to play it's solid it behaves
slightly differently than the actual
game but it's something that you could
change pretty easily with a flag on the
tile object and yeah we've come a long
way so thanks for sticking around for
the whole journey and I'll see all of
you on Friday this week for the Python
tutorial if you are interested in
learning tell your friends if they are
starting out to program if they might
want to learn a little bit about Python
or basic programming it'll be a I think
it'll be a nice opportunity for some
beginners so with that said enjoy the
rest of your week I will see all of you
next Friday take care or not next Friday
this Friday take care bye bye