Skip to content

Commit ee1b611

Browse files
Merge pull request #2522 from Shikhar9425/patch-6
Flappy_bird.py
2 parents d5b3eeb + 60e2dec commit ee1b611

File tree

2 files changed

+316
-0
lines changed

2 files changed

+316
-0
lines changed
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
#AI-driven AI Flappy Bird
2+
import pygame
3+
import neat
4+
import os
5+
import random
6+
7+
# Game window size
8+
WINDOW_WIDTH = 500
9+
WINDOW_HEIGHT = 800
10+
11+
# Bird images
12+
BIRD_IMAGES = [
13+
pygame.transform.scale2x(pygame.image.load(os.path.join("images", "bird1.png"))),
14+
pygame.transform.scale2x(pygame.image.load(os.path.join("images", "bird2.png"))),
15+
pygame.transform.scale2x(pygame.image.load(os.path.join("images", "bird3.png")))
16+
]
17+
18+
# Pipe image
19+
PIPE_IMAGE = pygame.transform.scale2x(pygame.image.load(os.path.join("images", "pipe.png")))
20+
21+
# Base image
22+
BASE_IMAGE = pygame.transform.scale2x(pygame.image.load(os.path.join("images", "base.png")))
23+
24+
# Background image
25+
BG_IMAGE = pygame.transform.scale2x(pygame.image.load(os.path.join("images", "bg.png")))
26+
27+
28+
class Bird:
29+
IMAGES = BIRD_IMAGES
30+
MAX_ROTATION = 25
31+
ROTATION_VELOCITY = 20
32+
ANIMATION_TIME = 5
33+
34+
def __init__(self, x, y):
35+
self.x = x
36+
self.y = y
37+
self.tilt = 0
38+
self.tick_count = 0
39+
self.velocity = 0
40+
self.height = self.y
41+
self.image_count = 0
42+
self.image = self.IMAGES[0]
43+
44+
def jump(self):
45+
self.velocity = -10.5
46+
self.tick_count = 0
47+
self.height = self.y
48+
49+
def move(self):
50+
self.tick_count += 1
51+
displacement = self.velocity * self.tick_count + 1.5 * self.tick_count ** 2
52+
53+
if displacement >= 16:
54+
displacement = 16
55+
56+
if displacement < 0:
57+
displacement -= 2
58+
59+
self.y = self.y + displacement
60+
61+
if displacement < 0 or self.y < self.height + 50:
62+
if self.tilt < self.MAX_ROTATION:
63+
self.tilt = self.MAX_ROTATION
64+
else:
65+
if self.tilt > -90:
66+
self.tilt -= self.ROTATION_VELOCITY
67+
68+
def draw(self, win):
69+
self.image_count += 1
70+
71+
if self.image_count < self.ANIMATION_TIME:
72+
self.image = self.IMAGES[0]
73+
elif self.image_count < self.ANIMATION_TIME * 2:
74+
self.image = self.IMAGES[1]
75+
elif self.image_count < self.ANIMATION_TIME * 3:
76+
self.image = self.IMAGES[2]
77+
elif self.image_count < self.ANIMATION_TIME * 4:
78+
self.image = self.IMAGES[1]
79+
elif self.image_count == self.ANIMATION_TIME * 4 + 1:
80+
self.image = self.IMAGES[0]
81+
self.image_count = 0
82+
83+
if self.tilt <= -80:
84+
self.image = self.IMAGES[1]
85+
self.image_count = self.ANIMATION_TIME * 2
86+
87+
rotated_image = pygame.transform.rotate(self.image, self.tilt)
88+
new_rect = rotated_image.get_rect(center=self.image.get_rect(topleft=(self.x, self.y)).center)
89+
win.blit(rotated_image, new_rect.topleft)
90+
91+
def get_mask(self):
92+
return pygame.mask.from_surface(self.image)
93+
94+
95+
class Pipe:
96+
GAP = 200
97+
VEL = 5
98+
99+
def __init__(self, x):
100+
self.x = x
101+
self.height = 0
102+
103+
self.top = 0
104+
self.bottom = 0
105+
self.PIPE_TOP = pygame.transform.flip(PIPE_IMAGE, False, True)
106+
self.PIPE_BOTTOM = PIPE_IMAGE
107+
108+
self.passed = False
109+
self.set_height()
110+
111+
def set_height(self):
112+
self.height = random.randrange(50, 450)
113+
self.top = self.height - self.PIPE_TOP.get_height()
114+
self.bottom = self.height + self.GAP
115+
116+
def move(self):
117+
self.x -= self.VEL
118+
119+
def draw(self, win):
120+
win.blit(self.PIPE_TOP, (self.x, self.top))
121+
win.blit(self.PIPE_BOTTOM, (self.x, self.bottom))
122+
123+
def collide(self, bird):
124+
bird_mask = bird.get_mask()
125+
top_mask = pygame.mask.from_surface(self.PIPE_TOP)
126+
bottom_mask = pygame.mask.from_surface(self.PIPE_BOTTOM)
127+
128+
top_offset = (self.x - bird.x, self.top - round(bird.y))
129+
bottom_offset = (self.x - bird.x, self.bottom - round(bird.y))
130+
131+
t_point = bird_mask.overlap(top_mask, top_offset)
132+
b_point = bird_mask.overlap(bottom_mask, bottom_offset)
133+
134+
if t_point or b_point:
135+
return True
136+
137+
return False
138+
139+
140+
class Base:
141+
VEL = 5
142+
WIDTH = BASE_IMAGE.get_width()
143+
IMG = BASE_IMAGE
144+
145+
def __init__(self, y):
146+
self.y = y
147+
self.x1 = 0
148+
self.x2 = self.WIDTH
149+
150+
def move(self):
151+
self.x1 -= self.VEL
152+
self.x2 -= self.VEL
153+
154+
if self.x1 + self.WIDTH < 0:
155+
self.x1 = self.x2 + self.WIDTH
156+
157+
if self.x2 + self.WIDTH < 0:
158+
self.x2 = self.x1 + self.WIDTH
159+
160+
def draw(self, win):
161+
win.blit(self.IMG, (self.x1, self.y))
162+
win.blit(self.IMG, (self.x2, self.y))
163+
164+
165+
def draw_window(win, birds, pipes, base, score):
166+
win.blit(BG_IMAGE, (0, 0))
167+
for pipe in pipes:
168+
pipe.draw(win)
169+
170+
text = STAT_FONT.render("Score: " + str(score), 1, (255, 255, 255))
171+
win.blit(text, (WINDOW_WIDTH - 10 - text.get_width(), 10))
172+
173+
base.draw(win)
174+
for bird in birds:
175+
bird.draw(win)
176+
pygame.display.update()
177+
178+
179+
def main(genomes, config):
180+
nets = []
181+
ge = []
182+
birds = []
183+
184+
for _, g in genomes:
185+
net = neat.nn.FeedForwardNetwork.create(g, config)
186+
nets.append(net)
187+
birds.append(Bird(230, 350))
188+
g.fitness = 0
189+
ge.append(g)
190+
191+
base = Base(730)
192+
pipes = [Pipe(700)]
193+
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
194+
clock = pygame.time.Clock()
195+
score = 0
196+
197+
run = True
198+
while run:
199+
clock.tick(30)
200+
for event in pygame.event.get():
201+
if event.type == pygame.QUIT:
202+
run = False
203+
pygame.quit()
204+
quit()
205+
206+
pipe_ind = 0
207+
if len(birds) > 0:
208+
if len(pipes) > 1 and birds[0].x > pipes[0].x + pipes[0].PIPE_TOP.get_width():
209+
pipe_ind = 1
210+
else:
211+
run = False
212+
break
213+
214+
for x, bird in enumerate(birds):
215+
bird.move()
216+
ge[x].fitness += 0.1
217+
218+
output = nets[x].activate((bird.y, abs(bird.y - pipes[pipe_ind].height), abs(bird.y - pipes[pipe_ind].bottom)))
219+
220+
if output[0] > 0.5:
221+
bird.jump()
222+
223+
add_pipe = False
224+
remove_pipes = []
225+
for pipe in pipes:
226+
for x, bird in enumerate(birds):
227+
if pipe.collide(bird):
228+
ge[x].fitness -= 1
229+
birds.pop(x)
230+
nets.pop(x)
231+
ge.pop(x)
232+
233+
if not pipe.passed and pipe.x < bird.x:
234+
pipe.passed = True
235+
add_pipe = True
236+
237+
if pipe.x + pipe.PIPE_TOP.get_width() < 0:
238+
remove_pipes.append(pipe)
239+
240+
pipe.move()
241+
242+
if add_pipe:
243+
score += 1
244+
for g in ge:
245+
g.fitness += 5
246+
pipes.append(Pipe(700))
247+
248+
for pipe in remove_pipes:
249+
pipes.remove(pipe)
250+
251+
for x, bird in enumerate(birds):
252+
if bird.y + bird.image.get_height() >= 730 or bird.y < 0:
253+
birds.pop(x)
254+
nets.pop(x)
255+
ge.pop(x)
256+
257+
base.move()
258+
draw_window(win, birds, pipes, base, score)
259+
260+
261+
def run_neat():
262+
local_dir = os.path.dirname(__file__)
263+
config_path = os.path.join(local_dir, "config-feedforward.txt")
264+
config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
265+
neat.DefaultSpeciesSet, neat.DefaultStagnation,
266+
config_path)
267+
268+
population = neat.Population(config)
269+
population.add_reporter(neat.StdOutReporter(True))
270+
stats = neat.StatisticsReporter()
271+
population.add_reporter(stats)
272+
273+
winner = population.run(main, 50)
274+
275+
print("\nBest genome:\n{!s}".format(winner))
276+
277+
278+
if __name__ == "__main__":
279+
pygame.init()
280+
STAT_FONT = pygame.font.SysFont("comicsans", 50)
281+
run_neat()
282+

AI-driven AI Flappy Bird/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Package/Script Name: AI-driven AI Flappy Bird
2+
3+
Short Description: AI-driven AI Flappy Bird is a Python script that implements an AI player for the game "Flappy Bird." The AI player uses the Genetic Algorithm to learn and play the game automatically, aiming to achieve a high score.
4+
5+
Functionalities/Script:
6+
7+
FlappyBirdGame class: Represents the Flappy Bird game and handles game logic.
8+
AI_agent class: Implements the AI player using the Genetic Algorithm to learn and play the game.
9+
Heuristic evaluation function: Calculates the fitness of each AI agent based on its performance in the game.
10+
Board representation: Displays the game window, bird, and pipes.
11+
Setup Instructions:
12+
13+
Make sure you have Python installed on your system (Python 3.6 or higher).
14+
Install the required libraries using pip:
15+
bash
16+
Copy code
17+
pip install pygame
18+
Download the AI_flappy_bird.py file from the repository or package.
19+
Explanation of Script:
20+
The AI-driven AI Flappy Bird script utilizes the Genetic Algorithm to train AI agents to play the Flappy Bird game. The AI agents aim to learn how to navigate through pipes by optimizing their performance over multiple generations.
21+
22+
Usage:
23+
24+
Run the AI_flappy_bird.py script.
25+
bash
26+
Copy code
27+
python AI_flappy_bird.py
28+
The game window will open, and the AI agents will start playing Flappy Bird.
29+
Observe how the AI agents improve their performance over generations.
30+
Output:
31+
The AI-driven AI Flappy Bird script will display a game window where AI agents play the Flappy Bird game. The script will continuously show the performance of the current generation of AI agents. The AI agents will learn and adapt to navigate through the pipes more effectively over generations.
32+
33+
Author:
34+
Shikhar9425

0 commit comments

Comments
 (0)