and now the last thing we need to do is actually move the burbs which I was gonna do at the beginning but I kind of skipped over so right now we've checked you know if they've collided with things I they're going through the pipes and we're removing it and all that we actually need to move the birds based on their neural network so the thing to think about here is what input are we giving to our neural network well we've already discussed this and we're giving you know the distance between the top pipe and the dystrophy in the bottom pipe as well as the Y position of the bird but what if there's more than one pipe on the screen well this is a problem I ran into and we need to make sure we account for this so essentially we need to check we need to find out which pipe we should actually be looking at if it's the first pipe in this list or if it's the second pipe in the list this list because they'll be at max two pipes at all times so to do this I'm gonna do this kind of weird thing I'm gonna say pipe IND equals zero and now I'm going to check if the Len birds is greater than zero and if it is what I'm gonna do is say if the Len of pipes is greater than one and Bird dot X on up yeah bird X we're gonna say bird birds zero dot X I just need to check this to make sure I don't mess it up is greater than pipes zero dot X plus pipes 0 dot top pipe or pipe top dot get underscore wit then what we're gonna do is say pipe underscore int because one alright so what did I just do here well essentially we're setting the pipe index to be 0 which means the pipe we're actually gonna look at for the what do you call it's the input to our neural network we're seeing if the length of birds is 0 because if it's not we don't mean it's about they're doing this and then we say if the let of pipes is greater than 1 then we're gonna do is just get the first bird in our list exposition now since these expositions are always going to be the same this doesn't matter which bird I get so I'm just using 0 advice if that is greater than pipe 0 dot X plus pipe 0 to pipe top get width which essentially just means if we've passed those pipes then change the pipe that we're looking at to be the second pipe in the list and that is as easy as that to work so now we're gonna do is for all of our birds we're gonna move them so whereas a four X comma bird in enumerates Birds what we're gonna do is create or not create but we're actually going to pass some values to a neural network so the neural network that's associated with this bird get its output value check if that output value is greater than 0.5 and if it is make the bird jump so we'll start by just moving the bird because this is important so we'll say bird dumb move we'll also just set the fitness of our bird give it a little bit of fitness for surviving this long so if it's reached this frame and we're actually running now he needs to get a little bit of fitness because it's moved forward so this is how we actually add Fitness to our bird and encourage it to keep moving forward we're gonna say bird or not bird gonna say GE x dot fitness plus equals zero point one now the reason I'm giving so little Fitness here is because this for loop is gonna run 30 times a second so in theory every second art bird stays alive it's gonna gain one fitness point which means that it's going to encourage the bird to stay alive and not just fly all the way up off the screen or fly all the way down okay so now that we've done that GE x dot fitness plus equals one we need to create or actually activate a neural network with our input so what I'm gonna say here is output which is gonna hold the value of the output from a neural network is neat dot isn't it - no it's not sorry it's net and then this is gonna be X dot activate in this case now we need to pass it up with all our inputs we're gonna say bird dot Y which is the first information that we need and now what we're gonna do is actually find the distance but in the Y between the top pipe and the bird so the way that we do that is we're gonna take the absolute value of bird Y - pypes pype underscore ind dot I guess in this case it is height which gonna is gonna stand for exactly where our pipe is on the top of the screen then we're gonna do another comma here we're gonna say abs of bird lime - pipes pipe underscore IND bottom and this bottom is the Y position of the bottom pipe and since we're doing absolute value it doesn't matter what way we subtract these we'll still get the correct value here okay awesome so we have that and now what we need to is actually look at this output and see if it's greater than 0.5 so we're gonna say if output is greater than 0.5 then we'll say bird dot jump like that okay so that should be moving our birds there's definitely a few things I forgot here I think one that I want to check here is if our bird reaches the top of the screen I want it to not survive as well because there'll be some birds that just jump every time and they'll actually be able to get like above the screen over the pipes and they'll never die so what I'm gonna do here is check if bird Y essentially is higher than 0 or less than 0 so I'll say or bird Y is less than 0 okay so now that we've done that I'm just gonna read through this program quickly because there's definitely things that I forgot and that we need to fix once we'll fix those we'll start testing this and then will pretty much be done with this program all right so I'm back and there's a bunch errors we need to fix things that I forgot like I mentioned first thing we're gonna get rid of this main function call here cuz we don't need that we're also gonna get rid of piking duck quit and quit I'm just gonna copy this and what I'm gonna do is instead of having it here I'm actually just gonna paste it right where we have this quit event and this way if we click the red X button rather than just breaking this loop because you know we're gonna call this function up to 50 times then we're actually just gonna quit the game which is what we want to do all right so now that we're at the top of this let's start going through the errors so the first one here is we need to change this for loop to be underscore comma G in genomes now the reason we need to do this is because genomes is actually a tupple that has the genome ID so like one as well as the genome object now obviously we just care about the genome object so we need to loop through it like this so underscore G in genomes so we don't get any errors next thing which is coincidentally the next line down we need to add a dot create here I don't know why I forgot that but essentially feed-forward network dot create that's the method to actually make it where I was running into some issues when I tried to test that and let's keep going because there's some more things need to do alright so next if the line of birds is greater than zero if it's not greater than zero which means that we have no birds less left I want to quit this generation or quit running the game so to do that I'm just gonna type brake I'll type run equals false as well as brake just as like a fail-safe but anyways this means essentially if there's no birds left we're gonna quit the game it's what this else statement stands for I just works well as well with this you know pipe Ind thing that we have alright so next thing I need to change output here when we're comparing against 0.5 to be able to put 0 because output is actually a list which means that you know we're gonna get all of the output neurons in a list of the value of those output neurons in this case we only have one output neuron for our examples so we can just do output 0 but in some examples you'd have more than one output neuron and then you'd have to check you know 1 2 3 all the different values alright so that's pretty good I'm trying to remember what else oh this here we need to actually draw all of the birds which we weren't doing which means instead of having bird here we're gonna pass Birds and then what we're gonna do is go into our draw loop here and say instead of just drunk bird we're gonna say 4 birds in our sorry 4 bird in birds and then we're gonna change this parameter to say birds okay so that is I think everything that we need to do now I'm gonna run this and I did this on purpose but you guys gonna see what happens and I think some of you're gonna be kind of a surprise I've already ran this once but let's let's just run this and I'll show you what happens so here we go we have all our birds and surprisingly these birds seem to be doing pretty well on one generation how does that work why we haven't done any training this is generation zero these are all random neural networks why are these guys performing so well well it so happens that in with such a simple game and such a simple network which this is by generating a hundred birds to start we actually kind of come up with almost every possible neural network for this game and just by chance we've actually created two birds here that are doing phenomenally well and it looks like at this rate they're not actually gonna die so this isn't very efficient for most games to just randomly generate a ton and see which ones work well but let's let's just you know for this example it worked to do a ton of birds but let's bump this down to fifty and see if we got any significant changes in performance here and I have a feeling we will alright so this bird is doing okay I think he might run into a pipe though again still he's not he's not hitting anything which is really surprising me that these guys are doing so well okay so I'm gonna bump this down now to twenty because I guess we got lucky and those guys just worked well but let's see what we get now and this guy's going maybe he'll hit a pipe though or and crap out we'll see okay so he hit a pipe so there you go you can see when we generate twenty Birds now we don't get quite as lucky and now we still have to we have to actually go through the process of neuro evolution where before if we generate a ton of different birds we just we kind of get lucky and we generate one that does very well so that's what I wanted to show and you can see that here we're actually running on generation three and you can see kind of the stats popping up here too and this guy's pretty much perfect now now I want I encourage you guys to change and mess around with the fitness functions for this project and see how much worse and better your bird gets and notice that even just very slight changes to the fitness function will change how well this bird does exponentially now the last few things I want to show are kind of talked about this which is actually the statistics involved with this so what's popping up and what we're actually watching as well as how to save this guy so that we can use him immediately rather than having to always train this AI to play the game but after that we're pretty much gonna be done this tutorial series so let's look at some of the stats here so we can see that what we get as a populations average Fitness the standard deviation which I hope you guys know that others I'm not gonna explain it best fitness which is the best bit of that generation the size which is just I guess actually I don't know what size is I think it's like the amount of species maybe I don't know um average adjusted Fitness mean genetic distance honestly don't know what that is population of 20 members in one species it tells you the size the age so how long that species has existed as well as their adjusted fitness and there's stagnation I guess and then you know it tells you how long it took to run generation now let's say in theory that you wanted to run these generations extremely quickly well you wouldn't actually draw the pygame frame and you wouldn't take at 30 seconds what you would do is you would change that so that it runs as fast as possible because right now we're actually just like watching this guy run but in theory we can do all these calculations and just kind of simulate without actually rendering to the screen all of this stuff so that's just something important to note now obviously you know like after three generations this guy's running phenomenally well which really is honestly I'm blowing my mind that's running this well maybe just for the video it's doing that well I don't know so I'll run again and see you know if this will take longer but I guess it just figures it out pretty quickly because we have a very good fitness function for selecting the best birds and that's really important and I'll show you I guess you know if we change and we get rid of removing fitness for hitting a pipe and all of that then let's see what let's see if this makes any difference whatsoever so if we don't remove any fitness for hitting a pipe we'll give these guys a second to see if they say crap out or not why are these pipes staying so high make one go low then you can see that it doesn't do as well at least well if first generation was always random but then after that we can see these guys still do surprisingly well I want to see if any of them hit the pipe so there's one that hits the pipe anyways you guys you kind of get the point you can mess with the fitness you can see how it goes let's add one more thing to this where we actually draw the generation and the amount of alive birds so what I'm gonna do is just put another parameter in here called Gen and we'll just draw the generation as well onto the screen so that we can see that so let's copy this text for score and let's do text equals stat font instead of doing this we're gonna do Gen 4 generate and string Jen and let's just change the position here so that we are drawing it at like 1010 I guess so do 10 10 as our position for the text and then we need to obviously pass a generation so that also means that we need to keep track of a generation so every time that we run this main loop will increment generation which I guess is gonna have to be a global variable so to do that we'll just keep track up Jen up here this is a bad way to do everything by the way guys but it's it's fine for this purposes this is just you know to see something so I'm gonna say global Jen then what I'm gonna do is every time we run this I'm gonna say Jen plus equals 1 okay so Jen plus equals 1 and then we'll pass generation where do we have this loop here in here so that we actually can draw it okay so let's run this now and see if we get generation so there we go we have generation 1 happening right now let's see if these guys die there we're on generation 2 and then you could also draw if you want to see the amount of birds that are currently alive all right so I guess the last thing to mention here and I talked about it briefly at the beginning is saving the best bird and actually using that bird now unfortunately I'm not actually gonna do that in this tutorial series because I was just kind of thinking about it and realizing that it's gonna take another like one or two videos to do that and I really don't want to do more videos in this series especially because we now kind of just wrapped it up and I feel like those problem oast people probably gonna watch them anyways but I'll give you some hints if you are interested in doing that on how you can be be able to so that you're not completely stuck if you want to so essentially there's a module in Python called pickle you can import it really easily just import pickle you don't need to install it or anything and what you can do is just save this object so save this winner object because this is gonna return to you the best genome whenever this stops running so whenever you meet the fitness threshold it's gonna be returned here to winner you can pickle that and save that as a file and then you can load that file in and use that neural network associated with that genome to move the bird up and down now you so need to change or create a new function like this that only runs the bird once there only runs one bird right or you just pass in like only one genome and it just runs through and use that uses that neural network now if you need to be able to actually break out of this wildly because what's gonna happen eventually is while you're training the birds you're gonna get one that's that's as good as it can get right like it's never gonna lose so you need some way to eventually actually be able to get this winner thing here so the way that you do that is you check the score and once the score meet just our reaches a certain threshold you can just break out of this while loop and then that genome will be at the fitness threshold so it'll stop running and it'll be returned to winner so what I do whenever I want to stop running after a while is I just say if score is greater than fifty brink now that's as easy as it is and when you do this once you reach a score up greater than fifty then you'll have a bird that's meets the fitness threshold it'll quit it'll be returned to winner you can pickle it save it and then you can use the neural network associated with that bird to just draw one bird on the screen and set up like a hundred and just have it run through and play the game and that's how you would do that pretty straightforward if you follow along through all this you should be capable of doing that and finally with that being said you guys enjoyed this video please please please give a massive thumbs up it's taking a really long time to make this tutorial series ivory recorded a few episodes just to make sure that everything is clear and works well and please if you are not subscribed to the channel seriously consider doing that because I come up with all kinds of cool stuff like this and I wouldn't want you to miss that in the future so anyways I will see you guys in another tutorial series