diff --git a/README.md b/README.md
index 28a3578..1b7ae7b 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,16 @@
+[![Open in Visual Studio Code](https://classroom.github.com/assets/open-in-vscode-718a45dd9cf7e7f842a935f5ebbe5719a5e09af4491e668f4dbf3b35d5cca122.svg)](https://classroom.github.com/online_ide?assignment_repo_id=14588401&assignment_repo_type=AssignmentRepo)
 
-:warning: Everything between << >> needs to be replaced (remove << >> after replacing)
+# Cuff Final Project
+## CS110 Final Project  Spring 2024
 
-# << Project Title >>
-## CS110 Final Project  << Semester, Year >>
-
-## Team Members
-
-<< List team member names >>
+## Team Members 
 
+Patrick Cuff 
 ***
 
 ## Project Description
 
-<< Give an overview of your project >>
-
+My project is meant to resemble the game "Crossy Road" to an extent. The player is meant to move vertically up the screen as enemies move horizontally across the screen. If you bump into an enemy, the game is over. The goal is to reach the end of the level(top of the screen) as fast as possible without dying, and the fastest time is the high score recorded. If you collide with an enemy, it is game over and you have the option of playing again. If you win, your best time is recorded and you have the option to play again to get the best score possible!
 ***    
 
 ## GUI Design
@@ -30,20 +27,76 @@
 
 ### Features
 
-1. << Feature 1 >>
-2. << Feature 2 >>
-3. << Feature 3 >>
-4. << Feature 4 >>
-5. << Feature 5 >>
+1. start button on main screen that starts the game 
+2.  player moves left, right, up, down by means of arrow key 
+3.  player dies and ends game as they collide with moving enemy
+4. player wins when they reach the top of the screen, win page appears
+5. game over screen appears once you collide with enemy, and the play again option is available setting you back to the starting position
+6.  win screen displays the high score, or "best time" in which the player has finished the game. This time can also be found in the top left of the screen as you play.
+
+
 
 ### Classes
 
-- << You should have a list of each of your classes with a description >>
+
+1. player_controller: This class handles the players movement in the window, using each movement(up,right,left,down) with its respective arrow key. It also initializes the players size, position, and score.
+
+2. enemy: This class handles the "enemies" or obstacles that move horizonatally across the screen and are to be avoided by the player. It also initializes the generation of these enemies' position, size, and their movement speed. 
+
+3. crossy_road_controller: This class handles the games main loop of the game itself. It takes in user inputs such as "start" and "play again" buttons. It also handles the detection of the player making contact with enemies, and will change the screen to the respective game over or winner screen depending on the games outcome. This class also handles the best score time dynamic by keeping count of the current run time, and comparing it with the overall kept best score. 
+         
+
 
 ## ATP
 
-| Step                 |Procedure             |Expected Results                   |
-|----------------------|:--------------------:|----------------------------------:|
-|  1                   | Run Counter Program  |GUI window appears with count = 0  |
-|  2                   | click count button   | display changes to count = 1      |
-etc...
+Test Case 1: Player Movement
+
+a. Test Description: Verify that the player moves left, right, up, and down as expected
+b. Test Steps:
+1. Press the start game button
+2. Press the arrow keys (up, down, left, right) to verify the player moves in their respective direction.
+c. Expected Outcome: The player should move in the corresponding direction according to the arrow key inputs.
+
+
+Test Case 2: Collision Detection with Enemy
+
+a. Test Description: Ensure that collisions between the player and enemies are detected correctly.
+b. Test Steps:
+1. press the start game button
+2. Use the arrow keys to move the player towards an enemy.
+3. Verify that when the player collides with an enemy, the game over screen appears.
+c. Expected Outcome: When the player collides with an enemy, the game over screen should appear.
+
+
+Test Case 3: Start Button/Main Menu Works
+
+a. Test Description: Test the functionality of the start button or main menu.
+b. Test Steps:
+1. Launch the game.
+2. Click on the start button located on the main menu
+3. Verify that the game starts once you press the button.
+c. Expected Outcome: Clicking on the start button should start the game.
+
+
+Test Case 4: Player wins
+
+a. Test Description: Confirm that once the player reaches the end of the level, they win and are taken to the win screen.
+b. Test Steps:
+1. press the start game button
+2. Move the player upward using the up key without hitting any enemies
+3. Touch the top of the screen with your player, reaching the maximum height
+4. Verify that the game takes you to the winner page, listing your best time.
+c. Expected Outcome: The player is taken to the win page after they reach the maximum height of the level.
+
+
+Test Case 5:  Play Again
+
+a. Test Description: Confirm that the play again button appears when the player collides with an enemy on the game over screen, and also appears when the player wins on the win screen.
+b. Test Steps:
+1. press the start game button
+2. use the arrow keys to move the player into an enemy
+3. verify that the play again button is offered and restarts the game for the player
+4. use the arrow keys to avoid enemies and reach the end of the level at the top
+5. verify that the play again button is offered on the win screeen and restarts the game for the player.
+Click on the play again button.
+c. Expected Outcome: The play again button should restart the game and allow the player to play again, offered when they die and when they win. 
\ No newline at end of file
diff --git a/__pycache__/crossy_road_controller.cpython-310.pyc b/__pycache__/crossy_road_controller.cpython-310.pyc
new file mode 100644
index 0000000..d089faf
Binary files /dev/null and b/__pycache__/crossy_road_controller.cpython-310.pyc differ
diff --git a/__pycache__/enemy.cpython-310.pyc b/__pycache__/enemy.cpython-310.pyc
new file mode 100644
index 0000000..c7f7414
Binary files /dev/null and b/__pycache__/enemy.cpython-310.pyc differ
diff --git a/__pycache__/player_controller.cpython-310.pyc b/__pycache__/player_controller.cpython-310.pyc
new file mode 100644
index 0000000..1bac5b3
Binary files /dev/null and b/__pycache__/player_controller.cpython-310.pyc differ
diff --git a/assets/finalgui.jpg b/assets/finalgui.jpg
new file mode 100644
index 0000000..751030e
Binary files /dev/null and b/assets/finalgui.jpg differ
diff --git a/assets/gui.jpg b/assets/gui.jpg
index cf4630c..bb1eeda 100644
Binary files a/assets/gui.jpg and b/assets/gui.jpg differ
diff --git a/besttime.txt b/besttime.txt
new file mode 100644
index 0000000..dfe1cba
--- /dev/null
+++ b/besttime.txt
@@ -0,0 +1 @@
+20.008684873580933
\ No newline at end of file
diff --git a/crossy_road_controller.py b/crossy_road_controller.py
new file mode 100644
index 0000000..73f58c7
--- /dev/null
+++ b/crossy_road_controller.py
@@ -0,0 +1,176 @@
+import pygame
+import sys
+import time
+import random
+from player_controller import PlayerController
+from enemy import Enemy
+
+class CrossyRoadController:
+    def __init__(self):
+        pygame.init()
+        self.screen_width = 800
+        self.screen_height = 600
+        self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
+        pygame.display.set_caption("Crossy Road")
+        self.clock = pygame.time.Clock()
+        self.player_size = 50
+        self.player_speed = 5
+        self.enemy_size = 50
+        self.enemy_speed = 3
+        self.enemies = []
+        self.player_controller = PlayerController(self.screen_width, self.screen_height, self.player_size,
+                                                  self.player_speed)
+        self.running = False
+        self.game_over = False
+        self.best_time = None
+        self.start_time = 0
+
+    def load_best_time(self):
+        try:
+            with open("besttime.txt", "r") as file:
+                return float(file.read())
+        except FileNotFoundError:
+            return None
+
+    def save_best_time(self):
+        with open("besttime.txt", "w") as file:
+            if self.best_time is not None:
+                file.write(str(self.best_time))
+            else:
+                file.write("N/A")
+
+    def generate_enemy(self):
+        initial_y = random.randint(0, self.screen_height - self.enemy_size)
+        direction = random.choice(["LEFT", "RIGHT"])
+        enemy = Enemy(self.screen_width, self.screen_height, self.enemy_size, self.enemy_speed, direction, initial_y)
+        self.enemies.append(enemy)
+
+    def handle_keyboard_events(self):
+        for event in pygame.event.get():
+            if event.type == pygame.QUIT:
+                sys.exit()
+            if event.type == pygame.KEYDOWN:
+                if event.key == pygame.K_UP:
+                    self.player_controller.move_up()
+                elif event.key == pygame.K_DOWN:
+                    self.player_controller.move_down()
+                elif event.key == pygame.K_LEFT:
+                    self.player_controller.move_left()
+                elif event.key == pygame.K_RIGHT:
+                    self.player_controller.move_right()
+
+    def handle_mouse_events(self):
+        for event in pygame.event.get():
+            if event.type == pygame.QUIT:
+                sys.exit()
+            elif event.type == pygame.MOUSEBUTTONDOWN:
+                if not self.running and not self.game_over:
+                    if 300 <= event.pos[0] <= 500 and 400 <= event.pos[1] <= 450:
+                        self.start_game()
+                elif self.game_over:
+                    if 300 <= event.pos[0] <= 500 and 400 <= event.pos[1] <= 450:
+                        self.start_game()
+
+    def start_game(self):
+        self.running = True
+        self.game_over = False
+        self.enemies.clear()
+        self.player_controller.player.topleft = self.player_controller.initial_player_position
+        self.player_controller.score = 0
+        self.start_time = time.time()
+
+    def move_enemies(self):
+        for enemy in self.enemies:
+            enemy.move()
+
+    def check_collisions(self):
+        for enemy in self.enemies:
+            if self.player_controller.player.colliderect(enemy.rect):
+                self.game_over = True
+                self.running = False
+
+    def check_win_condition(self):
+        if self.player_controller.player.top <= 0:
+            self.running = False
+            self.game_over = True
+            time_taken = time.time() - self.start_time
+            if self.best_time is None or time_taken < self.best_time:
+                self.best_time = time_taken
+                self.save_best_time()
+
+    def draw_best_time(self):
+        font = pygame.font.Font(None, 24)
+        if self.best_time is None:
+            best_time_text = font.render("Best Time: N/A", True, pygame.Color("black"))
+        else:
+            best_time_text = font.render("Best Time: " + "{:.2f}".format(self.best_time) + " seconds", True,
+                                         pygame.Color("black"))
+        self.screen.blit(best_time_text, (10, 30))
+
+    def draw_start_screen(self):
+        self.screen.fill((255, 255, 255))
+        font = pygame.font.Font(None, 36)
+        main_menu_text = font.render("Main Menu", True, pygame.Color("blue"))
+        self.screen.blit(main_menu_text, (330, 100))
+        adaptation_text = font.render("Crossy Road Adaptation: By Pat Cuff", True, pygame.Color("blue"))
+        self.screen.blit(adaptation_text, (180, 150))
+        start_button = pygame.Rect(300, 400, 200, 50)
+        pygame.draw.rect(self.screen, pygame.Color("green"), start_button)
+        start_text = font.render("Start", True, pygame.Color("black"))
+        self.screen.blit(start_text, (370, 410))
+
+    def draw_game_over_screen(self):
+        self.screen.fill((255, 255, 255))
+        font = pygame.font.Font(None, 36)
+        game_over_text = font.render("Game Over", True, pygame.Color("red"))
+        self.screen.blit(game_over_text, (340, 200))
+        final_score_text = font.render("Best Time: " + ("N/A" if self.best_time is None else "{:.2f}".format(self.best_time)) + " seconds", True,
+                                       pygame.Color("black"))
+        self.screen.blit(final_score_text, (300, 250))
+        play_again_button = pygame.Rect(300, 400, 200, 50)
+        pygame.draw.rect(self.screen, pygame.Color("green"), play_again_button)
+        play_again_text = font.render("Play Again", True, pygame.Color("black"))
+        self.screen.blit(play_again_text, (340, 410))
+
+    def draw_win_screen(self):
+        self.screen.fill((255, 255, 255))
+        font = pygame.font.Font(None, 36)
+        win_text = font.render("You Win!", True, pygame.Color("green"))
+        self.screen.blit(win_text, (340, 200))
+        final_score_text = font.render("Best Time: " + ("N/A" if self.best_time is None else "{:.2f}".format(self.best_time)) + " seconds", True,
+                                       pygame.Color("black"))
+        self.screen.blit(final_score_text, (300, 250))
+        play_again_button = pygame.Rect(300, 400, 200, 50)
+        pygame.draw.rect(self.screen, pygame.Color("green"), play_again_button)
+        play_again_text = font.render("Play Again", True, pygame.Color("black"))
+        self.screen.blit(play_again_text, (340, 410))
+
+    def run_game(self):
+        while True:
+            if self.running:
+                self.handle_keyboard_events()
+            else:
+                self.handle_mouse_events()
+
+            if self.running:
+                if random.random() < 0.02:
+                    self.generate_enemy()
+                self.move_enemies()
+                self.check_collisions()
+                self.check_win_condition() 
+                self.screen.fill((255, 255, 255))  # Clear screen before drawing
+                self.draw_best_time()
+                pygame.draw.rect(self.screen, pygame.Color("blue"), self.player_controller.player)
+                for enemy in self.enemies:
+                    pygame.draw.rect(self.screen, pygame.Color("red"), enemy.rect)
+            else:
+                if self.game_over:
+                    if self.player_controller.player.top <= 0: 
+                        self.draw_win_screen()  
+                    else:
+                        self.draw_game_over_screen()  
+                else:
+                    self.draw_start_screen()
+
+            pygame.display.update()
+            self.clock.tick(60)
\ No newline at end of file
diff --git a/enemy.py b/enemy.py
new file mode 100644
index 0000000..7977dfe
--- /dev/null
+++ b/enemy.py
@@ -0,0 +1,26 @@
+import pygame
+import random
+
+class Enemy:
+    def __init__(self, screen_width, screen_height, size, speed, direction, initial_y):
+        self.screen_width = screen_width
+        self.screen_height = screen_height
+        self.size = size
+        self.speed = speed
+        self.direction = direction
+        self.initial_y = initial_y
+        self.rect = self.initialize_position()
+
+    def initialize_position(self):
+        if self.direction == "LEFT":
+            x = self.screen_width
+        else:
+            x = -self.size
+        y = self.initial_y
+        return pygame.Rect(x, y, self.size, self.size)
+
+    def move(self):
+        if self.direction == "LEFT":
+            self.rect.x -= self.speed
+        else:
+            self.rect.x += self.speed
\ No newline at end of file
diff --git a/main.py b/main.py
index a5c44c6..3111bd4 100644
--- a/main.py
+++ b/main.py
@@ -1,13 +1,5 @@
-import pygame
-#import your controller
+from crossy_road_controller import CrossyRoadController
 
-def main():
-    pygame.init()
-    #Create an instance on your controller object
-    #Call your mainloop
-    
-    ###### NOTHING ELSE SHOULD GO IN main(), JUST THE ABOVE 3 LINES OF CODE ######
-
-# https://codefather.tech/blog/if-name-main-python/
-if __name__ == '__main__':
-    main()
+if __name__ == "__main__":
+    game = CrossyRoadController()
+    game.run_game()
diff --git a/player_controller.py b/player_controller.py
new file mode 100644
index 0000000..551c7b5
--- /dev/null
+++ b/player_controller.py
@@ -0,0 +1,29 @@
+import pygame
+
+class PlayerController:
+    def __init__(self, screen_width, screen_height, player_size, player_speed):
+        self.screen_width = screen_width
+        self.screen_height = screen_height
+        self.player_size = player_size
+        self.player_speed = player_speed
+        self.initial_player_position = (self.screen_width // 2 - self.player_size // 2,
+                                        self.screen_height - self.player_size - 10)
+        self.player = pygame.Rect(*self.initial_player_position, self.player_size, self.player_size)
+        self.score = 0
+
+    def move_up(self):
+        if self.player.top > 0:
+            self.player.y -= self.player_speed
+            self.score += 1
+
+    def move_down(self):
+        if self.player.bottom < self.screen_height:
+            self.player.y += self.player_speed
+
+    def move_left(self):
+        if self.player.left > 0:
+            self.player.x -= self.player_speed
+
+    def move_right(self):
+        if self.player.right < self.screen_width:
+            self.player.x += self.player_speed
\ No newline at end of file