From 3308ca0dc4c60e69bd253e547428a0e1ead5bdfa Mon Sep 17 00:00:00 2001 From: Jon Bergland Date: Tue, 5 Mar 2024 17:52:16 +0000 Subject: [PATCH 01/10] feat: add class for tetris game manager --- src/game/TetrisGameManager.py | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/game/TetrisGameManager.py diff --git a/src/game/TetrisGameManager.py b/src/game/TetrisGameManager.py new file mode 100644 index 0000000..c815dbd --- /dev/null +++ b/src/game/TetrisGameManager.py @@ -0,0 +1,62 @@ +baseScore = 100 +DOWN = (0, 1) +LEFT = (-1, 0) +RIGHT = (1, 0) + + +class TetrisGameManager: + + current_piece = None + new_piece = None + score = 0 + + def __init__(self, board): + self.board = board + self.score = 0 + + def rotate_piece(self, direction): + self.current_piece.rotate(direction) + + + def move_piece(self, direction): + + self.current_piece.move(direction) + + def drop_piece(self, newPiece): + if self.legal_move(DOWN): + self.move_piece(DOWN) + + def is_game_over(self): + return self.board.is_game_over() + + def start_game(self): + self.current_piece = self.next_piece() + self.next_piece = self.next_piece() + + + def legal_move(self, x, y): + return self.board.legal_move(x, y) + + def clear_lines(self): + lines_cleared = self.board.clear_lines() + self.update_score(lines_cleared) + + def update_score(self, lines_cleared): + self.score += baseScore**lines_cleared + + def place_piece(self, direction): + x = direction[0] + y = direction[1] + if self.legal_move(x, y): + self.board.place_piece(x, y, self.current_piece) + + if self.is_game_over(): + self.stop_game() + + def new_piece(self): + return self.pieces.get_new_piece() + + def stop_game(self): + self.board.stop_game() + +print(DOWN.index(1)) \ No newline at end of file From 787be747d3d72fa0605c981cc4d27af3820b838a Mon Sep 17 00:00:00 2001 From: Jon Bergland Date: Tue, 5 Mar 2024 18:40:21 +0000 Subject: [PATCH 02/10] refactor: change method names and method implementation Co-authored-by: oystkva --- src/game/TetrisGameManager.py | 76 +++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/src/game/TetrisGameManager.py b/src/game/TetrisGameManager.py index c815dbd..7a1c166 100644 --- a/src/game/TetrisGameManager.py +++ b/src/game/TetrisGameManager.py @@ -1,3 +1,5 @@ +import keyboard + baseScore = 100 DOWN = (0, 1) LEFT = (-1, 0) @@ -6,57 +8,63 @@ class TetrisGameManager: - current_piece = None - new_piece = None + currentPiece = None + nextPiece = None score = 0 + updateTimer = 1 + streak = 1 def __init__(self, board): self.board = board self.score = 0 - def rotate_piece(self, direction): - self.current_piece.rotate(direction) + def rotatePiece(self, direction): + self.currentPiece.rotate(direction) - def move_piece(self, direction): + def movePiece(self, direction): - self.current_piece.move(direction) + if self.legalMove(direction): + self.currentPiece.move(direction) - def drop_piece(self, newPiece): - if self.legal_move(DOWN): - self.move_piece(DOWN) + def dropPiece(self, newPiece): + self.movePiece(DOWN) - def is_game_over(self): - return self.board.is_game_over() + def isGameOver(self): + return self.board.isGameOver() - def start_game(self): - self.current_piece = self.next_piece() - self.next_piece = self.next_piece() + def startGame(self): + self.currentPiece = self.newPiece() + self.nextPiece = self.newPiece() + def newPiece(self): + return self.pieces.getNewPiece() - def legal_move(self, x, y): - return self.board.legal_move(x, y) + def legalMove(self, x, y): + return self.board.legalMove(x, y) - def clear_lines(self): - lines_cleared = self.board.clear_lines() - self.update_score(lines_cleared) + def clearLines(self): + linesCleared = self.board.checkGameState() + if linesCleared == 4: + self.streak += 1 + else: + self.streak = 1 + + self.updateScore(linesCleared) - def update_score(self, lines_cleared): - self.score += baseScore**lines_cleared + def updateScore(self, linesCleared): + self.score += self.streak*(baseScore**linesCleared) - def place_piece(self, direction): + def placePiece(self, direction): x = direction[0] y = direction[1] - if self.legal_move(x, y): - self.board.place_piece(x, y, self.current_piece) - - if self.is_game_over(): - self.stop_game() + if self.legalMove(x, y): + self.board.placePiece(x, y, self.currentPiece) + self.currentPiece = self.nextPiece + self.next_piece = self.nextPiece() + if self.isGameOver(): + self.stopGame() - def new_piece(self): - return self.pieces.get_new_piece() - - def stop_game(self): - self.board.stop_game() - -print(DOWN.index(1)) \ No newline at end of file + + def stopGame(self): + self.board.stop_game() \ No newline at end of file From 40a2d2a6e45e8200891b6710163ea0e8c545710e Mon Sep 17 00:00:00 2001 From: Jon Bergland Date: Tue, 5 Mar 2024 18:59:33 +0000 Subject: [PATCH 03/10] refactor: move clearLines-method to placePiece-method Co-authored-by: oystkva --- src/game/TetrisGameManager.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/game/TetrisGameManager.py b/src/game/TetrisGameManager.py index 7a1c166..7d5a463 100644 --- a/src/game/TetrisGameManager.py +++ b/src/game/TetrisGameManager.py @@ -1,10 +1,19 @@ -import keyboard +import keyboard as kb +import time as t baseScore = 100 DOWN = (0, 1) LEFT = (-1, 0) RIGHT = (1, 0) +""" TODO: Timer for piece drop + keyboard input for piece movement + keyboard input for piece rotation + keyboard input for piece drop + keyboard input for game start + soft drop and hard drop implementation + """ + class TetrisGameManager: @@ -43,14 +52,13 @@ def newPiece(self): def legalMove(self, x, y): return self.board.legalMove(x, y) - def clearLines(self): - linesCleared = self.board.checkGameState() - if linesCleared == 4: - self.streak += 1 - else: - self.streak = 1 - - self.updateScore(linesCleared) + # def clearLines(self): + # linesCleared = self.board.checkGameState() + # if linesCleared == 4: + # self.streak += 1 + # else: + # self.streak = 1 + def updateScore(self, linesCleared): self.score += self.streak*(baseScore**linesCleared) @@ -64,6 +72,9 @@ def placePiece(self, direction): self.next_piece = self.nextPiece() if self.isGameOver(): self.stopGame() + linesCleared = self.board.checkGameState() + if linesCleared: + self.updateScore(linesCleared) def stopGame(self): From de45750d4ef865525e3637821e9011e8428ba867 Mon Sep 17 00:00:00 2001 From: Eduard Prokhorikhin Date: Mon, 11 Mar 2024 11:30:45 +0100 Subject: [PATCH 04/10] chore: removed devcontainer settup to prepeare for venv --- .devcontainer/devcontainer.json | 41 --------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 9af928d..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,41 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/python -{ - "name": "Python 3", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye", - "settings": { - "terminal.integrated.shell.linux": "/bin/bash" - }, - // Add the IDs of extensions you want installed when the container is created. - "customizations": { - "vscode": { - "extensions": [ - "streetsidesoftware.code-spell-checker", - "ms-azuretools.vscode-docker", - "DavidAnson.vscode-markdownlint", - "esbenp.prettier-vscode", - "ms-python.python", - "ms-python.vscode-pylance", - "ms-python.debugpy" - ] - } - }, - // install the pip packages on container creation - "postCreateCommand": "pip3 install --user -r requirements.txt", - - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "pip3 install --user -r requirements.txt", - - // Configure tool-specific properties. - // "customizations": {}, - - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" -} From 2a23a97e4201d3985de90d8a44e477d2d204f5d6 Mon Sep 17 00:00:00 2001 From: Eduard Prokhorikhin Date: Mon, 11 Mar 2024 11:31:33 +0100 Subject: [PATCH 05/10] docs: updated the environment settup docs to include venv --- docs/guide/{env.md => devContainer.md} | 0 docs/guide/venv.md | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+) rename docs/guide/{env.md => devContainer.md} (100%) create mode 100644 docs/guide/venv.md diff --git a/docs/guide/env.md b/docs/guide/devContainer.md similarity index 100% rename from docs/guide/env.md rename to docs/guide/devContainer.md diff --git a/docs/guide/venv.md b/docs/guide/venv.md new file mode 100644 index 0000000..3689853 --- /dev/null +++ b/docs/guide/venv.md @@ -0,0 +1,25 @@ +# Development Environment + +We will be utilizing a virtual environment to develop the project. This will allow us to have a consistent development environment across all developers.In this case we will be using `venv` to create the virtual environment. + +## Getting Started + +* Have [Python](https://www.python.org/downloads/) installed + * Verify that python is installed by running `python --version` +* Pip install the virtual environment package + * Verify that pip is installed by running `pip --version` + * Install the virtual environment package by running `pip install virtualenv` +* In the root of the project, create a virtual environment by running `python -m venv .venv` +* Activate the virtual environment + * On Windows, run `.venv\Scripts\activate` + * On Mac/Linux, run `source .venv/bin/activate` +* Done! You should now have a fully functional development environment +* To deactivate the virtual environment, run `deactivate` + +## Dependencies +Once you have entered venv you need to make sure the dependencies are installed by running `pip install -r requirements.txt`. +If you use a new pip dependency, make sure to add it to the `requirements.txt` file. This can be done by running: +```bash +pip freeze > requirements.txt +``` +after you pip installed it locally, and then committing the changes. From bb237eaf83d9a8634f3b041d11f7456c5f2e8428 Mon Sep 17 00:00:00 2001 From: Eduard Prokhorikhin Date: Mon, 11 Mar 2024 11:57:40 +0100 Subject: [PATCH 06/10] docs: Added planning folder and plan for upcoming work night --- docs/planning/12.03.2024.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/planning/12.03.2024.md diff --git a/docs/planning/12.03.2024.md b/docs/planning/12.03.2024.md new file mode 100644 index 0000000..6884f3a --- /dev/null +++ b/docs/planning/12.03.2024.md @@ -0,0 +1,14 @@ +# Cogito work night nr. 3 + +## Agenda + +- Venv +- [Mer klarere plan for Tetris](#tetris) +- Progge +- Hva skjer neste uke? + + +## Tetris +- **Headless:** ingen grafikk ting skjer sekvensielt. En viss boardstate og en ny block -> velger presist hvor den skal plasseres (blant mulige plasser) uten tidsbegrensning. + For development purpuses har vi en to print outs av brettet. Første viser brettet med den uplasserte blokken (øverst i midten), andre viser brettet etter at blokken er plassert. Bruker de objektene som vi har blitt enige om. Tanken er at vi kan bruke dette til å teste ut forskjellige algoritmer for å plassere blokken (ai/algorytme velger posisjonen). +- **Grafisk:** pygame. Adapsjon av samme objekter som headless bare at vi nå styrer hvor blokken skal plasseres dynamisk. Blokken faller nedover med en viss hastighet og vi kan flytte den rundt med en viss hastighet (feks. et tastetrykk = forflytter blokken en rute). For å la agenten spille må vi lage et oversettelses lag mellom headless og grafisk, hvor vi kan sende input til grafisk for å manuvrere blokken til samme posisjon som headless ville plassert den. \ No newline at end of file From 696c4703cf028e9774f7718736266ae7785d36cd Mon Sep 17 00:00:00 2001 From: Jon Bergland Date: Tue, 12 Mar 2024 19:01:00 +0100 Subject: [PATCH 07/10] build: add new dependency to requirements.txt --- requirements.txt | 121 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index 3fd17da..12091fb 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,121 @@ +anyio==4.0.0 +appdirs==1.4.4 +argon2-cffi==23.1.0 +argon2-cffi-bindings==21.2.0 +arrow==1.3.0 +asttokens==2.4.0 +async-lru==2.0.4 +attrs==23.1.0 +Babel==2.13.0 +backcall==0.2.0 +beautifulsoup4==4.12.2 +bleach==6.1.0 +certifi==2023.7.22 +cffi==1.16.0 +charset-normalizer==3.3.1 +click==8.1.7 +cloudpickle==3.0.0 +colorama==0.4.6 +comm==0.1.4 +contourpy==1.2.0 +cycler==0.12.1 +debugpy==1.8.0 +decorator==5.1.1 +defusedxml==0.7.1 +docker-pycreds==0.4.0 +executing==2.0.0 +Farama-Notifications==0.0.4 +fastjsonschema==2.18.1 +fonttools==4.44.0 +fqdn==1.5.1 gitdb==4.0.11 GitPython==3.1.41 -iniconfig==2.0.0 +gymnasium==0.29.1 +idna==3.4 +ipykernel==6.25.2 +ipympl==0.9.3 +ipython==8.16.1 +ipython-genutils==0.2.0 +ipywidgets==8.1.1 +isoduration==20.11.0 +jedi==0.19.1 +Jinja2==3.1.2 +json5==0.9.14 +jsonpointer==2.4 +jsonschema==4.19.1 +jsonschema-specifications==2023.7.1 +jupyter-events==0.8.0 +jupyter-lsp==2.2.0 +jupyter_client==8.4.0 +jupyter_core==5.4.0 +jupyter_server==2.8.0 +jupyter_server_terminals==0.4.4 +jupyterlab==4.0.7 +jupyterlab-pygments==0.2.2 +jupyterlab-widgets==3.0.9 +jupyterlab_server==2.25.0 +kiwisolver==1.4.5 +MarkupSafe==2.1.3 +matplotlib==3.8.1 +matplotlib-inline==0.1.6 +mistune==3.0.2 +nbclient==0.8.0 +nbconvert==7.9.2 +nbformat==5.9.2 +nest-asyncio==1.5.8 +notebook==7.0.6 +notebook_shim==0.2.3 +numpy==1.26.2 +overrides==7.4.0 packaging==23.2 -pluggy==1.4.0 +pandas==2.1.3 +pandocfilters==1.5.0 +parso==0.8.3 +pickleshare==0.7.5 +Pillow==10.1.0 +platformdirs==3.11.0 +prometheus-client==0.17.1 +prompt-toolkit==3.0.39 +protobuf==4.25.2 +psutil==5.9.6 +pure-eval==0.2.2 +pybricks==3.2.0 +pycparser==2.21 pygame==2.5.2 -pytest==8.0.2 -setuptools==69.0.3 +Pygments==2.16.1 +pyparsing==3.1.1 +python-dateutil==2.8.2 +python-json-logger==2.0.7 +pytz==2023.3.post1 +pywin32==306 +pywinpty==2.0.12 +PyYAML==6.0.1 +pyzmq==25.1.1 +referencing==0.30.2 +requests==2.31.0 +rfc3339-validator==0.1.4 +rfc3986-validator==0.1.1 +rpds-py==0.10.6 +Send2Trash==1.8.2 +sentry-sdk==1.40.4 +setproctitle==1.3.3 +six==1.16.0 smmap==5.0.1 -wheel==0.42.0 +sniffio==1.3.0 +soupsieve==2.5 +stack-data==0.6.3 +terminado==0.17.1 +tinycss2==1.2.1 +tornado==6.3.3 +traitlets==5.11.2 +types-python-dateutil==2.8.19.14 +typing_extensions==4.9.0 +tzdata==2023.3 +uri-template==1.3.0 +urllib3==2.0.7 +wandb==0.16.3 +wcwidth==0.2.8 +webcolors==1.13 +webencodings==0.5.1 +websocket-client==1.6.4 +widgetsnbextension==4.0.9 From f674ce7fdc3356508bacfd5cc88c4e8b4c329123 Mon Sep 17 00:00:00 2001 From: Jon Bergland Date: Tue, 12 Mar 2024 19:24:20 +0100 Subject: [PATCH 08/10] build: add pynput to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 12091fb..9c317bd 100755 --- a/requirements.txt +++ b/requirements.txt @@ -83,6 +83,7 @@ pybricks==3.2.0 pycparser==2.21 pygame==2.5.2 Pygments==2.16.1 +pynput==1.7.6 pyparsing==3.1.1 python-dateutil==2.8.2 python-json-logger==2.0.7 From 4604ad124994de5a5d3f00b7b58f78032b72e690 Mon Sep 17 00:00:00 2001 From: Jon Bergland Date: Tue, 12 Mar 2024 20:00:08 +0100 Subject: [PATCH 09/10] feat: add functionality for actions, hardDrop and softDrop --- src/game/TetrisGameManager.py | 87 ++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/src/game/TetrisGameManager.py b/src/game/TetrisGameManager.py index 7d5a463..0c846a8 100644 --- a/src/game/TetrisGameManager.py +++ b/src/game/TetrisGameManager.py @@ -1,4 +1,4 @@ -import keyboard as kb +from pynput.keyboard import Key, Listener import time as t baseScore = 100 @@ -22,10 +22,26 @@ class TetrisGameManager: score = 0 updateTimer = 1 streak = 1 + currentTime = None def __init__(self, board): self.board = board self.score = 0 + self.currentTime = int(round(t.time() * 1000)) + + # while True: + # with Listener(on_press=self.on_press, on_release=self.on_release) as listener: + # listener.join() + + + def onPress(self, key): + switcher = { + + } + + def onRelease(self, key): + pass + def rotatePiece(self, direction): self.currentPiece.rotate(direction) @@ -45,6 +61,33 @@ def isGameOver(self): def startGame(self): self.currentPiece = self.newPiece() self.nextPiece = self.newPiece() + + while not self.isGameOver(): + action = input("Enter action: ") ## valid commands: [moveLeft, moveRight, moveDown, softDrop, hardDrop, quitGame, rotateLeft, rotateRight, rotate180] + if action == "moveLeft" and self.legalMove(LEFT): + self.movePiece(LEFT) + elif action == "moveRight" and self.legalMove(RIGHT): + self.movePiece(RIGHT) + elif action == "moveDown" and self.legalMove(DOWN): + self.dropPiece(DOWN) + elif action == "softDrop": + self.softDrop() + elif action == "h": + self.hardDrop() + elif action == "rotateLeft": + self.rotatePiece(-1) + elif action == "rotateRight": + self.rotatePiece(1) + elif action == "rotate180": + self.rotatePiece(2) + elif action == "q": + self.stopGame() + break + else: + self.moveDown() + + + def newPiece(self): return self.pieces.getNewPiece() @@ -63,19 +106,51 @@ def legalMove(self, x, y): def updateScore(self, linesCleared): self.score += self.streak*(baseScore**linesCleared) + def softDrop(self): + if self.legalMove(DOWN): + self.dropPiece() + else: + self.placePiece(DOWN) + + def hardDrop(self): + while self.legalMove(DOWN): + self.dropPiece() + self.placePiece(DOWN) + def placePiece(self, direction): x = direction[0] y = direction[1] - if self.legalMove(x, y): + if not self.legalMove(x, y): self.board.placePiece(x, y, self.currentPiece) self.currentPiece = self.nextPiece self.next_piece = self.nextPiece() + else: + self.movePiece(DOWN) + return False if self.isGameOver(): self.stopGame() - linesCleared = self.board.checkGameState() - if linesCleared: - self.updateScore(linesCleared) + return True + clearLines = self.board.checkGameState() + if clearLines: + self.board.clearLines(clearLines) + self.updateScore(clearLines) + return True + + def checkTimer(self): + checkTime = self.currentTime + 1000 + newTime = int(round(t.time() * 1000)) + if (checkTime > newTime): + #TODO Implement functionality + pass + + + return True def stopGame(self): - self.board.stop_game() \ No newline at end of file + self.board.stop_game() + + + if __name__ == "__main__": + millisec = int(round(t.time() * 1000)) + print(millisec) \ No newline at end of file From 6c304e81bc99ca2f99b1fa2a7556af0d2f92f319 Mon Sep 17 00:00:00 2001 From: Jon Bergland Date: Tue, 19 Mar 2024 17:06:35 +0100 Subject: [PATCH 10/10] feat: implement checkTimer-method --- src/game/TetrisGameManager.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/game/TetrisGameManager.py b/src/game/TetrisGameManager.py index 0c846a8..8588a34 100644 --- a/src/game/TetrisGameManager.py +++ b/src/game/TetrisGameManager.py @@ -141,8 +141,7 @@ def checkTimer(self): checkTime = self.currentTime + 1000 newTime = int(round(t.time() * 1000)) if (checkTime > newTime): - #TODO Implement functionality - pass + self.movePiece(DOWN) return True