├── BG.png ├── Pipe.png ├── README.md ├── Robin.png ├── Ch2 ├── defs.py └── main.py ├── Ch3 ├── defs.py ├── pipe.py └── main.py ├── Ch4 ├── defs.py ├── main.py └── pipe.py ├── Ch5 ├── defs.py ├── bird.py ├── main.py └── pipe.py ├── Ch6 ├── defs.py ├── bird.py ├── main.py └── pipe.py ├── Ch7 ├── defs.py ├── main.py ├── bird.py └── pipe.py ├── Ch10 ├── defs.py ├── nnet.py ├── main.py ├── bird.py └── pipe.py ├── Ch11 ├── defs.py ├── nnet.py ├── main.py ├── pipe.py └── bird.py ├── Ch13 ├── defs.py ├── main.py ├── pipe.py ├── bird.py └── nnet.py ├── Ch14 ├── defs.py ├── main.py ├── pipe.py ├── nnet.py └── bird.py ├── Ch15 ├── defs.py ├── main.py ├── pipe.py ├── nnet.py └── bird.py └── .gitignore /BG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefeversoft/flappy_learning_pygame/HEAD/BG.png -------------------------------------------------------------------------------- /Pipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefeversoft/flappy_learning_pygame/HEAD/Pipe.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flappy_learning_pygame 2 | Tutorial intro to neural nets with flappy 3 | -------------------------------------------------------------------------------- /Robin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluefeversoft/flappy_learning_pygame/HEAD/Robin.png -------------------------------------------------------------------------------- /Ch2/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' -------------------------------------------------------------------------------- /Ch3/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' 8 | 9 | PIPE_FILENAME = '../Pipe.png' 10 | PIPE_SPEED = 70/1000 11 | PIPE_DONE = 1 12 | PIPE_MOVING = 0 13 | PIPE_UPPER = 1 14 | PIPE_LOWER = 0 15 | 16 | -------------------------------------------------------------------------------- /Ch4/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' 8 | 9 | PIPE_FILENAME = '../Pipe.png' 10 | PIPE_SPEED = 70/1000 11 | PIPE_DONE = 1 12 | PIPE_MOVING = 0 13 | PIPE_UPPER = 1 14 | PIPE_LOWER = 0 15 | 16 | PIPE_ADD_GAP = 160 17 | PIPE_MIN = 80 18 | PIPE_MAX = 500 19 | PIPE_START_X = DISPLAY_W 20 | PIPE_GAP_SIZE = 160 21 | PIPE_FIRST = 400 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Ch5/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' 8 | 9 | PIPE_FILENAME = '../Pipe.png' 10 | PIPE_SPEED = 70/1000 11 | PIPE_DONE = 1 12 | PIPE_MOVING = 0 13 | PIPE_UPPER = 1 14 | PIPE_LOWER = 0 15 | 16 | PIPE_ADD_GAP = 160 17 | PIPE_MIN = 80 18 | PIPE_MAX = 500 19 | PIPE_START_X = DISPLAY_W 20 | PIPE_GAP_SIZE = 160 21 | PIPE_FIRST = 400 22 | 23 | BIRD_FILENAME = '../Robin.png' 24 | BIRD_START_SPEED = -0.32 25 | BIRD_START_X = 200 26 | BIRD_START_Y = 200 27 | BIRD_ALIVE = 1 28 | BIRD_DEAD = 0 29 | GRAVITY = 0.001 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /Ch6/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' 8 | 9 | PIPE_FILENAME = '../Pipe.png' 10 | PIPE_SPEED = 70/1000 11 | PIPE_DONE = 1 12 | PIPE_MOVING = 0 13 | PIPE_UPPER = 1 14 | PIPE_LOWER = 0 15 | 16 | PIPE_ADD_GAP = 160 17 | PIPE_MIN = 80 18 | PIPE_MAX = 500 19 | PIPE_START_X = DISPLAY_W 20 | PIPE_GAP_SIZE = 160 21 | PIPE_FIRST = 400 22 | 23 | BIRD_FILENAME = '../Robin.png' 24 | BIRD_START_SPEED = -0.32 25 | BIRD_START_X = 200 26 | BIRD_START_Y = 200 27 | BIRD_ALIVE = 1 28 | BIRD_DEAD = 0 29 | GRAVITY = 0.001 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /Ch7/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' 8 | 9 | PIPE_FILENAME = '../Pipe.png' 10 | PIPE_SPEED = 70/1000 11 | PIPE_DONE = 1 12 | PIPE_MOVING = 0 13 | PIPE_UPPER = 1 14 | PIPE_LOWER = 0 15 | 16 | PIPE_ADD_GAP = 160 17 | PIPE_MIN = 80 18 | PIPE_MAX = 500 19 | PIPE_START_X = DISPLAY_W 20 | PIPE_GAP_SIZE = 160 21 | PIPE_FIRST = 400 22 | 23 | BIRD_FILENAME = '../Robin.png' 24 | BIRD_START_SPEED = -0.32 25 | BIRD_START_X = 200 26 | BIRD_START_Y = 200 27 | BIRD_ALIVE = 1 28 | BIRD_DEAD = 0 29 | GRAVITY = 0.001 30 | 31 | GENERATION_SIZE = 60 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /Ch10/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' 8 | 9 | PIPE_FILENAME = '../Pipe.png' 10 | PIPE_SPEED = 70/1000 11 | PIPE_DONE = 1 12 | PIPE_MOVING = 0 13 | PIPE_UPPER = 1 14 | PIPE_LOWER = 0 15 | 16 | PIPE_ADD_GAP = 160 17 | PIPE_MIN = 80 18 | PIPE_MAX = 500 19 | PIPE_START_X = DISPLAY_W 20 | PIPE_GAP_SIZE = 160 21 | PIPE_FIRST = 400 22 | 23 | BIRD_FILENAME = '../Robin.png' 24 | BIRD_START_SPEED = -0.32 25 | BIRD_START_X = 200 26 | BIRD_START_Y = 200 27 | BIRD_ALIVE = 1 28 | BIRD_DEAD = 0 29 | GRAVITY = 0.001 30 | 31 | GENERATION_SIZE = 60 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /Ch3/pipe.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | 6 | class Pipe(): 7 | 8 | def __init__(self, gameDisplay, x, y, pipe_type): 9 | self.gameDisplay = gameDisplay 10 | self.state = PIPE_MOVING 11 | self.pipe_type = pipe_type 12 | self.img = pygame.image.load(PIPE_FILENAME) 13 | self.rect = self.img.get_rect() 14 | self.set_position(x, y) 15 | print('PIPE_MOVING') 16 | 17 | def set_position(self, x, y): 18 | self.rect.left = x 19 | self.rect.top = y 20 | 21 | def move_position(self, dx, dy): 22 | self.rect.centerx += dx 23 | self.rect.centery += dy 24 | 25 | def draw(self): 26 | self.gameDisplay.blit(self.img, self.rect) 27 | 28 | def check_status(self): 29 | if self.rect.right < 0: 30 | self.state = PIPE_DONE 31 | print('PIPE_DONE') 32 | 33 | def update(self, dt): 34 | if self.state == PIPE_MOVING: 35 | self.move_position(-(PIPE_SPEED * dt), 0) 36 | self.draw() 37 | self.check_status() 38 | -------------------------------------------------------------------------------- /Ch11/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' 8 | 9 | PIPE_FILENAME = '../Pipe.png' 10 | PIPE_SPEED = 70/1000 11 | PIPE_DONE = 1 12 | PIPE_MOVING = 0 13 | PIPE_UPPER = 1 14 | PIPE_LOWER = 0 15 | 16 | PIPE_ADD_GAP = 160 17 | PIPE_MIN = 80 18 | PIPE_MAX = 500 19 | PIPE_START_X = DISPLAY_W 20 | PIPE_GAP_SIZE = 160 21 | PIPE_FIRST = 400 22 | 23 | BIRD_FILENAME = '../Robin.png' 24 | BIRD_START_SPEED = -0.32 25 | BIRD_START_X = 200 26 | BIRD_START_Y = 200 27 | BIRD_ALIVE = 1 28 | BIRD_DEAD = 0 29 | GRAVITY = 0.001 30 | 31 | GENERATION_SIZE = 60 32 | 33 | NNET_INPUTS = 2 34 | NNET_HIDDEN = 5 35 | NNET_OUTPUTS = 1 36 | 37 | JUMP_CHANCE = 0.5 38 | 39 | MAX_Y_DIFF = DISPLAY_H - PIPE_MIN - PIPE_GAP_SIZE/2 40 | MIN_Y_DIFF = PIPE_GAP_SIZE/2 - PIPE_MAX 41 | Y_SHIFT = abs(MIN_Y_DIFF) 42 | NORMALIZER = abs(MIN_Y_DIFF) + MAX_Y_DIFF 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /Ch13/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' 8 | 9 | PIPE_FILENAME = '../Pipe.png' 10 | PIPE_SPEED = 70/1000 11 | PIPE_DONE = 1 12 | PIPE_MOVING = 0 13 | PIPE_UPPER = 1 14 | PIPE_LOWER = 0 15 | 16 | PIPE_ADD_GAP = 160 17 | PIPE_MIN = 80 18 | PIPE_MAX = 500 19 | PIPE_START_X = DISPLAY_W 20 | PIPE_GAP_SIZE = 160 21 | PIPE_FIRST = 400 22 | 23 | BIRD_FILENAME = '../Robin.png' 24 | BIRD_START_SPEED = -0.32 25 | BIRD_START_X = 200 26 | BIRD_START_Y = 200 27 | BIRD_ALIVE = 1 28 | BIRD_DEAD = 0 29 | GRAVITY = 0.001 30 | 31 | GENERATION_SIZE = 60 32 | 33 | NNET_INPUTS = 2 34 | NNET_HIDDEN = 5 35 | NNET_OUTPUTS = 1 36 | 37 | JUMP_CHANCE = 0.5 38 | 39 | MAX_Y_DIFF = DISPLAY_H - PIPE_MIN - PIPE_GAP_SIZE/2 40 | MIN_Y_DIFF = PIPE_GAP_SIZE/2 - PIPE_MAX 41 | Y_SHIFT = abs(MIN_Y_DIFF) 42 | NORMALIZER = abs(MIN_Y_DIFF) + MAX_Y_DIFF 43 | 44 | MUTATION_WEIGHT_MODIFY_CHANCE = 0.2 45 | MUTATION_ARRAY_MIX_PERC = 0.5 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Ch14/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' 8 | 9 | PIPE_FILENAME = '../Pipe.png' 10 | PIPE_SPEED = 70/1000 11 | PIPE_DONE = 1 12 | PIPE_MOVING = 0 13 | PIPE_UPPER = 1 14 | PIPE_LOWER = 0 15 | 16 | PIPE_ADD_GAP = 160 17 | PIPE_MIN = 80 18 | PIPE_MAX = 500 19 | PIPE_START_X = DISPLAY_W 20 | PIPE_GAP_SIZE = 160 21 | PIPE_FIRST = 400 22 | 23 | BIRD_FILENAME = '../Robin.png' 24 | BIRD_START_SPEED = -0.32 25 | BIRD_START_X = 200 26 | BIRD_START_Y = 200 27 | BIRD_ALIVE = 1 28 | BIRD_DEAD = 0 29 | GRAVITY = 0.001 30 | 31 | GENERATION_SIZE = 60 32 | 33 | NNET_INPUTS = 2 34 | NNET_HIDDEN = 5 35 | NNET_OUTPUTS = 1 36 | 37 | JUMP_CHANCE = 0.5 38 | 39 | MAX_Y_DIFF = DISPLAY_H - PIPE_MIN - PIPE_GAP_SIZE/2 40 | MIN_Y_DIFF = PIPE_GAP_SIZE/2 - PIPE_MAX 41 | Y_SHIFT = abs(MIN_Y_DIFF) 42 | NORMALIZER = abs(MIN_Y_DIFF) + MAX_Y_DIFF 43 | 44 | MUTATION_WEIGHT_MODIFY_CHANCE = 0.2 45 | MUTATION_ARRAY_MIX_PERC = 0.5 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Ch10/nnet.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.special 3 | 4 | class Nnet: 5 | 6 | def __init__(self, num_input, num_hidden, num_output): 7 | self.num_input = num_input 8 | self.num_hidden = num_hidden 9 | self.num_output = num_output 10 | self.weight_input_hidden = np.random.uniform(-0.5, 0.5, size=(self.num_hidden, self.num_input)) 11 | self.weight_hidden_output = np.random.uniform(-0.5, 0.5, size=(self.num_output, self.num_hidden)) 12 | self.activation_function = lambda x: scipy.special.expit(x) 13 | 14 | def get_outputs(self, inputs_list): 15 | inputs = np.array(inputs_list, ndmin=2).T 16 | hidden_inputs = np.dot(self.weight_input_hidden, inputs) 17 | hidden_outputs = self.activation_function(hidden_inputs) 18 | final_inputs = np.dot(self.weight_hidden_output, hidden_outputs) 19 | final_outputs = self.activation_function(final_inputs) 20 | return final_outputs 21 | 22 | def get_max_value(self, inputs_list): 23 | outputs = self.get_outputs(inputs_list) 24 | return np.max(outputs) 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /Ch11/nnet.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.special 3 | 4 | class Nnet: 5 | 6 | def __init__(self, num_input, num_hidden, num_output): 7 | self.num_input = num_input 8 | self.num_hidden = num_hidden 9 | self.num_output = num_output 10 | self.weight_input_hidden = np.random.uniform(-0.5, 0.5, size=(self.num_hidden, self.num_input)) 11 | self.weight_hidden_output = np.random.uniform(-0.5, 0.5, size=(self.num_output, self.num_hidden)) 12 | self.activation_function = lambda x: scipy.special.expit(x) 13 | 14 | def get_outputs(self, inputs_list): 15 | inputs = np.array(inputs_list, ndmin=2).T 16 | hidden_inputs = np.dot(self.weight_input_hidden, inputs) 17 | hidden_outputs = self.activation_function(hidden_inputs) 18 | final_inputs = np.dot(self.weight_hidden_output, hidden_outputs) 19 | final_outputs = self.activation_function(final_inputs) 20 | return final_outputs 21 | 22 | def get_max_value(self, inputs_list): 23 | outputs = self.get_outputs(inputs_list) 24 | return np.max(outputs) 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /Ch15/defs.py: -------------------------------------------------------------------------------- 1 | DISPLAY_W = 960 2 | DISPLAY_H = 540 3 | FPS = 30 4 | 5 | DATA_FONT_SIZE = 18 6 | DATA_FONT_COLOR = (40,40,40) 7 | BG_FILENAME = '../BG.png' 8 | 9 | PIPE_FILENAME = '../Pipe.png' 10 | PIPE_SPEED = 70/1000 11 | PIPE_DONE = 1 12 | PIPE_MOVING = 0 13 | PIPE_UPPER = 1 14 | PIPE_LOWER = 0 15 | 16 | PIPE_ADD_GAP = 160 17 | PIPE_MIN = 80 18 | PIPE_MAX = 500 19 | PIPE_START_X = DISPLAY_W 20 | PIPE_GAP_SIZE = 160 21 | PIPE_FIRST = 400 22 | 23 | BIRD_FILENAME = '../Robin.png' 24 | BIRD_START_SPEED = -0.32 25 | BIRD_START_X = 200 26 | BIRD_START_Y = 200 27 | BIRD_ALIVE = 1 28 | BIRD_DEAD = 0 29 | GRAVITY = 0.001 30 | 31 | GENERATION_SIZE = 60 32 | 33 | NNET_INPUTS = 2 34 | NNET_HIDDEN = 5 35 | NNET_OUTPUTS = 1 36 | 37 | JUMP_CHANCE = 0.5 38 | 39 | MAX_Y_DIFF = DISPLAY_H - PIPE_MIN - PIPE_GAP_SIZE/2 40 | MIN_Y_DIFF = PIPE_GAP_SIZE/2 - PIPE_MAX 41 | Y_SHIFT = abs(MIN_Y_DIFF) 42 | NORMALIZER = abs(MIN_Y_DIFF) + MAX_Y_DIFF 43 | 44 | MUTATION_WEIGHT_MODIFY_CHANCE = 0.2 45 | MUTATION_ARRAY_MIX_PERC = 0.5 46 | MUTATION_CUT_OFF = 0.4 47 | MUTATION_BAD_TO_KEEP = 0.2 48 | MUTATION_MODIFY_CHANCE_LIMIT = 0.4 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Ch5/bird.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | class Bird(): 6 | 7 | def __init__(self, gameDisplay): 8 | self.gameDisplay = gameDisplay 9 | self.state = BIRD_ALIVE 10 | self.img = pygame.image.load(BIRD_FILENAME) 11 | self.rect = self.img.get_rect() 12 | self.speed = 0 13 | self.time_lived = 0 14 | self.set_position(BIRD_START_X, BIRD_START_Y) 15 | 16 | def set_position(self, x, y): 17 | self.rect.centerx = x 18 | self.rect.centery = y 19 | 20 | def move(self, dt): 21 | 22 | distance = 0 23 | new_speed = 0 24 | 25 | distance = (self.speed * dt) + (0.5 * GRAVITY * dt * dt) 26 | new_speed = self.speed + (GRAVITY * dt) 27 | 28 | self.rect.centery += distance 29 | self.speed = new_speed 30 | 31 | if self.rect.top < 0: 32 | self.rect.top = 0 33 | self.speed = 0 34 | 35 | def jump(self): 36 | self.speed = BIRD_START_SPEED 37 | 38 | def draw(self): 39 | self.gameDisplay.blit(self.img, self.rect) 40 | 41 | def check_status(self): 42 | if self.rect.bottom > DISPLAY_H: 43 | self.state = BIRD_DEAD 44 | print('Birdie died') 45 | 46 | def update(self, dt): 47 | if self.state == BIRD_ALIVE: 48 | self.time_lived += dt 49 | self.move(dt) 50 | self.draw() 51 | self.check_status() 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Ch2/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | 4 | def update_label(data, title, font, x, y, gameDisplay): 5 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 6 | gameDisplay.blit(label, (x, y)) 7 | return y 8 | 9 | def update_data_labels(gameDisplay, dt, game_time, font): 10 | y_pos = 10 11 | gap = 20 12 | x_pos = 10 13 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 14 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 15 | 16 | 17 | def run_game(): 18 | 19 | pygame.init() 20 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 21 | pygame.display.set_caption('Learn to fly') 22 | 23 | running = True 24 | bgImg = pygame.image.load(BG_FILENAME) 25 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 26 | 27 | clock = pygame.time.Clock() 28 | dt = 0 29 | game_time = 0 30 | 31 | while running: 32 | 33 | dt = clock.tick(FPS) 34 | game_time += dt 35 | 36 | gameDisplay.blit(bgImg, (0, 0)) 37 | 38 | 39 | for event in pygame.event.get(): 40 | if event.type == pygame.QUIT: 41 | running = False 42 | elif event.type == pygame.KEYDOWN: 43 | running = False 44 | 45 | update_data_labels(gameDisplay, dt, game_time, label_font) 46 | 47 | pygame.display.update() 48 | 49 | 50 | 51 | if __name__== "__main__": 52 | run_game() 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /Ch3/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | from pipe import Pipe 4 | 5 | def update_label(data, title, font, x, y, gameDisplay): 6 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 7 | gameDisplay.blit(label, (x, y)) 8 | return y 9 | 10 | def update_data_labels(gameDisplay, dt, game_time, font): 11 | y_pos = 10 12 | gap = 20 13 | x_pos = 10 14 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 15 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 16 | 17 | 18 | def run_game(): 19 | 20 | pygame.init() 21 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 22 | pygame.display.set_caption('Learn to fly') 23 | 24 | running = True 25 | bgImg = pygame.image.load(BG_FILENAME) 26 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 27 | 28 | clock = pygame.time.Clock() 29 | dt = 0 30 | game_time = 0 31 | 32 | pi = Pipe(gameDisplay, DISPLAY_W, 300, PIPE_LOWER) 33 | 34 | while running: 35 | 36 | dt = clock.tick(FPS) 37 | game_time += dt 38 | 39 | gameDisplay.blit(bgImg, (0, 0)) 40 | 41 | 42 | for event in pygame.event.get(): 43 | if event.type == pygame.QUIT: 44 | running = False 45 | elif event.type == pygame.KEYDOWN: 46 | running = False 47 | 48 | update_data_labels(gameDisplay, dt, game_time, label_font) 49 | pi.update(dt) 50 | 51 | pygame.display.update() 52 | 53 | 54 | 55 | if __name__== "__main__": 56 | run_game() 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Ch6/bird.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | class Bird(): 6 | 7 | def __init__(self, gameDisplay): 8 | self.gameDisplay = gameDisplay 9 | self.state = BIRD_ALIVE 10 | self.img = pygame.image.load(BIRD_FILENAME) 11 | self.rect = self.img.get_rect() 12 | self.speed = 0 13 | self.time_lived = 0 14 | self.set_position(BIRD_START_X, BIRD_START_Y) 15 | 16 | def set_position(self, x, y): 17 | self.rect.centerx = x 18 | self.rect.centery = y 19 | 20 | def move(self, dt): 21 | 22 | distance = 0 23 | new_speed = 0 24 | 25 | distance = (self.speed * dt) + (0.5 * GRAVITY * dt * dt) 26 | new_speed = self.speed + (GRAVITY * dt) 27 | 28 | self.rect.centery += distance 29 | self.speed = new_speed 30 | 31 | if self.rect.top < 0: 32 | self.rect.top = 0 33 | self.speed = 0 34 | 35 | def jump(self): 36 | self.speed = BIRD_START_SPEED 37 | 38 | def draw(self): 39 | self.gameDisplay.blit(self.img, self.rect) 40 | 41 | def check_status(self, pipes): 42 | if self.rect.bottom > DISPLAY_H: 43 | self.state = BIRD_DEAD 44 | else: 45 | self.check_hits(pipes) 46 | 47 | def check_hits(self, pipes): 48 | for p in pipes: 49 | if p.rect.colliderect(self.rect): 50 | self.state = BIRD_DEAD 51 | break 52 | 53 | def update(self, dt, pipes): 54 | if self.state == BIRD_ALIVE: 55 | self.time_lived += dt 56 | self.move(dt) 57 | self.draw() 58 | self.check_status(pipes) 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /Ch4/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | from pipe import PipeCollection 4 | 5 | def update_label(data, title, font, x, y, gameDisplay): 6 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 7 | gameDisplay.blit(label, (x, y)) 8 | return y 9 | 10 | def update_data_labels(gameDisplay, dt, game_time, font): 11 | y_pos = 10 12 | gap = 20 13 | x_pos = 10 14 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 15 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 16 | 17 | 18 | def run_game(): 19 | 20 | pygame.init() 21 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 22 | pygame.display.set_caption('Learn to fly') 23 | 24 | running = True 25 | bgImg = pygame.image.load(BG_FILENAME) 26 | pipes = PipeCollection(gameDisplay) 27 | pipes.create_new_set() 28 | 29 | 30 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 31 | 32 | clock = pygame.time.Clock() 33 | dt = 0 34 | game_time = 0 35 | 36 | 37 | 38 | while running: 39 | 40 | dt = clock.tick(FPS) 41 | game_time += dt 42 | 43 | gameDisplay.blit(bgImg, (0, 0)) 44 | 45 | 46 | for event in pygame.event.get(): 47 | if event.type == pygame.QUIT: 48 | running = False 49 | elif event.type == pygame.KEYDOWN: 50 | running = False 51 | 52 | update_data_labels(gameDisplay, dt, game_time, label_font) 53 | pipes.update(dt) 54 | 55 | pygame.display.update() 56 | 57 | 58 | 59 | if __name__== "__main__": 60 | run_game() 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /Ch5/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | from pipe import PipeCollection 4 | from bird import Bird 5 | 6 | def update_label(data, title, font, x, y, gameDisplay): 7 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 8 | gameDisplay.blit(label, (x, y)) 9 | return y 10 | 11 | def update_data_labels(gameDisplay, dt, game_time, font): 12 | y_pos = 10 13 | gap = 20 14 | x_pos = 10 15 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 16 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 17 | 18 | 19 | def run_game(): 20 | 21 | pygame.init() 22 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 23 | pygame.display.set_caption('Learn to fly') 24 | 25 | running = True 26 | bgImg = pygame.image.load(BG_FILENAME) 27 | pipes = PipeCollection(gameDisplay) 28 | pipes.create_new_set() 29 | bird = Bird(gameDisplay) 30 | 31 | 32 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 33 | 34 | clock = pygame.time.Clock() 35 | dt = 0 36 | game_time = 0 37 | 38 | 39 | 40 | while running: 41 | 42 | dt = clock.tick(FPS) 43 | game_time += dt 44 | 45 | gameDisplay.blit(bgImg, (0, 0)) 46 | 47 | 48 | for event in pygame.event.get(): 49 | if event.type == pygame.QUIT: 50 | running = False 51 | elif event.type == pygame.KEYDOWN: 52 | if event.key == pygame.K_SPACE: 53 | bird.jump() 54 | else: 55 | running = False 56 | 57 | update_data_labels(gameDisplay, dt, game_time, label_font) 58 | pipes.update(dt) 59 | bird.update(dt) 60 | 61 | pygame.display.update() 62 | 63 | 64 | 65 | if __name__== "__main__": 66 | run_game() 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Ch6/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | from pipe import PipeCollection 4 | from bird import Bird 5 | 6 | def update_label(data, title, font, x, y, gameDisplay): 7 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 8 | gameDisplay.blit(label, (x, y)) 9 | return y 10 | 11 | def update_data_labels(gameDisplay, dt, game_time, num_iterations, font): 12 | y_pos = 10 13 | gap = 20 14 | x_pos = 10 15 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 16 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 17 | y_pos = update_label(num_iterations,'Iteration', font, x_pos, y_pos + gap, gameDisplay) 18 | 19 | 20 | def run_game(): 21 | 22 | pygame.init() 23 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 24 | pygame.display.set_caption('Learn to fly') 25 | 26 | running = True 27 | bgImg = pygame.image.load(BG_FILENAME) 28 | pipes = PipeCollection(gameDisplay) 29 | pipes.create_new_set() 30 | bird = Bird(gameDisplay) 31 | 32 | 33 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 34 | 35 | clock = pygame.time.Clock() 36 | dt = 0 37 | game_time = 0 38 | num_iterations = 1 39 | 40 | while running: 41 | 42 | dt = clock.tick(FPS) 43 | game_time += dt 44 | 45 | gameDisplay.blit(bgImg, (0, 0)) 46 | 47 | 48 | for event in pygame.event.get(): 49 | if event.type == pygame.QUIT: 50 | running = False 51 | elif event.type == pygame.KEYDOWN: 52 | if event.key == pygame.K_SPACE: 53 | bird.jump() 54 | else: 55 | running = False 56 | 57 | pipes.update(dt) 58 | bird.update(dt, pipes.pipes) 59 | 60 | if bird.state == BIRD_DEAD: 61 | pipes.create_new_set() 62 | game_time = 0 63 | bird = Bird(gameDisplay) 64 | num_iterations += 1 65 | 66 | update_data_labels(gameDisplay, dt, game_time, num_iterations, label_font) 67 | pygame.display.update() 68 | 69 | 70 | 71 | if __name__== "__main__": 72 | run_game() 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /Ch14/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | from pipe import PipeCollection 4 | from bird import BirdCollection 5 | 6 | def update_label(data, title, font, x, y, gameDisplay): 7 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 8 | gameDisplay.blit(label, (x, y)) 9 | return y 10 | 11 | def update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, font): 12 | y_pos = 10 13 | gap = 20 14 | x_pos = 10 15 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 16 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 17 | y_pos = update_label(num_iterations,'Iteration', font, x_pos, y_pos + gap, gameDisplay) 18 | y_pos = update_label(num_alive,'Alive', font, x_pos, y_pos + gap, gameDisplay) 19 | 20 | 21 | def run_game(): 22 | 23 | pygame.init() 24 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 25 | pygame.display.set_caption('Learn to fly') 26 | 27 | running = True 28 | bgImg = pygame.image.load(BG_FILENAME) 29 | pipes = PipeCollection(gameDisplay) 30 | pipes.create_new_set() 31 | birds = BirdCollection(gameDisplay) 32 | 33 | 34 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 35 | 36 | clock = pygame.time.Clock() 37 | dt = 0 38 | game_time = 0 39 | num_iterations = 1 40 | 41 | while running: 42 | 43 | dt = clock.tick(FPS) 44 | game_time += dt 45 | 46 | gameDisplay.blit(bgImg, (0, 0)) 47 | 48 | 49 | for event in pygame.event.get(): 50 | if event.type == pygame.QUIT: 51 | running = False 52 | elif event.type == pygame.KEYDOWN: 53 | running = False 54 | 55 | pipes.update(dt) 56 | num_alive = birds.update(dt, pipes.pipes) 57 | 58 | if num_alive == 0: 59 | pipes.create_new_set() 60 | game_time = 0 61 | birds.evolve_population() 62 | num_iterations += 1 63 | 64 | update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, label_font) 65 | pygame.display.update() 66 | 67 | 68 | 69 | if __name__== "__main__": 70 | run_game() 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Ch15/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | from pipe import PipeCollection 4 | from bird import BirdCollection 5 | 6 | def update_label(data, title, font, x, y, gameDisplay): 7 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 8 | gameDisplay.blit(label, (x, y)) 9 | return y 10 | 11 | def update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, font): 12 | y_pos = 10 13 | gap = 20 14 | x_pos = 10 15 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 16 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 17 | y_pos = update_label(num_iterations,'Iteration', font, x_pos, y_pos + gap, gameDisplay) 18 | y_pos = update_label(num_alive,'Alive', font, x_pos, y_pos + gap, gameDisplay) 19 | 20 | 21 | def run_game(): 22 | 23 | pygame.init() 24 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 25 | pygame.display.set_caption('Learn to fly') 26 | 27 | running = True 28 | bgImg = pygame.image.load(BG_FILENAME) 29 | pipes = PipeCollection(gameDisplay) 30 | pipes.create_new_set() 31 | birds = BirdCollection(gameDisplay) 32 | 33 | 34 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 35 | 36 | clock = pygame.time.Clock() 37 | dt = 0 38 | game_time = 0 39 | num_iterations = 1 40 | 41 | while running: 42 | 43 | dt = clock.tick(FPS) 44 | game_time += dt 45 | 46 | gameDisplay.blit(bgImg, (0, 0)) 47 | 48 | 49 | for event in pygame.event.get(): 50 | if event.type == pygame.QUIT: 51 | running = False 52 | elif event.type == pygame.KEYDOWN: 53 | running = False 54 | 55 | pipes.update(dt) 56 | num_alive = birds.update(dt, pipes.pipes) 57 | 58 | if num_alive == 0: 59 | pipes.create_new_set() 60 | game_time = 0 61 | birds.evolve_population() 62 | num_iterations += 1 63 | 64 | update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, label_font) 65 | pygame.display.update() 66 | 67 | 68 | 69 | if __name__== "__main__": 70 | run_game() 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Ch10/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | from pipe import PipeCollection 4 | from bird import BirdCollection 5 | 6 | def update_label(data, title, font, x, y, gameDisplay): 7 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 8 | gameDisplay.blit(label, (x, y)) 9 | return y 10 | 11 | def update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, font): 12 | y_pos = 10 13 | gap = 20 14 | x_pos = 10 15 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 16 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 17 | y_pos = update_label(num_iterations,'Iteration', font, x_pos, y_pos + gap, gameDisplay) 18 | y_pos = update_label(num_alive,'Alive', font, x_pos, y_pos + gap, gameDisplay) 19 | 20 | 21 | def run_game(): 22 | 23 | pygame.init() 24 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 25 | pygame.display.set_caption('Learn to fly') 26 | 27 | running = True 28 | bgImg = pygame.image.load(BG_FILENAME) 29 | pipes = PipeCollection(gameDisplay) 30 | pipes.create_new_set() 31 | birds = BirdCollection(gameDisplay) 32 | 33 | 34 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 35 | 36 | clock = pygame.time.Clock() 37 | dt = 0 38 | game_time = 0 39 | num_iterations = 1 40 | 41 | while running: 42 | 43 | dt = clock.tick(FPS) 44 | game_time += dt 45 | 46 | gameDisplay.blit(bgImg, (0, 0)) 47 | 48 | 49 | for event in pygame.event.get(): 50 | if event.type == pygame.QUIT: 51 | running = False 52 | elif event.type == pygame.KEYDOWN: 53 | running = False 54 | 55 | pipes.update(dt) 56 | num_alive = birds.update(dt, pipes.pipes) 57 | 58 | if num_alive == 0: 59 | pipes.create_new_set() 60 | game_time = 0 61 | birds.create_new_generation() 62 | num_iterations += 1 63 | 64 | update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, label_font) 65 | pygame.display.update() 66 | 67 | 68 | 69 | if __name__== "__main__": 70 | run_game() 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Ch11/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | from pipe import PipeCollection 4 | from bird import BirdCollection 5 | 6 | def update_label(data, title, font, x, y, gameDisplay): 7 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 8 | gameDisplay.blit(label, (x, y)) 9 | return y 10 | 11 | def update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, font): 12 | y_pos = 10 13 | gap = 20 14 | x_pos = 10 15 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 16 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 17 | y_pos = update_label(num_iterations,'Iteration', font, x_pos, y_pos + gap, gameDisplay) 18 | y_pos = update_label(num_alive,'Alive', font, x_pos, y_pos + gap, gameDisplay) 19 | 20 | 21 | def run_game(): 22 | 23 | pygame.init() 24 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 25 | pygame.display.set_caption('Learn to fly') 26 | 27 | running = True 28 | bgImg = pygame.image.load(BG_FILENAME) 29 | pipes = PipeCollection(gameDisplay) 30 | pipes.create_new_set() 31 | birds = BirdCollection(gameDisplay) 32 | 33 | 34 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 35 | 36 | clock = pygame.time.Clock() 37 | dt = 0 38 | game_time = 0 39 | num_iterations = 1 40 | 41 | while running: 42 | 43 | dt = clock.tick(FPS) 44 | game_time += dt 45 | 46 | gameDisplay.blit(bgImg, (0, 0)) 47 | 48 | 49 | for event in pygame.event.get(): 50 | if event.type == pygame.QUIT: 51 | running = False 52 | elif event.type == pygame.KEYDOWN: 53 | running = False 54 | 55 | pipes.update(dt) 56 | num_alive = birds.update(dt, pipes.pipes) 57 | 58 | if num_alive == 0: 59 | pipes.create_new_set() 60 | game_time = 0 61 | birds.create_new_generation() 62 | num_iterations += 1 63 | 64 | update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, label_font) 65 | pygame.display.update() 66 | 67 | 68 | 69 | if __name__== "__main__": 70 | run_game() 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Ch13/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | from pipe import PipeCollection 4 | from bird import BirdCollection 5 | 6 | def update_label(data, title, font, x, y, gameDisplay): 7 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 8 | gameDisplay.blit(label, (x, y)) 9 | return y 10 | 11 | def update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, font): 12 | y_pos = 10 13 | gap = 20 14 | x_pos = 10 15 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 16 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 17 | y_pos = update_label(num_iterations,'Iteration', font, x_pos, y_pos + gap, gameDisplay) 18 | y_pos = update_label(num_alive,'Alive', font, x_pos, y_pos + gap, gameDisplay) 19 | 20 | 21 | def run_game(): 22 | 23 | pygame.init() 24 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 25 | pygame.display.set_caption('Learn to fly') 26 | 27 | running = True 28 | bgImg = pygame.image.load(BG_FILENAME) 29 | pipes = PipeCollection(gameDisplay) 30 | pipes.create_new_set() 31 | birds = BirdCollection(gameDisplay) 32 | 33 | 34 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 35 | 36 | clock = pygame.time.Clock() 37 | dt = 0 38 | game_time = 0 39 | num_iterations = 1 40 | 41 | while running: 42 | 43 | dt = clock.tick(FPS) 44 | game_time += dt 45 | 46 | gameDisplay.blit(bgImg, (0, 0)) 47 | 48 | 49 | for event in pygame.event.get(): 50 | if event.type == pygame.QUIT: 51 | running = False 52 | elif event.type == pygame.KEYDOWN: 53 | running = False 54 | 55 | pipes.update(dt) 56 | num_alive = birds.update(dt, pipes.pipes) 57 | 58 | if num_alive == 0: 59 | pipes.create_new_set() 60 | game_time = 0 61 | birds.create_new_generation() 62 | num_iterations += 1 63 | 64 | update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, label_font) 65 | pygame.display.update() 66 | 67 | 68 | 69 | if __name__== "__main__": 70 | run_game() 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Ch7/main.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from defs import * 3 | from pipe import PipeCollection 4 | from bird import BirdCollection 5 | 6 | def update_label(data, title, font, x, y, gameDisplay): 7 | label = font.render('{} {}'.format(title, data), 1, DATA_FONT_COLOR) 8 | gameDisplay.blit(label, (x, y)) 9 | return y 10 | 11 | def update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, font): 12 | y_pos = 10 13 | gap = 20 14 | x_pos = 10 15 | y_pos = update_label(round(1000/dt,2), 'FPS', font, x_pos, y_pos + gap, gameDisplay) 16 | y_pos = update_label(round(game_time/1000,2),'Game time', font, x_pos, y_pos + gap, gameDisplay) 17 | y_pos = update_label(num_iterations,'Iteration', font, x_pos, y_pos + gap, gameDisplay) 18 | y_pos = update_label(num_alive,'Alive', font, x_pos, y_pos + gap, gameDisplay) 19 | 20 | 21 | def run_game(): 22 | 23 | pygame.init() 24 | gameDisplay = pygame.display.set_mode((DISPLAY_W,DISPLAY_H)) 25 | pygame.display.set_caption('Learn to fly') 26 | 27 | running = True 28 | bgImg = pygame.image.load(BG_FILENAME) 29 | pipes = PipeCollection(gameDisplay) 30 | pipes.create_new_set() 31 | birds = BirdCollection(gameDisplay) 32 | 33 | 34 | label_font = pygame.font.SysFont("monospace", DATA_FONT_SIZE) 35 | 36 | clock = pygame.time.Clock() 37 | dt = 0 38 | game_time = 0 39 | num_iterations = 1 40 | 41 | while running: 42 | 43 | dt = clock.tick(FPS) 44 | game_time += dt 45 | 46 | gameDisplay.blit(bgImg, (0, 0)) 47 | 48 | 49 | for event in pygame.event.get(): 50 | if event.type == pygame.QUIT: 51 | running = False 52 | elif event.type == pygame.KEYDOWN: 53 | running = False 54 | 55 | pipes.update(dt) 56 | num_alive = birds.update(dt, pipes.pipes) 57 | 58 | if num_alive == 0: 59 | pipes.create_new_set() 60 | game_time = 0 61 | birds.create_new_generation() 62 | num_iterations += 1 63 | 64 | update_data_labels(gameDisplay, dt, game_time, num_iterations, num_alive, label_font) 65 | pygame.display.update() 66 | 67 | 68 | 69 | if __name__== "__main__": 70 | run_game() 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Ch10/bird.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | class Bird(): 6 | 7 | def __init__(self, gameDisplay): 8 | self.gameDisplay = gameDisplay 9 | self.state = BIRD_ALIVE 10 | self.img = pygame.image.load(BIRD_FILENAME) 11 | self.rect = self.img.get_rect() 12 | self.speed = 0 13 | self.time_lived = 0 14 | self.set_position(BIRD_START_X, BIRD_START_Y) 15 | 16 | def set_position(self, x, y): 17 | self.rect.centerx = x 18 | self.rect.centery = y 19 | 20 | def move(self, dt): 21 | 22 | distance = 0 23 | new_speed = 0 24 | 25 | distance = (self.speed * dt) + (0.5 * GRAVITY * dt * dt) 26 | new_speed = self.speed + (GRAVITY * dt) 27 | 28 | self.rect.centery += distance 29 | self.speed = new_speed 30 | 31 | if self.rect.top < 0: 32 | self.rect.top = 0 33 | self.speed = 0 34 | 35 | def jump(self): 36 | self.speed = BIRD_START_SPEED 37 | 38 | def draw(self): 39 | self.gameDisplay.blit(self.img, self.rect) 40 | 41 | def check_status(self, pipes): 42 | if self.rect.bottom > DISPLAY_H: 43 | self.state = BIRD_DEAD 44 | else: 45 | self.check_hits(pipes) 46 | 47 | def check_hits(self, pipes): 48 | for p in pipes: 49 | if p.rect.colliderect(self.rect): 50 | self.state = BIRD_DEAD 51 | break 52 | 53 | def update(self, dt, pipes): 54 | if self.state == BIRD_ALIVE: 55 | self.time_lived += dt 56 | self.move(dt) 57 | self.draw() 58 | self.check_status(pipes) 59 | 60 | 61 | 62 | class BirdCollection(): 63 | 64 | def __init__(self, gameDisplay): 65 | self.gameDisplay = gameDisplay 66 | self.birds = [] 67 | self.create_new_generation() 68 | 69 | def create_new_generation(self): 70 | self.birds = [] 71 | for i in range(0, GENERATION_SIZE): 72 | self.birds.append(Bird(self.gameDisplay)) 73 | 74 | def update(self, dt, pipes): 75 | num_alive = 0 76 | for b in self.birds: 77 | if random.randint(0,4) == 1: 78 | b.jump() 79 | b.update(dt, pipes) 80 | if b.state == BIRD_ALIVE: 81 | num_alive += 1 82 | 83 | return num_alive 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Ch7/bird.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | class Bird(): 6 | 7 | def __init__(self, gameDisplay): 8 | self.gameDisplay = gameDisplay 9 | self.state = BIRD_ALIVE 10 | self.img = pygame.image.load(BIRD_FILENAME) 11 | self.rect = self.img.get_rect() 12 | self.speed = 0 13 | self.time_lived = 0 14 | self.set_position(BIRD_START_X, BIRD_START_Y) 15 | 16 | def set_position(self, x, y): 17 | self.rect.centerx = x 18 | self.rect.centery = y 19 | 20 | def move(self, dt): 21 | 22 | distance = 0 23 | new_speed = 0 24 | 25 | distance = (self.speed * dt) + (0.5 * GRAVITY * dt * dt) 26 | new_speed = self.speed + (GRAVITY * dt) 27 | 28 | self.rect.centery += distance 29 | self.speed = new_speed 30 | 31 | if self.rect.top < 0: 32 | self.rect.top = 0 33 | self.speed = 0 34 | 35 | def jump(self): 36 | self.speed = BIRD_START_SPEED 37 | 38 | def draw(self): 39 | self.gameDisplay.blit(self.img, self.rect) 40 | 41 | def check_status(self, pipes): 42 | if self.rect.bottom > DISPLAY_H: 43 | self.state = BIRD_DEAD 44 | else: 45 | self.check_hits(pipes) 46 | 47 | def check_hits(self, pipes): 48 | for p in pipes: 49 | if p.rect.colliderect(self.rect): 50 | self.state = BIRD_DEAD 51 | break 52 | 53 | def update(self, dt, pipes): 54 | if self.state == BIRD_ALIVE: 55 | self.time_lived += dt 56 | self.move(dt) 57 | self.draw() 58 | self.check_status(pipes) 59 | 60 | 61 | 62 | class BirdCollection(): 63 | 64 | def __init__(self, gameDisplay): 65 | self.gameDisplay = gameDisplay 66 | self.birds = [] 67 | self.create_new_generation() 68 | 69 | def create_new_generation(self): 70 | self.birds = [] 71 | for i in range(0, GENERATION_SIZE): 72 | self.birds.append(Bird(self.gameDisplay)) 73 | 74 | def update(self, dt, pipes): 75 | num_alive = 0 76 | for b in self.birds: 77 | if random.randint(0,4) == 1: 78 | b.jump() 79 | b.update(dt, pipes) 80 | if b.state == BIRD_ALIVE: 81 | num_alive += 1 82 | 83 | return num_alive 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Ch4/pipe.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | 6 | class Pipe(): 7 | 8 | def __init__(self, gameDisplay, x, y, pipe_type): 9 | self.gameDisplay = gameDisplay 10 | self.state = PIPE_MOVING 11 | self.pipe_type = pipe_type 12 | self.img = pygame.image.load(PIPE_FILENAME) 13 | self.rect = self.img.get_rect() 14 | if pipe_type == PIPE_UPPER: 15 | y = y - self.rect.height 16 | self.set_position(x, y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.left = x 20 | self.rect.top = y 21 | 22 | def move_position(self, dx, dy): 23 | self.rect.centerx += dx 24 | self.rect.centery += dy 25 | 26 | def draw(self): 27 | self.gameDisplay.blit(self.img, self.rect) 28 | 29 | def check_status(self): 30 | if self.rect.right < 0: 31 | self.state = PIPE_DONE 32 | 33 | def update(self, dt): 34 | if self.state == PIPE_MOVING: 35 | self.move_position(-(PIPE_SPEED * dt), 0) 36 | self.draw() 37 | self.check_status() 38 | 39 | 40 | class PipeCollection(): 41 | 42 | def __init__(self, gameDisplay): 43 | self.gameDisplay = gameDisplay 44 | self.pipes = [] 45 | 46 | 47 | def add_new_pipe_pair(self, x): 48 | 49 | top_y = random.randint(PIPE_MIN, PIPE_MAX - PIPE_GAP_SIZE) 50 | bottom_y = top_y + PIPE_GAP_SIZE 51 | 52 | p1 = Pipe(self.gameDisplay, x, top_y, PIPE_UPPER) 53 | p2 = Pipe(self.gameDisplay, x, bottom_y, PIPE_LOWER) 54 | 55 | self.pipes.append(p1) 56 | self.pipes.append(p2) 57 | 58 | def create_new_set(self): 59 | self.pipes = [] 60 | placed = PIPE_FIRST 61 | 62 | while placed < DISPLAY_W: 63 | self.add_new_pipe_pair(placed) 64 | placed += PIPE_ADD_GAP 65 | 66 | def update(self, dt): 67 | 68 | rightmost = 0 69 | 70 | for p in self.pipes: 71 | p.update(dt) 72 | if p.pipe_type == PIPE_UPPER: 73 | if p.rect.left > rightmost: 74 | rightmost = p.rect.left 75 | 76 | if rightmost < (DISPLAY_W - PIPE_ADD_GAP): 77 | self.add_new_pipe_pair(DISPLAY_W) 78 | 79 | self.pipes = [p for p in self.pipes if p.state == PIPE_MOVING] 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Ch5/pipe.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | 6 | class Pipe(): 7 | 8 | def __init__(self, gameDisplay, x, y, pipe_type): 9 | self.gameDisplay = gameDisplay 10 | self.state = PIPE_MOVING 11 | self.pipe_type = pipe_type 12 | self.img = pygame.image.load(PIPE_FILENAME) 13 | self.rect = self.img.get_rect() 14 | if pipe_type == PIPE_UPPER: 15 | y = y - self.rect.height 16 | self.set_position(x, y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.left = x 20 | self.rect.top = y 21 | 22 | def move_position(self, dx, dy): 23 | self.rect.centerx += dx 24 | self.rect.centery += dy 25 | 26 | def draw(self): 27 | self.gameDisplay.blit(self.img, self.rect) 28 | 29 | def check_status(self): 30 | if self.rect.right < 0: 31 | self.state = PIPE_DONE 32 | 33 | def update(self, dt): 34 | if self.state == PIPE_MOVING: 35 | self.move_position(-(PIPE_SPEED * dt), 0) 36 | self.draw() 37 | self.check_status() 38 | 39 | 40 | class PipeCollection(): 41 | 42 | def __init__(self, gameDisplay): 43 | self.gameDisplay = gameDisplay 44 | self.pipes = [] 45 | 46 | 47 | def add_new_pipe_pair(self, x): 48 | 49 | top_y = random.randint(PIPE_MIN, PIPE_MAX - PIPE_GAP_SIZE) 50 | bottom_y = top_y + PIPE_GAP_SIZE 51 | 52 | p1 = Pipe(self.gameDisplay, x, top_y, PIPE_UPPER) 53 | p2 = Pipe(self.gameDisplay, x, bottom_y, PIPE_LOWER) 54 | 55 | self.pipes.append(p1) 56 | self.pipes.append(p2) 57 | 58 | def create_new_set(self): 59 | self.pipes = [] 60 | placed = PIPE_FIRST 61 | 62 | while placed < DISPLAY_W: 63 | self.add_new_pipe_pair(placed) 64 | placed += PIPE_ADD_GAP 65 | 66 | def update(self, dt): 67 | 68 | rightmost = 0 69 | 70 | for p in self.pipes: 71 | p.update(dt) 72 | if p.pipe_type == PIPE_UPPER: 73 | if p.rect.left > rightmost: 74 | rightmost = p.rect.left 75 | 76 | if rightmost < (DISPLAY_W - PIPE_ADD_GAP): 77 | self.add_new_pipe_pair(DISPLAY_W) 78 | 79 | self.pipes = [p for p in self.pipes if p.state == PIPE_MOVING] 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Ch6/pipe.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | 6 | class Pipe(): 7 | 8 | def __init__(self, gameDisplay, x, y, pipe_type): 9 | self.gameDisplay = gameDisplay 10 | self.state = PIPE_MOVING 11 | self.pipe_type = pipe_type 12 | self.img = pygame.image.load(PIPE_FILENAME) 13 | self.rect = self.img.get_rect() 14 | if pipe_type == PIPE_UPPER: 15 | y = y - self.rect.height 16 | self.set_position(x, y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.left = x 20 | self.rect.top = y 21 | 22 | def move_position(self, dx, dy): 23 | self.rect.centerx += dx 24 | self.rect.centery += dy 25 | 26 | def draw(self): 27 | self.gameDisplay.blit(self.img, self.rect) 28 | 29 | def check_status(self): 30 | if self.rect.right < 0: 31 | self.state = PIPE_DONE 32 | 33 | def update(self, dt): 34 | if self.state == PIPE_MOVING: 35 | self.move_position(-(PIPE_SPEED * dt), 0) 36 | self.draw() 37 | self.check_status() 38 | 39 | 40 | class PipeCollection(): 41 | 42 | def __init__(self, gameDisplay): 43 | self.gameDisplay = gameDisplay 44 | self.pipes = [] 45 | 46 | 47 | def add_new_pipe_pair(self, x): 48 | 49 | top_y = random.randint(PIPE_MIN, PIPE_MAX - PIPE_GAP_SIZE) 50 | bottom_y = top_y + PIPE_GAP_SIZE 51 | 52 | p1 = Pipe(self.gameDisplay, x, top_y, PIPE_UPPER) 53 | p2 = Pipe(self.gameDisplay, x, bottom_y, PIPE_LOWER) 54 | 55 | self.pipes.append(p1) 56 | self.pipes.append(p2) 57 | 58 | def create_new_set(self): 59 | self.pipes = [] 60 | placed = PIPE_FIRST 61 | 62 | while placed < DISPLAY_W: 63 | self.add_new_pipe_pair(placed) 64 | placed += PIPE_ADD_GAP 65 | 66 | def update(self, dt): 67 | 68 | rightmost = 0 69 | 70 | for p in self.pipes: 71 | p.update(dt) 72 | if p.pipe_type == PIPE_UPPER: 73 | if p.rect.left > rightmost: 74 | rightmost = p.rect.left 75 | 76 | if rightmost < (DISPLAY_W - PIPE_ADD_GAP): 77 | self.add_new_pipe_pair(DISPLAY_W) 78 | 79 | self.pipes = [p for p in self.pipes if p.state == PIPE_MOVING] 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Ch7/pipe.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | 6 | class Pipe(): 7 | 8 | def __init__(self, gameDisplay, x, y, pipe_type): 9 | self.gameDisplay = gameDisplay 10 | self.state = PIPE_MOVING 11 | self.pipe_type = pipe_type 12 | self.img = pygame.image.load(PIPE_FILENAME) 13 | self.rect = self.img.get_rect() 14 | if pipe_type == PIPE_UPPER: 15 | y = y - self.rect.height 16 | self.set_position(x, y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.left = x 20 | self.rect.top = y 21 | 22 | def move_position(self, dx, dy): 23 | self.rect.centerx += dx 24 | self.rect.centery += dy 25 | 26 | def draw(self): 27 | self.gameDisplay.blit(self.img, self.rect) 28 | 29 | def check_status(self): 30 | if self.rect.right < 0: 31 | self.state = PIPE_DONE 32 | 33 | def update(self, dt): 34 | if self.state == PIPE_MOVING: 35 | self.move_position(-(PIPE_SPEED * dt), 0) 36 | self.draw() 37 | self.check_status() 38 | 39 | 40 | class PipeCollection(): 41 | 42 | def __init__(self, gameDisplay): 43 | self.gameDisplay = gameDisplay 44 | self.pipes = [] 45 | 46 | 47 | def add_new_pipe_pair(self, x): 48 | 49 | top_y = random.randint(PIPE_MIN, PIPE_MAX - PIPE_GAP_SIZE) 50 | bottom_y = top_y + PIPE_GAP_SIZE 51 | 52 | p1 = Pipe(self.gameDisplay, x, top_y, PIPE_UPPER) 53 | p2 = Pipe(self.gameDisplay, x, bottom_y, PIPE_LOWER) 54 | 55 | self.pipes.append(p1) 56 | self.pipes.append(p2) 57 | 58 | def create_new_set(self): 59 | self.pipes = [] 60 | placed = PIPE_FIRST 61 | 62 | while placed < DISPLAY_W: 63 | self.add_new_pipe_pair(placed) 64 | placed += PIPE_ADD_GAP 65 | 66 | def update(self, dt): 67 | 68 | rightmost = 0 69 | 70 | for p in self.pipes: 71 | p.update(dt) 72 | if p.pipe_type == PIPE_UPPER: 73 | if p.rect.left > rightmost: 74 | rightmost = p.rect.left 75 | 76 | if rightmost < (DISPLAY_W - PIPE_ADD_GAP): 77 | self.add_new_pipe_pair(DISPLAY_W) 78 | 79 | self.pipes = [p for p in self.pipes if p.state == PIPE_MOVING] 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Ch10/pipe.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | 6 | class Pipe(): 7 | 8 | def __init__(self, gameDisplay, x, y, pipe_type): 9 | self.gameDisplay = gameDisplay 10 | self.state = PIPE_MOVING 11 | self.pipe_type = pipe_type 12 | self.img = pygame.image.load(PIPE_FILENAME) 13 | self.rect = self.img.get_rect() 14 | if pipe_type == PIPE_UPPER: 15 | y = y - self.rect.height 16 | self.set_position(x, y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.left = x 20 | self.rect.top = y 21 | 22 | def move_position(self, dx, dy): 23 | self.rect.centerx += dx 24 | self.rect.centery += dy 25 | 26 | def draw(self): 27 | self.gameDisplay.blit(self.img, self.rect) 28 | 29 | def check_status(self): 30 | if self.rect.right < 0: 31 | self.state = PIPE_DONE 32 | 33 | def update(self, dt): 34 | if self.state == PIPE_MOVING: 35 | self.move_position(-(PIPE_SPEED * dt), 0) 36 | self.draw() 37 | self.check_status() 38 | 39 | 40 | class PipeCollection(): 41 | 42 | def __init__(self, gameDisplay): 43 | self.gameDisplay = gameDisplay 44 | self.pipes = [] 45 | 46 | 47 | def add_new_pipe_pair(self, x): 48 | 49 | top_y = random.randint(PIPE_MIN, PIPE_MAX - PIPE_GAP_SIZE) 50 | bottom_y = top_y + PIPE_GAP_SIZE 51 | 52 | p1 = Pipe(self.gameDisplay, x, top_y, PIPE_UPPER) 53 | p2 = Pipe(self.gameDisplay, x, bottom_y, PIPE_LOWER) 54 | 55 | self.pipes.append(p1) 56 | self.pipes.append(p2) 57 | 58 | def create_new_set(self): 59 | self.pipes = [] 60 | placed = PIPE_FIRST 61 | 62 | while placed < DISPLAY_W: 63 | self.add_new_pipe_pair(placed) 64 | placed += PIPE_ADD_GAP 65 | 66 | def update(self, dt): 67 | 68 | rightmost = 0 69 | 70 | for p in self.pipes: 71 | p.update(dt) 72 | if p.pipe_type == PIPE_UPPER: 73 | if p.rect.left > rightmost: 74 | rightmost = p.rect.left 75 | 76 | if rightmost < (DISPLAY_W - PIPE_ADD_GAP): 77 | self.add_new_pipe_pair(DISPLAY_W) 78 | 79 | self.pipes = [p for p in self.pipes if p.state == PIPE_MOVING] 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Ch11/pipe.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | 6 | class Pipe(): 7 | 8 | def __init__(self, gameDisplay, x, y, pipe_type): 9 | self.gameDisplay = gameDisplay 10 | self.state = PIPE_MOVING 11 | self.pipe_type = pipe_type 12 | self.img = pygame.image.load(PIPE_FILENAME) 13 | self.rect = self.img.get_rect() 14 | if pipe_type == PIPE_UPPER: 15 | y = y - self.rect.height 16 | self.set_position(x, y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.left = x 20 | self.rect.top = y 21 | 22 | def move_position(self, dx, dy): 23 | self.rect.centerx += dx 24 | self.rect.centery += dy 25 | 26 | def draw(self): 27 | self.gameDisplay.blit(self.img, self.rect) 28 | 29 | def check_status(self): 30 | if self.rect.right < 0: 31 | self.state = PIPE_DONE 32 | 33 | def update(self, dt): 34 | if self.state == PIPE_MOVING: 35 | self.move_position(-(PIPE_SPEED * dt), 0) 36 | self.draw() 37 | self.check_status() 38 | 39 | 40 | class PipeCollection(): 41 | 42 | def __init__(self, gameDisplay): 43 | self.gameDisplay = gameDisplay 44 | self.pipes = [] 45 | 46 | 47 | def add_new_pipe_pair(self, x): 48 | 49 | top_y = random.randint(PIPE_MIN, PIPE_MAX - PIPE_GAP_SIZE) 50 | bottom_y = top_y + PIPE_GAP_SIZE 51 | 52 | p1 = Pipe(self.gameDisplay, x, top_y, PIPE_UPPER) 53 | p2 = Pipe(self.gameDisplay, x, bottom_y, PIPE_LOWER) 54 | 55 | self.pipes.append(p1) 56 | self.pipes.append(p2) 57 | 58 | def create_new_set(self): 59 | self.pipes = [] 60 | placed = PIPE_FIRST 61 | 62 | while placed < DISPLAY_W: 63 | self.add_new_pipe_pair(placed) 64 | placed += PIPE_ADD_GAP 65 | 66 | def update(self, dt): 67 | 68 | rightmost = 0 69 | 70 | for p in self.pipes: 71 | p.update(dt) 72 | if p.pipe_type == PIPE_UPPER: 73 | if p.rect.left > rightmost: 74 | rightmost = p.rect.left 75 | 76 | if rightmost < (DISPLAY_W - PIPE_ADD_GAP): 77 | self.add_new_pipe_pair(DISPLAY_W) 78 | 79 | self.pipes = [p for p in self.pipes if p.state == PIPE_MOVING] 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Ch13/pipe.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | 6 | class Pipe(): 7 | 8 | def __init__(self, gameDisplay, x, y, pipe_type): 9 | self.gameDisplay = gameDisplay 10 | self.state = PIPE_MOVING 11 | self.pipe_type = pipe_type 12 | self.img = pygame.image.load(PIPE_FILENAME) 13 | self.rect = self.img.get_rect() 14 | if pipe_type == PIPE_UPPER: 15 | y = y - self.rect.height 16 | self.set_position(x, y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.left = x 20 | self.rect.top = y 21 | 22 | def move_position(self, dx, dy): 23 | self.rect.centerx += dx 24 | self.rect.centery += dy 25 | 26 | def draw(self): 27 | self.gameDisplay.blit(self.img, self.rect) 28 | 29 | def check_status(self): 30 | if self.rect.right < 0: 31 | self.state = PIPE_DONE 32 | 33 | def update(self, dt): 34 | if self.state == PIPE_MOVING: 35 | self.move_position(-(PIPE_SPEED * dt), 0) 36 | self.draw() 37 | self.check_status() 38 | 39 | 40 | class PipeCollection(): 41 | 42 | def __init__(self, gameDisplay): 43 | self.gameDisplay = gameDisplay 44 | self.pipes = [] 45 | 46 | 47 | def add_new_pipe_pair(self, x): 48 | 49 | top_y = random.randint(PIPE_MIN, PIPE_MAX - PIPE_GAP_SIZE) 50 | bottom_y = top_y + PIPE_GAP_SIZE 51 | 52 | p1 = Pipe(self.gameDisplay, x, top_y, PIPE_UPPER) 53 | p2 = Pipe(self.gameDisplay, x, bottom_y, PIPE_LOWER) 54 | 55 | self.pipes.append(p1) 56 | self.pipes.append(p2) 57 | 58 | def create_new_set(self): 59 | self.pipes = [] 60 | placed = PIPE_FIRST 61 | 62 | while placed < DISPLAY_W: 63 | self.add_new_pipe_pair(placed) 64 | placed += PIPE_ADD_GAP 65 | 66 | def update(self, dt): 67 | 68 | rightmost = 0 69 | 70 | for p in self.pipes: 71 | p.update(dt) 72 | if p.pipe_type == PIPE_UPPER: 73 | if p.rect.left > rightmost: 74 | rightmost = p.rect.left 75 | 76 | if rightmost < (DISPLAY_W - PIPE_ADD_GAP): 77 | self.add_new_pipe_pair(DISPLAY_W) 78 | 79 | self.pipes = [p for p in self.pipes if p.state == PIPE_MOVING] 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Ch14/pipe.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | 6 | class Pipe(): 7 | 8 | def __init__(self, gameDisplay, x, y, pipe_type): 9 | self.gameDisplay = gameDisplay 10 | self.state = PIPE_MOVING 11 | self.pipe_type = pipe_type 12 | self.img = pygame.image.load(PIPE_FILENAME) 13 | self.rect = self.img.get_rect() 14 | if pipe_type == PIPE_UPPER: 15 | y = y - self.rect.height 16 | self.set_position(x, y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.left = x 20 | self.rect.top = y 21 | 22 | def move_position(self, dx, dy): 23 | self.rect.centerx += dx 24 | self.rect.centery += dy 25 | 26 | def draw(self): 27 | self.gameDisplay.blit(self.img, self.rect) 28 | 29 | def check_status(self): 30 | if self.rect.right < 0: 31 | self.state = PIPE_DONE 32 | 33 | def update(self, dt): 34 | if self.state == PIPE_MOVING: 35 | self.move_position(-(PIPE_SPEED * dt), 0) 36 | self.draw() 37 | self.check_status() 38 | 39 | 40 | class PipeCollection(): 41 | 42 | def __init__(self, gameDisplay): 43 | self.gameDisplay = gameDisplay 44 | self.pipes = [] 45 | 46 | 47 | def add_new_pipe_pair(self, x): 48 | 49 | top_y = random.randint(PIPE_MIN, PIPE_MAX - PIPE_GAP_SIZE) 50 | bottom_y = top_y + PIPE_GAP_SIZE 51 | 52 | p1 = Pipe(self.gameDisplay, x, top_y, PIPE_UPPER) 53 | p2 = Pipe(self.gameDisplay, x, bottom_y, PIPE_LOWER) 54 | 55 | self.pipes.append(p1) 56 | self.pipes.append(p2) 57 | 58 | def create_new_set(self): 59 | self.pipes = [] 60 | placed = PIPE_FIRST 61 | 62 | while placed < DISPLAY_W: 63 | self.add_new_pipe_pair(placed) 64 | placed += PIPE_ADD_GAP 65 | 66 | def update(self, dt): 67 | 68 | rightmost = 0 69 | 70 | for p in self.pipes: 71 | p.update(dt) 72 | if p.pipe_type == PIPE_UPPER: 73 | if p.rect.left > rightmost: 74 | rightmost = p.rect.left 75 | 76 | if rightmost < (DISPLAY_W - PIPE_ADD_GAP): 77 | self.add_new_pipe_pair(DISPLAY_W) 78 | 79 | self.pipes = [p for p in self.pipes if p.state == PIPE_MOVING] 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Ch15/pipe.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | 5 | 6 | class Pipe(): 7 | 8 | def __init__(self, gameDisplay, x, y, pipe_type): 9 | self.gameDisplay = gameDisplay 10 | self.state = PIPE_MOVING 11 | self.pipe_type = pipe_type 12 | self.img = pygame.image.load(PIPE_FILENAME) 13 | self.rect = self.img.get_rect() 14 | if pipe_type == PIPE_UPPER: 15 | y = y - self.rect.height 16 | self.set_position(x, y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.left = x 20 | self.rect.top = y 21 | 22 | def move_position(self, dx, dy): 23 | self.rect.centerx += dx 24 | self.rect.centery += dy 25 | 26 | def draw(self): 27 | self.gameDisplay.blit(self.img, self.rect) 28 | 29 | def check_status(self): 30 | if self.rect.right < 0: 31 | self.state = PIPE_DONE 32 | 33 | def update(self, dt): 34 | if self.state == PIPE_MOVING: 35 | self.move_position(-(PIPE_SPEED * dt), 0) 36 | self.draw() 37 | self.check_status() 38 | 39 | 40 | class PipeCollection(): 41 | 42 | def __init__(self, gameDisplay): 43 | self.gameDisplay = gameDisplay 44 | self.pipes = [] 45 | 46 | 47 | def add_new_pipe_pair(self, x): 48 | 49 | top_y = random.randint(PIPE_MIN, PIPE_MAX - PIPE_GAP_SIZE) 50 | bottom_y = top_y + PIPE_GAP_SIZE 51 | 52 | p1 = Pipe(self.gameDisplay, x, top_y, PIPE_UPPER) 53 | p2 = Pipe(self.gameDisplay, x, bottom_y, PIPE_LOWER) 54 | 55 | self.pipes.append(p1) 56 | self.pipes.append(p2) 57 | 58 | def create_new_set(self): 59 | self.pipes = [] 60 | placed = PIPE_FIRST 61 | 62 | while placed < DISPLAY_W: 63 | self.add_new_pipe_pair(placed) 64 | placed += PIPE_ADD_GAP 65 | 66 | def update(self, dt): 67 | 68 | rightmost = 0 69 | 70 | for p in self.pipes: 71 | p.update(dt) 72 | if p.pipe_type == PIPE_UPPER: 73 | if p.rect.left > rightmost: 74 | rightmost = p.rect.left 75 | 76 | if rightmost < (DISPLAY_W - PIPE_ADD_GAP): 77 | self.add_new_pipe_pair(DISPLAY_W) 78 | 79 | self.pipes = [p for p in self.pipes if p.state == PIPE_MOVING] 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Ch11/bird.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | from nnet import Nnet 5 | 6 | class Bird(): 7 | 8 | def __init__(self, gameDisplay): 9 | self.gameDisplay = gameDisplay 10 | self.state = BIRD_ALIVE 11 | self.img = pygame.image.load(BIRD_FILENAME) 12 | self.rect = self.img.get_rect() 13 | self.speed = 0 14 | self.time_lived = 0 15 | self.nnet = Nnet(NNET_INPUTS, NNET_HIDDEN, NNET_OUTPUTS) 16 | self.set_position(BIRD_START_X, BIRD_START_Y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.centerx = x 20 | self.rect.centery = y 21 | 22 | def move(self, dt): 23 | 24 | distance = 0 25 | new_speed = 0 26 | 27 | distance = (self.speed * dt) + (0.5 * GRAVITY * dt * dt) 28 | new_speed = self.speed + (GRAVITY * dt) 29 | 30 | self.rect.centery += distance 31 | self.speed = new_speed 32 | 33 | if self.rect.top < 0: 34 | self.rect.top = 0 35 | self.speed = 0 36 | 37 | def jump(self, pipes): 38 | inputs = self.get_inputs(pipes) 39 | val = self.nnet.get_max_value(inputs) 40 | if val > JUMP_CHANCE: 41 | self.speed = BIRD_START_SPEED 42 | 43 | def draw(self): 44 | self.gameDisplay.blit(self.img, self.rect) 45 | 46 | def check_status(self, pipes): 47 | if self.rect.bottom > DISPLAY_H: 48 | self.state = BIRD_DEAD 49 | else: 50 | self.check_hits(pipes) 51 | 52 | def check_hits(self, pipes): 53 | for p in pipes: 54 | if p.rect.colliderect(self.rect): 55 | self.state = BIRD_DEAD 56 | break 57 | 58 | def update(self, dt, pipes): 59 | if self.state == BIRD_ALIVE: 60 | self.time_lived += dt 61 | self.move(dt) 62 | self.jump(pipes) 63 | self.draw() 64 | self.check_status(pipes) 65 | 66 | 67 | def get_inputs(self, pipes): 68 | 69 | closest = DISPLAY_W * 2 70 | bottom_y = 0 71 | for p in pipes: 72 | if p.pipe_type == PIPE_UPPER and p.rect.right < closest and p.rect.right > self.rect.left: 73 | closest = p.rect.right 74 | bottom_y = p.rect.bottom 75 | 76 | 77 | horizontal_distance = closest - self.rect.centerx 78 | vertical_distance = (self.rect.centery) - (bottom_y + PIPE_GAP_SIZE / 2) 79 | 80 | inputs = [ 81 | ((horizontal_distance / DISPLAY_W) * 0.99) + 0.01, 82 | ((( vertical_distance + Y_SHIFT) / NORMALIZER ) * 0.99 ) + 0.01 83 | ] 84 | 85 | return inputs 86 | 87 | 88 | 89 | class BirdCollection(): 90 | 91 | def __init__(self, gameDisplay): 92 | self.gameDisplay = gameDisplay 93 | self.birds = [] 94 | self.create_new_generation() 95 | 96 | def create_new_generation(self): 97 | self.birds = [] 98 | for i in range(0, GENERATION_SIZE): 99 | self.birds.append(Bird(self.gameDisplay)) 100 | 101 | def update(self, dt, pipes): 102 | num_alive = 0 103 | for b in self.birds: 104 | b.update(dt, pipes) 105 | if b.state == BIRD_ALIVE: 106 | num_alive += 1 107 | 108 | return num_alive 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /Ch13/bird.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | from nnet import Nnet 5 | 6 | class Bird(): 7 | 8 | def __init__(self, gameDisplay): 9 | self.gameDisplay = gameDisplay 10 | self.state = BIRD_ALIVE 11 | self.img = pygame.image.load(BIRD_FILENAME) 12 | self.rect = self.img.get_rect() 13 | self.speed = 0 14 | self.time_lived = 0 15 | self.nnet = Nnet(NNET_INPUTS, NNET_HIDDEN, NNET_OUTPUTS) 16 | self.set_position(BIRD_START_X, BIRD_START_Y) 17 | 18 | def set_position(self, x, y): 19 | self.rect.centerx = x 20 | self.rect.centery = y 21 | 22 | def move(self, dt): 23 | 24 | distance = 0 25 | new_speed = 0 26 | 27 | distance = (self.speed * dt) + (0.5 * GRAVITY * dt * dt) 28 | new_speed = self.speed + (GRAVITY * dt) 29 | 30 | self.rect.centery += distance 31 | self.speed = new_speed 32 | 33 | if self.rect.top < 0: 34 | self.rect.top = 0 35 | self.speed = 0 36 | 37 | def jump(self, pipes): 38 | inputs = self.get_inputs(pipes) 39 | val = self.nnet.get_max_value(inputs) 40 | if val > JUMP_CHANCE: 41 | self.speed = BIRD_START_SPEED 42 | 43 | def draw(self): 44 | self.gameDisplay.blit(self.img, self.rect) 45 | 46 | def check_status(self, pipes): 47 | if self.rect.bottom > DISPLAY_H: 48 | self.state = BIRD_DEAD 49 | else: 50 | self.check_hits(pipes) 51 | 52 | def check_hits(self, pipes): 53 | for p in pipes: 54 | if p.rect.colliderect(self.rect): 55 | self.state = BIRD_DEAD 56 | break 57 | 58 | def update(self, dt, pipes): 59 | if self.state == BIRD_ALIVE: 60 | self.time_lived += dt 61 | self.move(dt) 62 | self.jump(pipes) 63 | self.draw() 64 | self.check_status(pipes) 65 | 66 | 67 | def get_inputs(self, pipes): 68 | 69 | closest = DISPLAY_W * 2 70 | bottom_y = 0 71 | for p in pipes: 72 | if p.pipe_type == PIPE_UPPER and p.rect.right < closest and p.rect.right > self.rect.left: 73 | closest = p.rect.right 74 | bottom_y = p.rect.bottom 75 | 76 | 77 | horizontal_distance = closest - self.rect.centerx 78 | vertical_distance = (self.rect.centery) - (bottom_y + PIPE_GAP_SIZE / 2) 79 | 80 | inputs = [ 81 | ((horizontal_distance / DISPLAY_W) * 0.99) + 0.01, 82 | ((( vertical_distance + Y_SHIFT) / NORMALIZER ) * 0.99 ) + 0.01 83 | ] 84 | 85 | return inputs 86 | 87 | 88 | 89 | class BirdCollection(): 90 | 91 | def __init__(self, gameDisplay): 92 | self.gameDisplay = gameDisplay 93 | self.birds = [] 94 | self.create_new_generation() 95 | 96 | def create_new_generation(self): 97 | self.birds = [] 98 | for i in range(0, GENERATION_SIZE): 99 | self.birds.append(Bird(self.gameDisplay)) 100 | 101 | def update(self, dt, pipes): 102 | num_alive = 0 103 | for b in self.birds: 104 | b.update(dt, pipes) 105 | if b.state == BIRD_ALIVE: 106 | num_alive += 1 107 | 108 | return num_alive 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /Ch14/nnet.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.special 3 | import random 4 | from defs import * 5 | 6 | class Nnet: 7 | 8 | def __init__(self, num_input, num_hidden, num_output): 9 | self.num_input = num_input 10 | self.num_hidden = num_hidden 11 | self.num_output = num_output 12 | self.weight_input_hidden = np.random.uniform(-0.5, 0.5, size=(self.num_hidden, self.num_input)) 13 | self.weight_hidden_output = np.random.uniform(-0.5, 0.5, size=(self.num_output, self.num_hidden)) 14 | self.activation_function = lambda x: scipy.special.expit(x) 15 | 16 | def get_outputs(self, inputs_list): 17 | inputs = np.array(inputs_list, ndmin=2).T 18 | hidden_inputs = np.dot(self.weight_input_hidden, inputs) 19 | hidden_outputs = self.activation_function(hidden_inputs) 20 | final_inputs = np.dot(self.weight_hidden_output, hidden_outputs) 21 | final_outputs = self.activation_function(final_inputs) 22 | return final_outputs 23 | 24 | def get_max_value(self, inputs_list): 25 | outputs = self.get_outputs(inputs_list) 26 | return np.max(outputs) 27 | 28 | def modify_weights(self): 29 | Nnet.modify_array(self.weight_input_hidden) 30 | Nnet.modify_array(self.weight_hidden_output) 31 | 32 | def create_mixed_weights(self, net1, net2): 33 | self.weight_input_hidden = Nnet.get_mix_from_arrays(net1.weight_input_hidden, net2.weight_input_hidden) 34 | self.weight_hidden_output = Nnet.get_mix_from_arrays(net1.weight_hidden_output, net2.weight_hidden_output) 35 | 36 | def modify_array(a): 37 | for x in np.nditer(a, op_flags=['readwrite']): 38 | if random.random() < MUTATION_WEIGHT_MODIFY_CHANCE: 39 | x[...] = np.random.random_sample() - 0.5 40 | 41 | def get_mix_from_arrays(ar1, ar2): 42 | 43 | total_entries = ar1.size 44 | num_rows = ar1.shape[0] 45 | num_cols = ar1.shape[1] 46 | 47 | num_to_take = total_entries - int(total_entries * MUTATION_ARRAY_MIX_PERC) 48 | idx = np.random.choice(np.arange(total_entries), num_to_take, replace=False) 49 | 50 | res = np.random.rand(num_rows, num_cols) 51 | 52 | for row in range(0, num_rows): 53 | for col in range(0, num_cols): 54 | index = row * num_cols + col 55 | if index in idx: 56 | res[row][col] = ar1[row][col] 57 | else: 58 | res[row][col] = ar2[row][col] 59 | 60 | return res 61 | 62 | 63 | 64 | def tests(): 65 | ar1 = np.random.uniform(-0.5, 0.5, size=(3, 4)) 66 | ar2 = np.random.uniform(-0.5, 0.5, size=(3, 4)) 67 | print('ar1.size', ar1.size, sep='\n') 68 | print('ar1', ar1, sep='\n') 69 | 70 | Nnet.modify_array(ar1) 71 | print('ar1', ar1, sep='\n') 72 | 73 | print('') 74 | 75 | print('ar1', ar1, sep='\n') 76 | print('ar2', ar2, sep='\n') 77 | 78 | mixed = Nnet.get_mix_from_arrays(ar1, ar2) 79 | print('mixed', mixed, sep='\n') 80 | 81 | 82 | 83 | if __name__ == "__main__": 84 | tests() 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /Ch15/nnet.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.special 3 | import random 4 | from defs import * 5 | 6 | class Nnet: 7 | 8 | def __init__(self, num_input, num_hidden, num_output): 9 | self.num_input = num_input 10 | self.num_hidden = num_hidden 11 | self.num_output = num_output 12 | self.weight_input_hidden = np.random.uniform(-0.5, 0.5, size=(self.num_hidden, self.num_input)) 13 | self.weight_hidden_output = np.random.uniform(-0.5, 0.5, size=(self.num_output, self.num_hidden)) 14 | self.activation_function = lambda x: scipy.special.expit(x) 15 | 16 | def get_outputs(self, inputs_list): 17 | inputs = np.array(inputs_list, ndmin=2).T 18 | hidden_inputs = np.dot(self.weight_input_hidden, inputs) 19 | hidden_outputs = self.activation_function(hidden_inputs) 20 | final_inputs = np.dot(self.weight_hidden_output, hidden_outputs) 21 | final_outputs = self.activation_function(final_inputs) 22 | return final_outputs 23 | 24 | def get_max_value(self, inputs_list): 25 | outputs = self.get_outputs(inputs_list) 26 | return np.max(outputs) 27 | 28 | def modify_weights(self): 29 | Nnet.modify_array(self.weight_input_hidden) 30 | Nnet.modify_array(self.weight_hidden_output) 31 | 32 | def create_mixed_weights(self, net1, net2): 33 | self.weight_input_hidden = Nnet.get_mix_from_arrays(net1.weight_input_hidden, net2.weight_input_hidden) 34 | self.weight_hidden_output = Nnet.get_mix_from_arrays(net1.weight_hidden_output, net2.weight_hidden_output) 35 | 36 | def modify_array(a): 37 | for x in np.nditer(a, op_flags=['readwrite']): 38 | if random.random() < MUTATION_WEIGHT_MODIFY_CHANCE: 39 | x[...] = np.random.random_sample() - 0.5 40 | 41 | def get_mix_from_arrays(ar1, ar2): 42 | 43 | total_entries = ar1.size 44 | num_rows = ar1.shape[0] 45 | num_cols = ar1.shape[1] 46 | 47 | num_to_take = total_entries - int(total_entries * MUTATION_ARRAY_MIX_PERC) 48 | idx = np.random.choice(np.arange(total_entries), num_to_take, replace=False) 49 | 50 | res = np.random.rand(num_rows, num_cols) 51 | 52 | for row in range(0, num_rows): 53 | for col in range(0, num_cols): 54 | index = row * num_cols + col 55 | if index in idx: 56 | res[row][col] = ar1[row][col] 57 | else: 58 | res[row][col] = ar2[row][col] 59 | 60 | return res 61 | 62 | 63 | 64 | def tests(): 65 | ar1 = np.random.uniform(-0.5, 0.5, size=(3, 4)) 66 | ar2 = np.random.uniform(-0.5, 0.5, size=(3, 4)) 67 | print('ar1.size', ar1.size, sep='\n') 68 | print('ar1', ar1, sep='\n') 69 | 70 | Nnet.modify_array(ar1) 71 | print('ar1', ar1, sep='\n') 72 | 73 | print('') 74 | 75 | print('ar1', ar1, sep='\n') 76 | print('ar2', ar2, sep='\n') 77 | 78 | mixed = Nnet.get_mix_from_arrays(ar1, ar2) 79 | print('mixed', mixed, sep='\n') 80 | 81 | 82 | 83 | if __name__ == "__main__": 84 | tests() 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /Ch13/nnet.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.special 3 | import random 4 | from defs import * 5 | 6 | class Nnet: 7 | 8 | def __init__(self, num_input, num_hidden, num_output): 9 | self.num_input = num_input 10 | self.num_hidden = num_hidden 11 | self.num_output = num_output 12 | self.weight_input_hidden = np.random.uniform(-0.5, 0.5, size=(self.num_hidden, self.num_input)) 13 | self.weight_hidden_output = np.random.uniform(-0.5, 0.5, size=(self.num_output, self.num_hidden)) 14 | self.activation_function = lambda x: scipy.special.expit(x) 15 | 16 | def get_outputs(self, inputs_list): 17 | inputs = np.array(inputs_list, ndmin=2).T 18 | hidden_inputs = np.dot(self.weight_input_hidden, inputs) 19 | hidden_outputs = self.activation_function(hidden_inputs) 20 | final_inputs = np.dot(self.weight_hidden_output, hidden_outputs) 21 | final_outputs = self.activation_function(final_inputs) 22 | return final_outputs 23 | 24 | def get_max_value(self, inputs_list): 25 | outputs = self.get_outputs(inputs_list) 26 | return np.max(outputs) 27 | 28 | def modify_weights(self): 29 | Nnet.modify_array(self.weight_input_hidden) 30 | Nnet.modify_array(self.weight_hidden_output) 31 | 32 | def create_mixed_weights(self, net1, net2): 33 | self.weight_input_hidden = Nnet.get_mix_from_arrays(net1.weight_input_hidden, net2.weight_input_hidden) 34 | self.weight_hidden_output = Nnet.get_mix_from_arrays(net1.weight_hidden_output, net2.weight_hidden_output) 35 | 36 | def modify_array(a): 37 | for x in np.nditer(a, op_flags=['readwrite']): 38 | if random.random() < MUTATION_WEIGHT_MODIFY_CHANCE: 39 | x[...] = np.random.random_sample() - 0.5 40 | 41 | def get_mix_from_arrays(ar1, ar2): 42 | 43 | total_entries = ar1.size 44 | num_rows = ar1.shape[0] 45 | num_cols = ar1.shape[1] 46 | 47 | num_to_take = total_entries - int(total_entries * MUTATION_ARRAY_MIX_PERC) 48 | idx = np.random.choice(np.arange(total_entries), num_to_take, replace=False) 49 | 50 | print('idx', idx) 51 | 52 | res = np.random.rand(num_rows, num_cols) 53 | 54 | for row in range(0, num_rows): 55 | for col in range(0, num_cols): 56 | index = row * num_cols + col 57 | if index in idx: 58 | res[row][col] = ar1[row][col] 59 | else: 60 | res[row][col] = ar2[row][col] 61 | 62 | return res 63 | 64 | 65 | 66 | def tests(): 67 | ar1 = np.random.uniform(-0.5, 0.5, size=(3, 4)) 68 | ar2 = np.random.uniform(-0.5, 0.5, size=(3, 4)) 69 | print('ar1.size', ar1.size, sep='\n') 70 | print('ar1', ar1, sep='\n') 71 | 72 | Nnet.modify_array(ar1) 73 | print('ar1', ar1, sep='\n') 74 | 75 | print('') 76 | 77 | print('ar1', ar1, sep='\n') 78 | print('ar2', ar2, sep='\n') 79 | 80 | mixed = Nnet.get_mix_from_arrays(ar1, ar2) 81 | print('mixed', mixed, sep='\n') 82 | 83 | 84 | 85 | if __name__ == "__main__": 86 | tests() 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /Ch14/bird.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | from nnet import Nnet 5 | 6 | class Bird(): 7 | 8 | def __init__(self, gameDisplay): 9 | self.gameDisplay = gameDisplay 10 | self.state = BIRD_ALIVE 11 | self.img = pygame.image.load(BIRD_FILENAME) 12 | self.rect = self.img.get_rect() 13 | self.speed = 0 14 | self.fitness = 0 15 | self.time_lived = 0 16 | self.nnet = Nnet(NNET_INPUTS, NNET_HIDDEN, NNET_OUTPUTS) 17 | self.set_position(BIRD_START_X, BIRD_START_Y) 18 | 19 | def reset(self): 20 | self.state = BIRD_ALIVE 21 | self.speed = 0 22 | self.fitness = 0 23 | self.time_lived = 0 24 | self.set_position(BIRD_START_X, BIRD_START_Y) 25 | 26 | def set_position(self, x, y): 27 | self.rect.centerx = x 28 | self.rect.centery = y 29 | 30 | def move(self, dt): 31 | 32 | distance = 0 33 | new_speed = 0 34 | 35 | distance = (self.speed * dt) + (0.5 * GRAVITY * dt * dt) 36 | new_speed = self.speed + (GRAVITY * dt) 37 | 38 | self.rect.centery += distance 39 | self.speed = new_speed 40 | 41 | if self.rect.top < 0: 42 | self.rect.top = 0 43 | self.speed = 0 44 | 45 | def jump(self, pipes): 46 | inputs = self.get_inputs(pipes) 47 | val = self.nnet.get_max_value(inputs) 48 | if val > JUMP_CHANCE: 49 | self.speed = BIRD_START_SPEED 50 | 51 | def draw(self): 52 | self.gameDisplay.blit(self.img, self.rect) 53 | 54 | def check_status(self, pipes): 55 | if self.rect.bottom > DISPLAY_H: 56 | self.state = BIRD_DEAD 57 | else: 58 | self.check_hits(pipes) 59 | 60 | def assign_collision_fitness(self, p): 61 | gap_y = 0 62 | if p.pipe_type == PIPE_UPPER: 63 | gap_y = p.rect.bottom + PIPE_GAP_SIZE / 2 64 | else: 65 | gap_y = p.rect.top - PIPE_GAP_SIZE / 2 66 | 67 | self.fitness = -(abs(self.rect.centery - gap_y)) 68 | 69 | def check_hits(self, pipes): 70 | for p in pipes: 71 | if p.rect.colliderect(self.rect): 72 | self.state = BIRD_DEAD 73 | self.assign_collision_fitness(p) 74 | break 75 | 76 | def update(self, dt, pipes): 77 | if self.state == BIRD_ALIVE: 78 | self.time_lived += dt 79 | self.move(dt) 80 | self.jump(pipes) 81 | self.draw() 82 | self.check_status(pipes) 83 | 84 | 85 | def get_inputs(self, pipes): 86 | 87 | closest = DISPLAY_W * 2 88 | bottom_y = 0 89 | for p in pipes: 90 | if p.pipe_type == PIPE_UPPER and p.rect.right < closest and p.rect.right > self.rect.left: 91 | closest = p.rect.right 92 | bottom_y = p.rect.bottom 93 | 94 | 95 | horizontal_distance = closest - self.rect.centerx 96 | vertical_distance = (self.rect.centery) - (bottom_y + PIPE_GAP_SIZE / 2) 97 | 98 | inputs = [ 99 | ((horizontal_distance / DISPLAY_W) * 0.99) + 0.01, 100 | ((( vertical_distance + Y_SHIFT) / NORMALIZER ) * 0.99 ) + 0.01 101 | ] 102 | 103 | return inputs 104 | 105 | 106 | 107 | class BirdCollection(): 108 | 109 | def __init__(self, gameDisplay): 110 | self.gameDisplay = gameDisplay 111 | self.birds = [] 112 | self.create_new_generation() 113 | 114 | def create_new_generation(self): 115 | self.birds = [] 116 | for i in range(0, GENERATION_SIZE): 117 | self.birds.append(Bird(self.gameDisplay)) 118 | 119 | def update(self, dt, pipes): 120 | num_alive = 0 121 | for b in self.birds: 122 | b.update(dt, pipes) 123 | if b.state == BIRD_ALIVE: 124 | num_alive += 1 125 | 126 | return num_alive 127 | 128 | def evolve_population(self): 129 | 130 | for b in self.birds: 131 | b.fitness += b.time_lived * PIPE_SPEED 132 | 133 | self.birds.sort(key=lambda x: x.fitness, reverse=True) 134 | 135 | for b in self.birds[0:10]: 136 | print('fitness:', b.fitness) 137 | 138 | self.create_new_generation() 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /Ch15/bird.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import random 3 | from defs import * 4 | from nnet import Nnet 5 | import numpy as np 6 | 7 | class Bird(): 8 | 9 | def __init__(self, gameDisplay): 10 | self.gameDisplay = gameDisplay 11 | self.state = BIRD_ALIVE 12 | self.img = pygame.image.load(BIRD_FILENAME) 13 | self.rect = self.img.get_rect() 14 | self.speed = 0 15 | self.fitness = 0 16 | self.time_lived = 0 17 | self.nnet = Nnet(NNET_INPUTS, NNET_HIDDEN, NNET_OUTPUTS) 18 | self.set_position(BIRD_START_X, BIRD_START_Y) 19 | 20 | def reset(self): 21 | self.state = BIRD_ALIVE 22 | self.speed = 0 23 | self.fitness = 0 24 | self.time_lived = 0 25 | self.set_position(BIRD_START_X, BIRD_START_Y) 26 | 27 | def set_position(self, x, y): 28 | self.rect.centerx = x 29 | self.rect.centery = y 30 | 31 | def move(self, dt): 32 | 33 | distance = 0 34 | new_speed = 0 35 | 36 | distance = (self.speed * dt) + (0.5 * GRAVITY * dt * dt) 37 | new_speed = self.speed + (GRAVITY * dt) 38 | 39 | self.rect.centery += distance 40 | self.speed = new_speed 41 | 42 | if self.rect.top < 0: 43 | self.rect.top = 0 44 | self.speed = 0 45 | 46 | def jump(self, pipes): 47 | inputs = self.get_inputs(pipes) 48 | val = self.nnet.get_max_value(inputs) 49 | if val > JUMP_CHANCE: 50 | self.speed = BIRD_START_SPEED 51 | 52 | def draw(self): 53 | self.gameDisplay.blit(self.img, self.rect) 54 | 55 | def check_status(self, pipes): 56 | if self.rect.bottom > DISPLAY_H: 57 | self.state = BIRD_DEAD 58 | else: 59 | self.check_hits(pipes) 60 | 61 | def assign_collision_fitness(self, p): 62 | gap_y = 0 63 | if p.pipe_type == PIPE_UPPER: 64 | gap_y = p.rect.bottom + PIPE_GAP_SIZE / 2 65 | else: 66 | gap_y = p.rect.top - PIPE_GAP_SIZE / 2 67 | 68 | self.fitness = -(abs(self.rect.centery - gap_y)) 69 | 70 | def check_hits(self, pipes): 71 | for p in pipes: 72 | if p.rect.colliderect(self.rect): 73 | self.state = BIRD_DEAD 74 | self.assign_collision_fitness(p) 75 | break 76 | 77 | def update(self, dt, pipes): 78 | if self.state == BIRD_ALIVE: 79 | self.time_lived += dt 80 | self.move(dt) 81 | self.jump(pipes) 82 | self.draw() 83 | self.check_status(pipes) 84 | 85 | 86 | def get_inputs(self, pipes): 87 | 88 | closest = DISPLAY_W * 2 89 | bottom_y = 0 90 | for p in pipes: 91 | if p.pipe_type == PIPE_UPPER and p.rect.right < closest and p.rect.right > self.rect.left: 92 | closest = p.rect.right 93 | bottom_y = p.rect.bottom 94 | 95 | 96 | horizontal_distance = closest - self.rect.centerx 97 | vertical_distance = (self.rect.centery) - (bottom_y + PIPE_GAP_SIZE / 2) 98 | 99 | inputs = [ 100 | ((horizontal_distance / DISPLAY_W) * 0.99) + 0.01, 101 | ((( vertical_distance + Y_SHIFT) / NORMALIZER ) * 0.99 ) + 0.01 102 | ] 103 | 104 | return inputs 105 | 106 | def create_offspring(p1, p2, gameDisplay): 107 | new_bird = Bird(gameDisplay) 108 | new_bird.nnet.create_mixed_weights(p1.nnet, p2.nnet) 109 | return new_bird 110 | 111 | 112 | 113 | class BirdCollection(): 114 | 115 | def __init__(self, gameDisplay): 116 | self.gameDisplay = gameDisplay 117 | self.birds = [] 118 | self.create_new_generation() 119 | 120 | def create_new_generation(self): 121 | self.birds = [] 122 | for i in range(0, GENERATION_SIZE): 123 | self.birds.append(Bird(self.gameDisplay)) 124 | 125 | def update(self, dt, pipes): 126 | num_alive = 0 127 | for b in self.birds: 128 | b.update(dt, pipes) 129 | if b.state == BIRD_ALIVE: 130 | num_alive += 1 131 | 132 | return num_alive 133 | 134 | def evolve_population(self): 135 | 136 | for b in self.birds: 137 | b.fitness += b.time_lived * PIPE_SPEED 138 | 139 | self.birds.sort(key=lambda x: x.fitness, reverse=True) 140 | 141 | cut_off = int(len(self.birds) * MUTATION_CUT_OFF) 142 | good_birds = self.birds[0:cut_off] 143 | bad_birds = self.birds[cut_off:] 144 | num_bad_to_take = int(len(self.birds) * MUTATION_BAD_TO_KEEP) 145 | 146 | for b in bad_birds: 147 | b.nnet.modify_weights() 148 | 149 | new_birds = [] 150 | 151 | idx_bad_to_take = np.random.choice(np.arange(len(bad_birds)), num_bad_to_take, replace=False) 152 | 153 | for index in idx_bad_to_take: 154 | new_birds.append(bad_birds[index]) 155 | 156 | new_birds.extend(good_birds) 157 | 158 | children_needed = len(self.birds) - len(new_birds) 159 | 160 | while len(new_birds) < len(self.birds): 161 | idx_to_breed = np.random.choice(np.arange(len(good_birds)), 2, replace=False) 162 | if idx_to_breed[0] != idx_to_breed[1]: 163 | new_bird = Bird.create_offspring(good_birds[idx_to_breed[0]], good_birds[idx_to_breed[1]], self.gameDisplay) 164 | if random.random() < MUTATION_MODIFY_CHANCE_LIMIT: 165 | new_bird.nnet.modify_weights() 166 | new_birds.append(new_bird) 167 | 168 | for b in new_birds: 169 | b.reset(); 170 | 171 | self.birds = new_birds 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | --------------------------------------------------------------------------------