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 new file mode 100644 index 00000000..bc3311a4 --- /dev/null +++ b/Snake/main.py @@ -0,0 +1,93 @@ +import keyboard, time, random, os + +class Color: + red, green, normal = '\033[31m', '\033[32m', '\033[0m' + + +class Snake: + 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 in self.key_map) and (self.direction != self.opposite[self.key_map[key]]): + self.direction = self.key_map[key] + + + def move(self): + dx, dy = self.direction_map[self.direction] + self.length.append((self.x + dx, self.y + dy)) + + 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 WALL_COLLISION or SNAKE_COLLISION: + print('Game Over!') + exit() + + +class Apple: + def place(self): + while True: + self.x, self.y = random.randint(0, MAP_X_SIZE-1), random.randint(0, MAP_Y_SIZE-1) + + if not (self.x, self.y) in snake.length: return + + +class Renderer: + def __init__(self): + self.score = 0 + + + def render(self): + if (snake.x, snake.y) == (apple.x, apple.y): + self.score += 1 + apple.place() + snake.length.insert(0, 'SNAKE_GROWTH') + snake.move() + + os.system('clear' if os.name == 'posix' else 'cls') # Clears for the next render + + print('╔' + ('═' * MAP_X_SIZE * 2) + '╗') + + for y in range(MAP_Y_SIZE): + row = '║' + + for x in range(MAP_X_SIZE): + 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(f'Score: {self.score}') + + if self.score >= ((MAP_X_SIZE * MAP_Y_SIZE) - 1): + print('You Win!') + exit() + + +MAP_X_SIZE = MAP_Y_SIZE = 10 + +snake = Snake() +apple = Apple() +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) \ No newline at end of file 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