tictactoe in python

This commit is contained in:
nessar committed 2023-03-18 01:51:02 +01:00
1 parent 2180697c56
commit 29edc46339
11 files changed
+422

No files matched your search

+35
View File
@@ -0,0 +1,35 @@
name: Python
on:
push:
paths:
- "python/**"
- "**/python.yml"
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
PYTHONPATH=src pytest
+4
View File
@@ -0,0 +1,4 @@
__pycache__
.pytest_cache
.venv
.vscode
+29
View File
@@ -0,0 +1,29 @@
# TicTacToe in Python 🐍
## Time spent
- Total : 9 hrs 45 mins
- `tictactoe.py` : 53 mins (transformed in Grid, Case and const later)
- `test_tictactoe.py` : 45 mins
- `CLI.py` : 24 mins
- `GLI.py` : 16 mins
- `python.yml` : 12 mins
- `requirements.txt` : 2 min
## Dependencies
```bash
sudo apt install python3 python3-pip
pip install -r requirements.txt
```
## CLI
```bash
src/CLI.py
```
## Graphical Interface
```bash
src/GUI.py
```
+1
View File
@@ -0,0 +1 @@
pygame
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
from tictactoe import Grid
def main():
game = Grid(3)
outcome = game.outCome()
while outcome == "playing":
print(str(game))
playerInput = input(game.whoIsPlaying() + " to play: ")
if playerInput == "exit":
break
try:
x = int(playerInput[0])
y = int(playerInput[2])
if not game.play(x, y):
print("Invalid move")
except:
print("Invalid move")
outcome = game.outCome()
print(str(game))
if outcome == "draw":
print("Draw 😞\n")
else:
print("Circle wins 🎉\n")
if __name__ == "__main__":
main()
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
import pygame
from tictactoe import Grid
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
SIZE = 3
game = Grid(SIZE)
# pygame setup
pygame.init()
screen = pygame.display.set_mode((SIZE * 200, SIZE * 200))
pygame.display.set_caption("Tic Tac Toe in Python")
clock = pygame.time.Clock()
running = True
while running:
outcome = game.outCome()
# poll for events
# pygame.QUIT event means the user clicked X to close your window
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN and outcome == "playing":
x, y = pygame.mouse.get_pos()
game.play(x // 200, y // 200)
# RENDER YOUR GAME HERE
screen.fill(WHITE)
for cList in game.grid:
for c in cList:
pygame.draw.rect(screen, BLACK, (c.x * 200, c.y * 200, 200, 200), 1)
if c.what() == "circle":
pygame.draw.circle(screen, RED, (c.x * 200 + 100, c.y * 200 + 100), 80)
elif c.what() == "cross":
pygame.draw.line(screen, RED, (c.x * 200 + 20, c.y * 200 + 20), (c.x * 200 + 180, c.y * 200 + 180), 10)
pygame.draw.line(screen, RED, (c.x * 200 + 180, c.y * 200 + 20), (c.x * 200 + 20, c.y * 200 + 180), 10)
if c.isOnWinLine:
pygame.draw.rect(screen, GREEN, (c.x * 200, c.y * 200, 200, 200), 10)
# flip() the display to put your work on screen
pygame.display.flip()
clock.tick(60) # limits FPS to 60
pygame.quit()
+20
View File
@@ -0,0 +1,20 @@
from .const import CASECONTENT
class Case:
def __init__(self, char, x, y):
self.char = char
self.x = x
self.y = y
self.isOnWinLine = False
def what(self):
for key, value in CASECONTENT.items():
if self.char == value:
return key
def __str__(self):
if self.isOnWinLine:
return "-" + self.char + "-"
return " " + self.char + " "
+71
View File
@@ -0,0 +1,71 @@
from .Case import Case
from .const import CASECONTENT, DIRECTIONS
class Grid:
def __init__(self, size):
self.size = size
self.grid = [[Case(CASECONTENT["empty"], x, y) for x in range(size)] for y in range(size)]
self.turn = 1
def whoIsPlaying(self):
return list(CASECONTENT.keys())[self.turn % 2]
def __str__(self):
ret = ""
for _ in range(self.size):
ret += "-------"
ret += "-\n"
for y in range(self.size):
ret += "|"
for x in range(self.size):
ret += str(x) + str(self.grid[x][y]) + str(y)
if x != self.size - 1:
ret += "|"
ret += "|\n"
for _ in range(self.size):
ret += "-------"
ret += "-\n"
return ret
def getCaseDir(self, case: Case, dir):
retX = case.x + dir[0]
retY = case.y + dir[1]
if retX < 0 or retX >= self.size or retY < 0 or retY >= self.size:
return None
return self.grid[retX][retY]
def nbCaseEmpty(self):
ret = 0
for cList in self.grid:
for c in cList:
if c.what() == "empty":
ret += 1
return ret
def outCome(self):
if self.nbCaseEmpty() == 0:
return "draw"
for cList in self.grid:
for c in cList:
for dir in DIRECTIONS:
case1 = self.getCaseDir(c, DIRECTIONS[dir])
if case1 is None:
continue
case2 = self.getCaseDir(case1, DIRECTIONS[dir])
if case2 is None:
continue
if (c.what() == case1.what()) and (c.what() == case2.what()) and (c.what() != "empty"):
c.isOnWinLine = True
case1.isOnWinLine = True
case2.isOnWinLine = True
return c.what()
return "playing"
def play(self, x, y):
if self.grid[x][y].what() == "empty":
self.grid[x][y] = Case(list(CASECONTENT.values())[self.turn % 2], x, y)
self.turn += 1
return True
return False
+3
View File
@@ -0,0 +1,3 @@
from .Grid import Grid
from .Case import Case
from .const import *
+2
View File
@@ -0,0 +1,2 @@
CASECONTENT = {"cross": "❌", "circle": "⭕️", "empty": " "}
DIRECTIONS = {"up": [0, 1], "down": [0, -1], "left": [-1, 0], "right": [1, 0], "upLeft": [-1, 1], "upRight": [1, 1], "downLeft": [-1, -1], "downRight": [1, -1]}
+173
View File
@@ -0,0 +1,173 @@
from tictactoe import *
def testCase():
case = Case(CASECONTENT["empty"], 0, 0)
assert case.what() == "empty"
assert case.x == 0
assert case.y == 0
assert case.isOnWinLine == False
case = Case(CASECONTENT["circle"], 1, 2)
assert case.what() == "circle"
assert case.x == 1
assert case.y == 2
assert case.isOnWinLine == False
case = Case(CASECONTENT["cross"], 2, 1)
assert case.what() == "cross"
assert case.x == 2
assert case.y == 1
assert case.isOnWinLine == False
print("testCase passed")
def testGrid():
game = Grid(3)
assert game.size == 3
assert game.turn == 1
assert game.grid[0][0].what() == "empty"
assert game.grid[0][0].x == 0
assert game.grid[0][0].y == 0
assert game.grid[0][0].isOnWinLine == False
assert game.grid[1][1].what() == "empty"
assert game.grid[1][1].x == 1
assert game.grid[1][1].y == 1
assert game.grid[1][1].isOnWinLine == False
assert game.grid[2][2].what() == "empty"
assert game.grid[2][2].x == 2
assert game.grid[2][2].y == 2
assert game.grid[2][2].isOnWinLine == False
print("testGrid passed")
def testGridStr():
game = Grid(3)
assert str(
game
) == "----------------------\n|0 0|1 0|2 0|\n----------------------\n|0 1|1 1|2 1|\n----------------------\n|0 2|1 2|2 2|\n----------------------\n"
print("testGridStr passed")
def testGridBehavour():
# testing vertical line win
game = Grid(3)
assert game.grid[0][0].what() == "empty"
assert game.whoIsPlaying() == "circle"
assert game.play(0, 0) == True
assert game.play(0, 0) == False
assert game.grid[0][0].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(1, 1) == True
assert game.play(1, 1) == False
assert game.grid[1][1].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.play(2, 2) == True
assert game.play(2, 2) == False
assert game.grid[2][2].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(1, 0) == True
assert game.play(1, 0) == False
assert game.grid[1][0].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.play(0, 2) == True
assert game.play(0, 2) == False
assert game.grid[0][2].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(1, 2) == True
assert game.play(1, 2) == False
assert game.grid[1][2].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.outCome() == "cross"
print("vertical line win passed")
# testing digonal win
game = Grid(3)
assert game.grid[0][0].what() == "empty"
assert game.whoIsPlaying() == "circle"
assert game.play(0, 0) == True
assert game.play(0, 0) == False
assert game.grid[0][0].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(0, 1) == True
assert game.play(0, 1) == False
assert game.grid[0][1].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.play(1, 1) == True
assert game.play(1, 1) == False
assert game.grid[1][1].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(0, 2) == True
assert game.play(0, 2) == False
assert game.grid[0][2].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.play(2, 2) == True
assert game.play(2, 2) == False
assert game.grid[2][2].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.outCome() == "circle"
print("diagonal win passed")
# testing horizontal line win
game = Grid(3)
assert game.grid[0][0].what() == "empty"
assert game.whoIsPlaying() == "circle"
assert game.play(0, 0) == True
assert game.play(0, 0) == False
assert game.grid[0][0].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(0, 1) == True
assert game.play(0, 1) == False
assert game.grid[0][1].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.play(1, 0) == True
assert game.play(1, 0) == False
assert game.grid[1][0].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(1, 1) == True
assert game.play(1, 1) == False
assert game.grid[1][1].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.play(2, 0) == True
assert game.play(2, 0) == False
assert game.grid[2][0].what() == "circle"
assert game.outCome() == "circle"
print("horizontal line win passed")
# testing draw
game = Grid(3)
assert game.grid[0][0].what() == "empty"
assert game.whoIsPlaying() == "circle"
assert game.play(0, 0) == True
assert game.play(0, 0) == False
assert game.grid[0][0].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(0, 1) == True
assert game.play(0, 1) == False
assert game.grid[0][1].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.play(0, 2) == True
assert game.play(0, 2) == False
assert game.grid[0][2].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(1, 0) == True
assert game.play(1, 0) == False
assert game.grid[1][0].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.play(1, 1) == True
assert game.play(1, 1) == False
assert game.grid[1][1].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(1, 2) == True
assert game.play(1, 2) == False
assert game.grid[1][2].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.play(2, 0) == True
assert game.play(2, 0) == False
assert game.grid[2][0].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.play(2, 1) == True
assert game.play(2, 1) == False
assert game.grid[2][1].what() == "cross"
assert game.whoIsPlaying() == "circle"
assert game.play(2, 2) == True
assert game.play(2, 2) == False
assert game.grid[2][2].what() == "circle"
assert game.whoIsPlaying() == "cross"
assert game.outCome() == "draw"
print("draw passed")