Compare commits

..

9 commits
master ... game

Author SHA1 Message Date
Gérald LEBAN
7a10317630 main game 2021-01-31 19:12:41 +01:00
Gérald LEBAN
88ecb3a2e2 Board class 2021-01-31 19:11:47 +01:00
Gérald LEBAN
0442e04eaa Perfect IA 2021-01-31 19:11:27 +01:00
Gérald LEBAN
b951a51d82 Renamed 2021-01-31 19:11:16 +01:00
Gérald LEBAN
65ff0bd56f Randomly choose 1st player
Display playing order
Fix shadowing type function
2021-01-31 11:28:42 +01:00
docjyJ
e7a9b2ff0c commit 2021-01-30 12:42:02 +01:00
Gérald L
6a53ef0852 add utils function + docstring 2021-01-29 17:54:43 +01:00
Gérald L
72d874151c Add game explanation 2021-01-29 17:54:12 +01:00
Gérald L
7f22bdf78d Ignore idea 2021-01-29 17:53:55 +01:00
6 changed files with 283 additions and 0 deletions

3
.gitignore vendored
View file

@ -1,3 +1,6 @@
# Idea
.idea
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/

BIN
marinbad/Marienbad.pdf Normal file

Binary file not shown.

126
marinbad/ai.py Normal file
View file

@ -0,0 +1,126 @@
from random import choice, randint
class AI:
"""Ordinateur pour le jeu de Marienbad"""
def __init__(self):
self.row = 0
self.removed = 0
@staticmethod
def _intToBin(integer):
"""
Convertie un nombre en base 10 en base 2
:param integer: Le nombre à convertir
:type integer: int
:return: int
"""
return int(bin(integer)[2:])
def _calculSomme(self, liste: list):
"""
Convertie une liste de décimal en liste de binaire
Fait la somme des element binaire et la retranscrie en décimal
:param liste: une liste sur laquelle effectuer l'opération
:type liste: list
:return: list
"""
array = [self._intToBin(el) for el in liste] # int array => bin array
S = (list(str(sum(array)))) # Somme en base 2
S = [int(s) for s in S] # str array => int array
return S
@staticmethod
def _sommeNIM(liste: list):
"""
Remplace chaque digit par 0 si le digit est pair, par 1 si le digit est impair
:param liste: une liste sur laquelle effectuer l'opération
:type liste: list
:return: list
"""
array = [str(el % 2) for el in liste]
return array
@staticmethod
def _isSafe(liste: list):
"""
Retourne True si le nombre convertie en binaire vaut zéro.
Retourne False sinon
:param liste: une liste sur laquelle effectuer l'opération
:type liste: list
:return: int
"""
string = ""
for el in liste:
string += str(el)
return int(string, 2) == 0
def randomDraw(self, array):
"""
Retire une allumette d'une pile au hasard
:param array: Allumettes
:type array list
:return: list
"""
rows = [i for i, row in enumerate(array) if row != 0]
row = choice(rows)
removed = randint(1, array[row])
array[row] = array[row] - removed
self.row = row + 1
self.removed = removed
return array
def _positionPerdante(self, array, debug=None):
"""
Wrapper de méthodes
:param array: Allumettes
:type array list
:param debug: Affiche des info pour le debug
:type debug bool
:return: bool
"""
S = self._calculSomme(array)
nimS = self._sommeNIM(S)
safe = self._isSafe(nimS)
if debug:
print("Somme: ", S)
print("NIM S: ", nimS)
print("Safe : ", safe)
return self._isSafe(nimS)
def _trouver_position_perdante(self, array: list):
"""Brut force to find a solution"""
if self._positionPerdante(array):
print("Drawing one")
# Choisi une range au hasard où il reste des allumettes
return self.randomDraw(array)
else:
print("Computing")
# Tant que position pas perdante pour le joueur
while not self._positionPerdante(array):
# Choisi une range au hasard où il reste des allumettes
rows = [i for i, row in enumerate(array) if row > 0]
row = choice(rows)
# Créer une copie pour le brutforce
row_backup = array[row]
removed = 0
# Brutforce sur chaque rangée jusqu'a trouver une combinaison perdante
while not self._positionPerdante(array) and array[row] > 0:
removed += 1
# On retire une allumette
array[row] -= 1
self.row = row + 1
self.removed = removed
self.removed = row_backup - array[row]
if not self._positionPerdante(array):
array[row] = row_backup
return array
def compute(self, liste: list, *args, **kwargs):
"""Method to call"""
board = self._trouver_position_perdante(liste)
print(f"{kwargs['name']}: L{self.row} => {self.removed}")
return board

42
marinbad/board.py Normal file
View file

@ -0,0 +1,42 @@
class Board:
def __init__(self):
pass
@staticmethod
def show_board(board):
"""
Display the board o screen
:param board: the board
:type board list
:return: None
"""
for index, val in enumerate(board):
print(f"Row {index + 1}: {val}")
@staticmethod
def nb_allumettes(board: list):
"""
Return the number of remaining allumettes
:param board: the board
:type board list
:return: int
"""
return sum(board)
@staticmethod
def retirer(board, row, stick):
"""
Computer player move on the board
:param board: the board
:type board list
:param row: the selected row to remove allumettes from
:type row: int
:param stick: the number of allumettes to remove
:type stick: int
:return: board
"""
board[int(row) - 1] = board[int(row) - 1] - int(stick)
return board

79
marinbad/game_numy.py Normal file
View file

@ -0,0 +1,79 @@
from AI import AI
from Board import Board
from os import system
from random import shuffle
def play(board: list, **kwargs):
def strArray(array):
"""
Convert an array to a string array and add one to every value
Used to stringigy range() and start value from 1
:param array:
:return:
"""
return [str(el + 1) for el in array]
def intable(value):
"""
Return True if value can be cast to integer
:param value: The value to convert in integer
:type value str
:return: bool
"""
try:
int(value)
return True
except ValueError:
return False
# Filter row input
row = "string"
strRange = strArray(range(len(board)))
while not(intable(row)) or not(row in strRange):
row = input(f"Choisissez une rangée entre 1 et {len(board)}: ")
row = int(row)
# Filter remove allumettes
remove = "0"
while not(intable(remove)) or not("1" <= remove <= str(board[row - 1])):
remove = input(f"Choisissez le nombre d'allumettes à retirer entre 1 et {board[row - 1]}: ")
remove = int(remove)
print(f"{kwargs['name']}: L{row} => {remove}")
# Return board after player move
return game_board.retirer(board, row, remove)
game_board = Board()
players = [
{
"name": "Jean Yves",
"func": play
},
{
"name": "Gérald",
"func": AI().compute
}
]
# Choisi le 1er joueur
shuffle(players)
# Creation du plateau de jeu
print("Entrez une liste sous cette forme: X Y Z A B C")
allumettes = [int(el) for el in input(">>> ").split(" ")]
print(f"Voici l'ordre des joueurs: {' => '.join([player['name'] for player in players])}")
while True:
for player in players:
game_board.show_board(allumettes)
allumettes = player["func"](allumettes, name=player["name"])
if game_board.nb_allumettes(allumettes) == 0:
print(f"Le {player['name']} à gagné !!")
exit(0)
print("")

33
player.py Normal file
View file

@ -0,0 +1,33 @@
def get_row(rows):
i = 0
while not (i in range(1, rows + 1)):
print(f"Sur quel ligne voulez vous jouer ? (un nombre entre 1..{rows}) :")
try:
i = int(input())
except ValueError:
i = 0
return i - 1
def get_value(values):
i = 0
while not (i in range(1, values + 1)):
print(f"Combien de pièce voulez vous jouer (un nombre entre 1..{values}, c pour annuler) :")
try:
tmp = input()
if tmp == "c":
return 0
else:
i = int(tmp)
except ValueError:
i = 0
return i
def get_player_move(name, game):
print(f"{name} c'est à vous !")
value = 0
while value == 0:
row = get_row(len(game))
value = get_value(game[row])
return row, value