Download main.py from Hite1/MarioKartReinforcementLearning: direct link, hf CLI and curl.
- Browser
- Download file 6.85 kB
-
https://huggingface.co/Hite1/MarioKartReinforcementLearning/resolve/main/main.py
- Command line
-
hf download hf://Hite1/MarioKartReinforcementLearning/main.py
-
curl -L -o main.py https://huggingface.co/Hite1/MarioKartReinforcementLearning/resolve/main/main.py
6.85 kB
| import pygame | |
| import os | |
| import math | |
| import sys | |
| import neat | |
| import time | |
| SCREEN_WIDTH = 1011 | |
| SCREEN_HEIGHT = 979 | |
| SCREEN = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) | |
| TRACK = pygame.image.load(os.path.join("Assets","mario_circuit1.png")) | |
| pygame.font.init() | |
| fastest_lap = float('inf') | |
| class Car(pygame.sprite.Sprite): | |
| def __init__(self): | |
| super().__init__() | |
| self.orig_image = pygame.image.load(os.path.join("Assets", "mario_kart_2.png")) | |
| self.image = self.orig_image | |
| self.rect = self.image.get_rect(center=(624, 800)) | |
| self.velocity = pygame.math.Vector2(0.8, 0) | |
| self.angle = 0 | |
| self.rotation = 2.5 | |
| self.direction = 0 | |
| self.alive = True | |
| self.radars = [] | |
| self.start= False | |
| self.lap_completed=False | |
| self.start_time=None | |
| self.cooldown= 3 | |
| def update(self): | |
| self.radars.clear() | |
| self.drive() | |
| self.rotate() | |
| for radar_angle in (-60, -30, 0, 30, 60): | |
| self.radar(radar_angle) | |
| self.collision() | |
| self.data() | |
| def drive(self): | |
| self.rect.center += self.velocity * 3 | |
| def collision(self): | |
| length = 30 | |
| col_right = [int(self.rect.center[0] + math.cos(math.radians(self.angle + 18)) * length), | |
| int(self.rect.center[1] - math.sin(math.radians(self.angle + 18)) * length)] | |
| col_left = [int(self.rect.center[0] + math.cos(math.radians(self.angle - 18)) * length), | |
| int(self.rect.center[1] - math.sin(math.radians(self.angle - 18)) * length)] | |
| #Boundary checks | |
| if SCREEN.get_at(col_right) == pygame.Color(135, 81, 48, 255) or SCREEN.get_at(col_left) == pygame.Color(135, 81, 48, 255): | |
| self.alive = False | |
| if SCREEN.get_at(col_right) == pygame.Color(0, 162, 232, 255) or SCREEN.get_at(col_left) == pygame.Color(0, 162, 232, 255): | |
| current_time=time.time() | |
| if not self.start: | |
| self.start = True | |
| self.start_time= current_time | |
| elif self.start and not self.lap_completed and (current_time-self.start_time)>self.cooldown: | |
| self.lap_completed = True | |
| #Collision points | |
| pygame.draw.circle(SCREEN, (0, 255, 255, 0), col_right, 4) | |
| pygame.draw.circle(SCREEN, (0, 255, 255, 0), col_left, 4) | |
| def rotate(self): | |
| if self.direction == 1: | |
| self.angle -= self.rotation | |
| self.velocity.rotate_ip(self.rotation) | |
| if self.direction == -1: | |
| self.angle += self.rotation | |
| self.velocity.rotate_ip(-self.rotation) | |
| self.image = pygame.transform.rotozoom(self.orig_image, self.angle, 0.08) | |
| self.rect = self.image.get_rect(center=self.rect.center) | |
| #Radar lines | |
| def radar(self, radar_angle): | |
| length = 0 | |
| x = int(self.rect.center[0]) | |
| y = int(self.rect.center[1]) | |
| while not SCREEN.get_at((x, y)) == pygame.Color(135, 81, 48, 255) and length < 125: | |
| length+=1 | |
| x = int(self.rect.center[0] + math.cos(math.radians(self.angle + radar_angle)) * length) | |
| y = int(self.rect.center[1] - math.sin(math.radians(self.angle + radar_angle)) * length) | |
| pygame.draw.line(SCREEN, (255, 255, 255), self.rect.center, (x, y), 1) | |
| pygame.draw.circle(SCREEN, (239, 20, 20,0), (x, y), 3) | |
| distance = int(math.sqrt((self.rect.center[0] - x) ** 2 + (self.rect.center[1] - y) ** 2)) | |
| self.radars.append([radar_angle, distance]) | |
| def data(self): | |
| input = [0,0,0,0,0] | |
| for i, radar in enumerate(self.radars): | |
| input[i] = int(radar[1]) | |
| return input | |
| def remove(i): | |
| cars.pop(i) | |
| ind.pop(i) | |
| Neurnet.pop(i) | |
| #Evaluation function | |
| def eval_fitness(popul,config): | |
| global cars,ind,Neurnet,fastest_lap | |
| cars=[] | |
| ind=[] | |
| Neurnet=[] | |
| for individual_id, individual in popul: | |
| cars.append(pygame.sprite.GroupSingle(Car())) | |
| ind.append(individual) | |
| net= neat.nn.FeedForwardNetwork.create(individual,config) | |
| Neurnet.append(net) | |
| individual.fitness = 0 | |
| start_time= None | |
| end_time=None | |
| run= True | |
| while run: | |
| for event in pygame.event.get(): | |
| if event.type == pygame.QUIT: | |
| pygame.quit() | |
| sys.exit() | |
| SCREEN.blit(TRACK, (0, 0)) | |
| if len(cars)==0: | |
| break | |
| for i,car in enumerate(cars): | |
| ind[i].fitness+=1 | |
| if not car.sprite.alive: | |
| remove(i) | |
| for i,car in enumerate(cars): | |
| output= Neurnet[i].activate(car.sprite.data()) | |
| if output[0]>0.7: | |
| car.sprite.direction=1 | |
| if output[1]<0.7: | |
| car.sprite.direction=-1 | |
| if output[0] <= 0.7 and output[1] <= 0.7: | |
| car.sprite.direction=0 | |
| if car.sprite.start and car.sprite.start_time is not None: | |
| current_time= time.time()-car.sprite.start_time | |
| else: | |
| current_time=0 | |
| if car.sprite.lap_completed: | |
| lap_time = current_time | |
| if lap_time < fastest_lap: | |
| fastest_lap = lap_time | |
| run = False | |
| break | |
| #Update | |
| for car in cars: | |
| car.draw(SCREEN) | |
| car.update() | |
| font = pygame.font.Font('Roboto-Medium.ttf', 20) | |
| text = font.render(f"Time: {current_time:.2f}", True, (40, 40, 0)) | |
| SCREEN.blit(text, (10, 10)) | |
| if fastest_lap == float('inf'): | |
| ftext = font.render("Fastest Lap: --:--", True, (40, 40, 0)) | |
| else: | |
| ftext = font.render(f"Fastest Lap: {fastest_lap:.2f}", True, (40, 40, 0)) | |
| SCREEN.blit(ftext, (10, 40)) | |
| pygame.display.update() | |
| return max(ind, key=lambda x: x.fitness) | |
| #Neural Network | |
| def run(config_file): | |
| global population | |
| config= neat.config.Config( | |
| neat.DefaultGenome, | |
| neat.DefaultReproduction, | |
| neat.DefaultSpeciesSet, | |
| neat.DefaultStagnation, | |
| config_file | |
| ) | |
| population= neat.Population(config) | |
| population.add_reporter(neat.StdOutReporter(True)) | |
| stats_reporter = neat.StatisticsReporter() | |
| population.add_reporter(stats_reporter) | |
| population.run(eval_fitness,75) | |
| if __name__=='__main__': | |
| local_directory= os.path.dirname(__file__) | |
| configuration_path= os.path.join(local_directory,"config.txt") | |
| run(configuration_path) | |