diff --git a/.gitignore b/.gitignore index f5e96db..06109db 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,153 @@ -venv \ No newline at end of file +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ diff --git a/Snake/img/Snake.png b/Snake/img/Snake.png new file mode 100644 index 0000000..8d1181c Binary files /dev/null and b/Snake/img/Snake.png differ diff --git a/Snake/main.py b/Snake/main.py index e69de29..4e25b69 100644 --- a/Snake/main.py +++ b/Snake/main.py @@ -0,0 +1,79 @@ +from ast import Break, Global +import pygame +from pygame.locals import * +import src.level as level +import src.snake as snake +import src.window as window + +HEIGH = 20 +WIDTH = 40 + +def main(): + # Init Matrix/Window + Matrix = level.init_level(HEIGH, WIDTH) + Screen = window.init_game() + + # Init Game Variables + clock = pygame.time.Clock() + Running = True + Direction = 'right' + Direction_prev = 'right' + Move_loop = 10 + Score = 0 + Difficulty = 1 + Fruit = False + + # Spawn snake head + L_snake = snake.List((5, 5), None) + + # Spawn first apple + level.spawn_apple(Matrix, HEIGH, WIDTH) + + while Running: + clock.tick(60) + + for event in pygame.event.get(): + if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: + Running = False + if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT: + Direction = 'right' + if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT: + Direction = 'left' + if event.type == pygame.KEYDOWN and event.key == pygame.K_UP: + Direction = 'up' + if event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN: + Direction = 'down' + + if Move_loop == 0: + if Direction == 'left' and Direction_prev == 'right' or Direction == 'right' and Direction_prev == 'left' or Direction == 'up' and Direction_prev == 'down' or Direction == 'down' and Direction_prev == 'up': + Direction = Direction_prev + + try: + L_snake, Matrix, Fruit, Score = snake.Snake_move(Matrix, L_snake, Direction, Score, HEIGH, WIDTH) + except ValueError as Error: + if Error.args[0] == 1: + print("You take a wall !") + elif Error.args[0] == 2: + print("You ate your tale !") + exit() + + if Fruit: + level.spawn_apple(Matrix, HEIGH, WIDTH) + + Direction_prev = Direction + if(Score > 1000): + Difficulty = int(Score/1000) + 1 + Move_loop = 11 - Difficulty + + Move_loop -= 1 + + # Draw Scene + Screen = window.draw_level(Screen, Matrix, Difficulty, Score, int(clock.get_fps()), HEIGH, WIDTH) + pygame.display.flip() + + # Print current fps + print(float("{0:.2f}".format(clock.get_fps())), 'fps') + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Snake/requirements.txt b/Snake/requirements.txt index 231dd17..485eb9e 100644 --- a/Snake/requirements.txt +++ b/Snake/requirements.txt @@ -1 +1,2 @@ -pygame \ No newline at end of file +pygame +numpy \ No newline at end of file diff --git a/Snake/src/level.py b/Snake/src/level.py index e69de29..b6167a5 100644 --- a/Snake/src/level.py +++ b/Snake/src/level.py @@ -0,0 +1,21 @@ +import numpy as np +import random + +# 0 = AIR +# 1 = SNAKE +# 2 = WALL +# 3 = APPLE + +def init_level(heigh, width): + return np.zeros((heigh, width)) + +def spawn_apple(M, heigh, width): + random.seed() + rand_heigh = random.randrange(0, heigh) + rand_width = random.randrange(0, width) + + if M[rand_heigh][rand_width] == 0: + M[rand_heigh][rand_width] = 3 + else: + spawn_apple(M, heigh, width) + \ No newline at end of file diff --git a/Snake/src/snake.py b/Snake/src/snake.py index e69de29..ed3d64e 100644 --- a/Snake/src/snake.py +++ b/Snake/src/snake.py @@ -0,0 +1,78 @@ + +DIRECTION = {'left': (0, -1), 'right': (0, 1), 'up': (-1, 0), 'down': (1, 0)} + +class List: + def __init__(self, val, next): + self.val = val + self.next = next + + def __str__(self): + if self.next == None: + return(f"{self.val} -> None") + else: + return(f"{self.val} -> {str(self.next)}") + + def is_empty(L): + return L is None + + def List_add(L, value): + if L == None: + return List(value, None) + else: + return List(L.val, List.List_add(L.next, value)) + + def List_size(L): + i = 0 + while L is not None: + i += 1 + L = L.next + + return i + +def Snake_move(M, L, dir, score, heigh, width): + Fruit = False + List_save = L + Save_Value = L.val + + # Calculate new snake head coord + if dir == 'left' and L.val[1] == 0: + Next_coord = (L.val[0], width-1) + elif dir == 'right' and L.val[1] == width-1: + Next_coord = (L.val[0], 0) + elif dir == 'up' and L.val[0] == 0: + Next_coord = (heigh-1, L.val[1]) + elif dir == 'down' and L.val[0] == heigh-1: + Next_coord = (0, L.val[1]) + else: + Next_coord = (DIRECTION[dir][0] + L.val[0], DIRECTION[dir][1] + L.val[1]) + + # Check nature of the future snake head coord + if M[Next_coord[0]][Next_coord[1]] == 3: + Fruit = True + elif M[Next_coord[0]][Next_coord[1]] == 2: + raise ValueError(1) # Error : You take a wall ! + quit + elif M[Next_coord[0]][Next_coord[1]] == 1: + raise ValueError(2) # Error : You ate your tale ! + quit + + # Update snake head coord and print on matrix + L.val = Next_coord + M[Next_coord[0]][Next_coord[1]] = 1 + L = L.next + + # Loot to update snake segment coord + while L is not None: + Save_bis_Value = L.val + L.val = Save_Value + Save_Value = Save_bis_Value + L = L.next + + # If snake eat fruit -> spawn new segment at the end of the snake + if Fruit: + List_save = List.List_add(List_save, Save_Value) + score += 50 + else: + M[Save_Value[0]][Save_Value[1]] = 0 + + return List_save, M, Fruit, score \ No newline at end of file diff --git a/Snake/src/window.py b/Snake/src/window.py index e69de29..1871b7d 100644 --- a/Snake/src/window.py +++ b/Snake/src/window.py @@ -0,0 +1,50 @@ +import pygame +from pygame.locals import * + +def init_game(): + pygame.init() + pygame.font.init() + screen = pygame.display.set_mode((1000, 525), pygame.SCALED) + pygame.display.set_caption("Snake") + + return screen + +def draw_level(S, M, difficulty, score, fps, heigh, width): + WHITE = (255, 255, 255) # AIR + GREEN = (0, 255, 0) # SNAKE + BROWN = (255,248,220) # WALL + RED = (255, 0, 0) # APPLE + + # Reset screen + pygame.draw.rect(S, (0, 0, 0), pygame.Rect(0, 0, 1000, 525)) + + my_font = pygame.font.SysFont('Comic Sans MS', 18) + + # Add FPS counter + text_fps = my_font.render(str(fps) + ' fps', False, (255, 255, 255)) + S.blit(text_fps, (10, 0)) + + # Add Score + text_score = my_font.render('Score : '+ str(score), False, (255, 255, 255)) + S.blit(text_score, (400, 0)) + + # Add Diffucilty + text_difficulty = my_font.render('Difficulty : '+ str(difficulty), False, (255, 255, 255)) + S.blit(text_difficulty, (850, 0)) + + Color = WHITE + + for j in range(heigh): + for i in range(width): + if M[j][i] == 0: + Color = WHITE + elif M[j][i] == 1: + Color = GREEN + elif M[j][i] == 2: + Color = BROWN + elif M[j][i] == 3: + Color = RED + + pygame.draw.rect(S, Color, pygame.Rect(i*25, j*25+25, 25, 25)) + + return S \ No newline at end of file