From e300ba7257e63d9e5d704ab2ae61c8461cd92abe Mon Sep 17 00:00:00 2001 From: Azurrati <246398444+Azurrati@users.noreply.github.com> Date: Sun, 19 Apr 2026 13:47:25 -0700 Subject: [PATCH 1/5] Added Snake game --- Snake/main.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 Snake/main.py diff --git a/Snake/main.py b/Snake/main.py new file mode 100644 index 00000000..9845b9ed --- /dev/null +++ b/Snake/main.py @@ -0,0 +1,95 @@ +import keyboard, time, random, os, threading + +class Color: red, green, normal = '\033[31m', '\033[32m', '\033[0m' + +class Snake: + def __init__(self, x_pos, y_pos): + self.x, self.y = x_pos, y_pos + self.direction = None + self.length = [(self.x, self.y)] + + def new_direction(self, key): + if key == 'a' and self.direction != 'R': self.direction = 'L' + elif key == 'd' and self.direction != 'L': self.direction = 'R' + elif key == 'w' and self.direction != 'D': self.direction = 'U' + elif key == 's' and self.direction != 'U': self.direction = 'D' + + def move(self): + if self.direction == 'L': self.length.append((self.x-1, self.y)) + elif self.direction == 'R': self.length.append((self.x+1, self.y)) + elif self.direction == 'U': self.length.append((self.x, self.y-1)) + elif self.direction == 'D': self.length.append((self.x, self.y+1)) + elif self.direction == None: self.length.append((self.x, self.y)) + + self.x, self.y = self.length[-1][0], self.length[-1][1] + self.length.pop(0) + + if self.length[-1] in self.length[:-1]: print('Game Over!'), exit() + if (self.x < 0) or (self.x > MAP_X_SIZE-1) or (self.y < 0) or (self.y > MAP_Y_SIZE-1): print('Game Over!'), exit() + +class Apple: + def __init__(self, x_pos, y_pos): + self.x, self.y = x_pos, y_pos + + while (self.x, self.y) in snake.length: + self.x = random.randint(0, MAP_X_SIZE-1) + self.y = random.randint(0, MAP_Y_SIZE-1) + + def eaten(self): + self.x = random.randint(0, MAP_X_SIZE-1) + self.y = random.randint(0, MAP_Y_SIZE-1) + + while (self.x, self.y) in snake.length: + self.x = random.randint(0, MAP_X_SIZE-1) + self.y = random.randint(0, MAP_Y_SIZE-1) + +class Renderer: + def __init__(self, x_size, y_size): + self.x_size, self.y_size = x_size, y_size + self.score = 0 + + def render(self): + if (snake.x == apple.x) and (snake.y == apple.y): + self.score += 1 + apple.eaten() + snake.length.insert(0, snake.length[0]) + snake.move() + + os.system('clear' if os.name == 'posix' else 'cls') + + print('╔' + '═'*(MAP_X_SIZE*2) + '╗') + print('║' + f' Score: {self.score}' + ' '*((MAP_X_SIZE*2) - 8 - len(str(self.score))) + '║') + print('╠' + '═'*(MAP_X_SIZE*2) + '╣') + + for y in range(self.y_size): + row = '' + row += '║' + + for x in range(self.x_size): + if (x,y) in snake.length: row += Color.green + '[]' + Color.normal + elif (x == apple.x) and (y == apple.y): row += Color.red + '[]' + Color.normal + else: row += ' .' + + row += '║' + print(row) + + print('╚' + '═'*MAP_X_SIZE*2 + '╝') + +MAP_X_SIZE = MAP_Y_SIZE = 10 + +snake = Snake(random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1)) +apple = Apple(random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1)) +map = Renderer(MAP_X_SIZE, MAP_Y_SIZE) + +def keyboard_handler(): + while True: + event = keyboard.read_event() + if event.event_type == keyboard.KEY_DOWN: snake.new_direction(event.name) + +def map_renderer(): + while True: + map.render() + time.sleep(0.15) + +threading.Thread(target=keyboard_handler, daemon=True).start() +map_renderer() \ No newline at end of file From 599296cdb3880214c1e76c748ef176f6ab2c856a Mon Sep 17 00:00:00 2001 From: Azurrati <246398444+Azurrati@users.noreply.github.com> Date: Tue, 21 Apr 2026 20:55:44 -0700 Subject: [PATCH 2/5] Made a few changes with snake game --- Snake/main.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Snake/main.py b/Snake/main.py index 9845b9ed..8cdde9ad 100644 --- a/Snake/main.py +++ b/Snake/main.py @@ -44,8 +44,7 @@ def eaten(self): self.y = random.randint(0, MAP_Y_SIZE-1) class Renderer: - def __init__(self, x_size, y_size): - self.x_size, self.y_size = x_size, y_size + def __init__(self): self.score = 0 def render(self): @@ -58,28 +57,29 @@ def render(self): os.system('clear' if os.name == 'posix' else 'cls') print('╔' + '═'*(MAP_X_SIZE*2) + '╗') - print('║' + f' Score: {self.score}' + ' '*((MAP_X_SIZE*2) - 8 - len(str(self.score))) + '║') - print('╠' + '═'*(MAP_X_SIZE*2) + '╣') - for y in range(self.y_size): + for y in range(MAP_Y_SIZE): row = '' row += '║' - for x in range(self.x_size): + for x in range(MAP_X_SIZE): if (x,y) in snake.length: row += Color.green + '[]' + Color.normal - elif (x == apple.x) and (y == apple.y): row += Color.red + '[]' + Color.normal + elif (x == apple.x) and (y == apple.y): row += Color.red + '()' + Color.normal else: row += ' .' row += '║' print(row) print('╚' + '═'*MAP_X_SIZE*2 + '╝') + print(f'Score: {self.score}') -MAP_X_SIZE = MAP_Y_SIZE = 10 + if self.score >= ((MAP_X_SIZE * MAP_Y_SIZE) - 1): print('You Win!'), exit() + +MAP_X_SIZE = MAP_Y_SIZE = 6 snake = Snake(random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1)) apple = Apple(random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1)) -map = Renderer(MAP_X_SIZE, MAP_Y_SIZE) +map = Renderer() def keyboard_handler(): while True: From 95b11012cb02d8767cc92cdeeba005a0c8cb02a9 Mon Sep 17 00:00:00 2001 From: Azurrati <246398444+Azurrati@users.noreply.github.com> Date: Thu, 23 Apr 2026 21:20:53 -0700 Subject: [PATCH 3/5] Added the final touches for main.py and README.md --- Snake/README.md | 36 ++++++++++++++++++++++++++++++++++++ Snake/main.py | 2 +- Snake/requirements.txt | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 Snake/README.md create mode 100644 Snake/requirements.txt diff --git a/Snake/README.md b/Snake/README.md new file mode 100644 index 00000000..4dd28cdd --- /dev/null +++ b/Snake/README.md @@ -0,0 +1,36 @@ +# Snake Game + +## Overview +In Snake, you must eat apples that appear. You will grow each time you eat an apple. Try to get the highest score possible and try not to hit the wall or yourself. + + +## Controls +Press `a` to move left + +Press `d` to move right + +Press `s` to move down + +Press `w` to move up + + +## Installation + +1. **Clone the repository** + + ```bash + git clone https://github.com/josharsh/100LinesOfCode + cd 100LinesOfCode/snake + ``` + +2. **Install dependencies** + + ```bash + pip install -r requirements.txt + ``` + or + ```bash + pip install keyboard + ``` + +> This installs only the dependencies required for the Snake game (e.g., `keyboard`). diff --git a/Snake/main.py b/Snake/main.py index 8cdde9ad..20aec347 100644 --- a/Snake/main.py +++ b/Snake/main.py @@ -75,7 +75,7 @@ def render(self): if self.score >= ((MAP_X_SIZE * MAP_Y_SIZE) - 1): print('You Win!'), exit() -MAP_X_SIZE = MAP_Y_SIZE = 6 +MAP_X_SIZE = MAP_Y_SIZE = 10 snake = Snake(random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1)) apple = Apple(random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1)) diff --git a/Snake/requirements.txt b/Snake/requirements.txt new file mode 100644 index 00000000..fbfe7243 --- /dev/null +++ b/Snake/requirements.txt @@ -0,0 +1 @@ +keyboard \ No newline at end of file From d7f4d680687a0517c196fce7fdb9164731913bef Mon Sep 17 00:00:00 2001 From: Azurrati <246398444+Azurrati@users.noreply.github.com> Date: Sat, 6 Jun 2026 16:45:13 -0700 Subject: [PATCH 4/5] Increased Simplicity and Readability. --- Snake/main.py | 108 +++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/Snake/main.py b/Snake/main.py index 20aec347..62e54a9a 100644 --- a/Snake/main.py +++ b/Snake/main.py @@ -1,95 +1,95 @@ -import keyboard, time, random, os, threading +import keyboard, time, random, os + +class Color: + red, green, normal = '\033[31m', '\033[32m', '\033[0m' -class Color: red, green, normal = '\033[31m', '\033[32m', '\033[0m' class Snake: - def __init__(self, x_pos, y_pos): - self.x, self.y = x_pos, y_pos + def __init__(self): + self.x, self.y = random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1) self.direction = None self.length = [(self.x, self.y)] + + self.key_map = { 'a': 'Left', 'd': 'Right', 'w': 'Up', 's': 'Down' } + self.direction_map = { 'Left': (-1, 0), 'Right': (1, 0), 'Up': (0, -1), 'Down': (0, 1), None: (0, 0) } + self.opposite = { 'Left': 'Right', 'Right': 'Left', 'Up': 'Down', 'Down': 'Up'} + def new_direction(self, key): - if key == 'a' and self.direction != 'R': self.direction = 'L' - elif key == 'd' and self.direction != 'L': self.direction = 'R' - elif key == 'w' and self.direction != 'D': self.direction = 'U' - elif key == 's' and self.direction != 'U': self.direction = 'D' - + if (key in self.key_map) and (self.direction != self.opposite[self.key_map[key]]): + self.direction = self.key_map[key] + + def move(self): - if self.direction == 'L': self.length.append((self.x-1, self.y)) - elif self.direction == 'R': self.length.append((self.x+1, self.y)) - elif self.direction == 'U': self.length.append((self.x, self.y-1)) - elif self.direction == 'D': self.length.append((self.x, self.y+1)) - elif self.direction == None: self.length.append((self.x, self.y)) + dx, dy = self.direction_map[self.direction] + self.length.append((self.x + dx, self.y + dy)) - self.x, self.y = self.length[-1][0], self.length[-1][1] + self.x, self.y = self.length[-1] self.length.pop(0) - if self.length[-1] in self.length[:-1]: print('Game Over!'), exit() - if (self.x < 0) or (self.x > MAP_X_SIZE-1) or (self.y < 0) or (self.y > MAP_Y_SIZE-1): print('Game Over!'), exit() + + if self.length[-1] in self.length[:-1]: + print('Game Over!') + exit() + + if (self.x < 0) or (self.x > MAP_X_SIZE-1) or (self.y < 0) or (self.y > MAP_Y_SIZE-1): + print('Game Over!') + exit() + class Apple: - def __init__(self, x_pos, y_pos): - self.x, self.y = x_pos, y_pos + def place(self): + while True: + self.x, self.y = random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1) - while (self.x, self.y) in snake.length: - self.x = random.randint(0, MAP_X_SIZE-1) - self.y = random.randint(0, MAP_Y_SIZE-1) - - def eaten(self): - self.x = random.randint(0, MAP_X_SIZE-1) - self.y = random.randint(0, MAP_Y_SIZE-1) + if not (self.x, self.y) in snake.length: return - while (self.x, self.y) in snake.length: - self.x = random.randint(0, MAP_X_SIZE-1) - self.y = random.randint(0, MAP_Y_SIZE-1) class Renderer: def __init__(self): self.score = 0 - + + def render(self): - if (snake.x == apple.x) and (snake.y == apple.y): + if (snake.x, snake.y) == (apple.x, apple.y): self.score += 1 - apple.eaten() - snake.length.insert(0, snake.length[0]) + apple.place() + snake.length.insert(0, 'SNAKE_GROWTH') snake.move() - os.system('clear' if os.name == 'posix' else 'cls') + os.system('clear' if os.name == 'posix' else 'cls') # Clears for the next render - print('╔' + '═'*(MAP_X_SIZE*2) + '╗') + print('╔' + ('═' * MAP_X_SIZE * 2) + '╗') for y in range(MAP_Y_SIZE): - row = '' - row += '║' + row = '║' for x in range(MAP_X_SIZE): - if (x,y) in snake.length: row += Color.green + '[]' + Color.normal - elif (x == apple.x) and (y == apple.y): row += Color.red + '()' + Color.normal - else: row += ' .' + if (x, y) in snake.length: row += f'{Color.green}[]{Color.normal}' + elif (x, y) == (apple.x, apple.y): row += f'{Color.red}(){Color.normal}' + else: row += ' .' row += '║' print(row) - print('╚' + '═'*MAP_X_SIZE*2 + '╝') + print('╚' + ('═' * MAP_X_SIZE * 2) + '╝') print(f'Score: {self.score}') - if self.score >= ((MAP_X_SIZE * MAP_Y_SIZE) - 1): print('You Win!'), exit() + if self.score >= ((MAP_X_SIZE * MAP_Y_SIZE) - 1): + print('You Win!') + exit() + MAP_X_SIZE = MAP_Y_SIZE = 10 -snake = Snake(random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1)) -apple = Apple(random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1)) +snake = Snake() +apple = Apple() map = Renderer() -def keyboard_handler(): - while True: - event = keyboard.read_event() - if event.event_type == keyboard.KEY_DOWN: snake.new_direction(event.name) - -def map_renderer(): +if __name__ == '__main__': + apple.place() + keyboard.on_press(lambda key_input: snake.new_direction(key_input.name)) # This always checks for input, even if it's not in a loop + while True: map.render() - time.sleep(0.15) - -threading.Thread(target=keyboard_handler, daemon=True).start() -map_renderer() \ No newline at end of file + time.sleep(0.15) \ No newline at end of file From 8e0ab1eefb310f22b31d597fc78a7e92f4a1fd02 Mon Sep 17 00:00:00 2001 From: Azurrati <246398444+Azurrati@users.noreply.github.com> Date: Mon, 8 Jun 2026 21:26:42 -0700 Subject: [PATCH 5/5] Slight readability and simplicity increase --- Snake/main.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Snake/main.py b/Snake/main.py index 62e54a9a..bc3311a4 100644 --- a/Snake/main.py +++ b/Snake/main.py @@ -27,12 +27,10 @@ def move(self): self.x, self.y = self.length[-1] self.length.pop(0) + WALL_COLLISION = (self.x < 0) or (self.x > MAP_X_SIZE-1) or (self.y < 0) or (self.y > MAP_Y_SIZE-1) + SNAKE_COLLISION = self.length[-1] in self.length[:-1] - if self.length[-1] in self.length[:-1]: - print('Game Over!') - exit() - - if (self.x < 0) or (self.x > MAP_X_SIZE-1) or (self.y < 0) or (self.y > MAP_Y_SIZE-1): + if WALL_COLLISION or SNAKE_COLLISION: print('Game Over!') exit()