diff --git a/MVC/__pycache__/minimax.cpython-310.pyc b/MVC/__pycache__/minimax.cpython-310.pyc new file mode 100644 index 0000000..9901c13 Binary files /dev/null and b/MVC/__pycache__/minimax.cpython-310.pyc differ diff --git a/MVC/__pycache__/model.cpython-310.pyc b/MVC/__pycache__/model.cpython-310.pyc new file mode 100644 index 0000000..0d6aeed Binary files /dev/null and b/MVC/__pycache__/model.cpython-310.pyc differ diff --git a/MVC/__pycache__/playerhandler.cpython-310.pyc b/MVC/__pycache__/playerhandler.cpython-310.pyc new file mode 100644 index 0000000..f704828 Binary files /dev/null and b/MVC/__pycache__/playerhandler.cpython-310.pyc differ diff --git a/MVC/__pycache__/printer.cpython-310.pyc b/MVC/__pycache__/printer.cpython-310.pyc new file mode 100644 index 0000000..b780bf8 Binary files /dev/null and b/MVC/__pycache__/printer.cpython-310.pyc differ diff --git a/MVC/__pycache__/savestate.cpython-310.pyc b/MVC/__pycache__/savestate.cpython-310.pyc new file mode 100644 index 0000000..f8d9b16 Binary files /dev/null and b/MVC/__pycache__/savestate.cpython-310.pyc differ diff --git a/MVC/__pycache__/tictactoe.cpython-310.pyc b/MVC/__pycache__/tictactoe.cpython-310.pyc new file mode 100644 index 0000000..1ae6d07 Binary files /dev/null and b/MVC/__pycache__/tictactoe.cpython-310.pyc differ diff --git a/MVC/main.py b/MVC/main.py new file mode 100644 index 0000000..189b3c1 --- /dev/null +++ b/MVC/main.py @@ -0,0 +1,3 @@ +import tictactoe +newGame = tictactoe.Tictactoe() +newGame.main() \ No newline at end of file diff --git a/MVC/minimax.py b/MVC/minimax.py new file mode 100644 index 0000000..ec7893c --- /dev/null +++ b/MVC/minimax.py @@ -0,0 +1,69 @@ +import tictactoe +import random + + +class Minimax: + + def minimax(self, current_field, is_maximizing, player1_char, player2_char): + checkwin = self.check_win(current_field, player1_char, player2_char) + if checkwin == (1, 1): # Draw + return 0, 0, 0 + if checkwin == (1, 0): # Player wins + return -1, 0, 0 + if checkwin == (0, 1): # AI wins + return 1, 0, 0 + + best_score = float('-inf') if is_maximizing else float('inf') + best_move = None + + for j in range(0, len(current_field), 2): + for k in range(0, len(current_field), 2): + if current_field[j][k] == " ": + current_field[j][k] = player1_char if not is_maximizing else player2_char + score = self.minimax(current_field, not is_maximizing, player1_char, player2_char)[0] + current_field[j][k] = " " + + if is_maximizing and score > best_score: + best_score = score + best_move = j, k + elif not is_maximizing and score < best_score: + best_score = score + best_move = j, k + + if best_score == 0 and best_move == (0, 0): # is None: + empty_cells = [(j, k) for j in range(0, len(current_field), 2) for k in range(0, len(current_field), 2) if + current_field[j][k] == " "] + random.seed() + random_move = random.choice(empty_cells) + return 0, random_move[0], random_move[1] + else: + if best_move is None: + return 0, -1, -1 # No available moves + else: + # print('The next best move is:', best_move, "score: ", best_score) + return best_score, best_move[1], best_move[0] + + def check_win(self, ifield, player1_char, player2_char): + # nothing 0, 0; draw 1, 1; win player1 1, 0; win player2 0, 1 + for j in range(0, len(ifield), 2): + if ifield[j][0] == ifield[j][2] == ifield[j][4] == player1_char: + return 1, 0 + elif ifield[j][0] == ifield[j][2] == ifield[j][4] == player2_char: + return 0, 1 + elif ifield[0][j] == ifield[2][j] == ifield[4][j] == player1_char: + return 1, 0 + elif ifield[0][j] == ifield[2][j] == ifield[4][j] == player2_char: + return 0, 1 + + if ifield[0][0] == ifield[2][2] == ifield[4][4] == player1_char: + return 1, 0 + elif ifield[0][0] == ifield[2][2] == ifield[4][4] == player2_char: + return 0, 1 + elif ifield[0][4] == ifield[2][2] == ifield[4][0] == player1_char: + return 1, 0 + elif ifield[0][4] == ifield[2][2] == ifield[4][0] == player2_char: + return 0, 1 + elif all(ifield[j][k] != " " for j in range(len(ifield)) for k in range(len(ifield))): + return 1, 1 + else: + return 0, 0 diff --git a/MVC/model.py b/MVC/model.py new file mode 100644 index 0000000..c9b6a3c --- /dev/null +++ b/MVC/model.py @@ -0,0 +1,59 @@ +import os.path +if os.path.isfile("./savestate.py"): + from savestate import save + +class Model: + field = None + def __init__(self): + self.field = [[" ", "|", " ", "|", " "], + ["—", "+", "—", "+", "—"], + [" ", "|", " ", "|", " "], + ["—", "+", "—", "+", "—"], + [" ", "|", " ", "|", " "]] + + + + def do_move(self, x, y, player1, player1_char, player2_char): + self.field[y*2][x*2] = (player1_char if player1 else player2_char) + # printer() + # win = check_win(field) + # if win == (0, 0): + # savetosavestate + """player1 = not player1 + turn() controller""" + '''elif win == (1, 1): + elif win == (1, 0): + elif win == (0, 1): + ''' + + def loadsavestate(self): + if os.path.isfile('./savestate.py'): + from savestate import save + self.field = save + + def checksavestate(self): + if os.path.isfile('./savestate.py'): + return True + return False + + def savetosavestate(self): + f = open("savestate.py", "w") + f.write("save = " + repr(self.field)) + f.close() + + def deletesavestate(self): + os.remove("savestate.py") + + + def check_move(self, x, y, verbose): + + x = int(x * 2) + y = int(y * 2) + if not self.field[y][x] == " ": + if verbose: + # self.printer.occupied() + return False + else: + return True + # else: + # do_move(x, y) diff --git a/MVC/playerhandler.py b/MVC/playerhandler.py new file mode 100644 index 0000000..2440468 --- /dev/null +++ b/MVC/playerhandler.py @@ -0,0 +1,16 @@ +class Playerhandler: + + player1 = None # bool that states which player is currently playing + player1_char = None + player2_char = None + ai = None + + + def __init__(self): + self.player1 = True # bool that states which player is currently playing + self.player1_char = "X" + self.player2_char = "O" + self.ai = False + ''' + def getPlayer(self): + return''' \ No newline at end of file diff --git a/MVC/printer.py b/MVC/printer.py new file mode 100644 index 0000000..54e1c33 --- /dev/null +++ b/MVC/printer.py @@ -0,0 +1,84 @@ +# Das hier ist die View + +class Printer: + def printfield(self, ifield): # function that prints the field + print(" 0 1 2", end="\n") + for j in range(0, len(ifield)): + print("0" if j == 0 else "1" if j == 2 else "2" if j == 4 else " ", end=" ") + for k in range(0, len(ifield)): + print(str(ifield[j][k]), end=" ") + print("\n", end="") + + + def occupied(self): + print("Your given coordinates are already occupied. \nPlease Try again.\n") + + def aicalc(self): + print("Next move is being calculated...") + + def aimoved(self, best_move): + print("AI moved to ", best_move[1] // 2, best_move[2] // 2) + + def playermove(self, player1, player1_char, player2_char): + while True: + + + next_move_x = int(input( + f"Player {1 if player1 else 2} ({player1_char if player1 else player2_char}), please choose the x (" + f"horizontal) coordinates of your next move: ")) + if next_move_x in list(range(3)): + break + else: + print("Please be sure to input a valid number (0-2). \nPlease try Again.") + + while True: + next_move_y = int(input( + f"Player {1 if player1 else 2} ({player1_char if player1 else player2_char}), please choose the y (" + f"vertical) coordinates of your next move: ")) + if next_move_y in list(range(3)): + break + else: + print("Please be sure to input a valid number (0-2). \nPlease try Again.") + + next_move = (next_move_x, next_move_y) + return next_move + + def welcomemessage(self): + print("Welcome to Kat&Paul's TicTacToe:") + + def checksavestate(self): + return input("An older savestate has been found. Do you want to continue it? (y/n): ") + + def invalidsavestate(self): + return input("That was not a valid input. Type y/n if you want to continue or not: ") + + def checkai(self): + inp = input("Do you want to play against AI or local multiplayer? 1/2: ") + + + while True: + if inp == "1": + return 1 + break + elif inp == "2": + return 2 + break + return 3 + + def invalidai(self): + return input("That was not a valid input. Type 1/2 if you want to play against AI or local multiplayer: ") + + def startsplaying(self, player1, player1_char, player2_char): + print(f"Player {1 if player1 else 2} ({player1_char if player1 else player2_char}) will start playing.") + + + def endmessage(self,i, j, ai): + if i == 1 and j == 1: + print("Its a draw.") + if i == 1 and j == 0: + print("Player 1 won.") + if i == 0 and j == 1 and ai: + print("AI won.") + if i == 0 and j == 1 and not ai: + print("Player 2 won.") + diff --git a/MVC/tictactoe.py b/MVC/tictactoe.py new file mode 100644 index 0000000..541d365 --- /dev/null +++ b/MVC/tictactoe.py @@ -0,0 +1,126 @@ +import os.path +import random +import printer +import playerhandler +import model +import minimax + + +class Tictactoe: + printer = None + playerhandler = None + minimax = None + model = None + def __init__(self): + self.printer = printer.Printer() + self.playerhandler = playerhandler.Playerhandler() + self.minimax = minimax.Minimax() + self.model = model.Model() + + def turn(self): # function that checks whose turn it is and where they can place their symbol + self.printer.printfield(self.model.field) + if self.playerhandler.ai and not self.playerhandler.player1: + self.printer.aicalc() + best_move = self.minimax.minimax(self.model.field, not self.playerhandler.player1, self.playerhandler.player1_char, self.playerhandler.player2_char) + self.printer.aimoved(best_move) + self.model.do_move(best_move[1]//2, best_move[2]//2, self.playerhandler.player1, self.playerhandler.player1_char, + self.playerhandler.player2_char) + # self.printer.printfield(self.model.field) + + + else: + while True: + nextmove = self.printer.playermove(self.playerhandler.player1, self.playerhandler.player1_char, + self.playerhandler.player2_char) + next_move_x, next_move_y = nextmove + # return self.model.check_move(next_move_x, next_move_y, True) + + if self.model.check_move(next_move_x, next_move_y, True): + self.model.do_move(next_move_x, next_move_y, self.playerhandler.player1, self.playerhandler.player1_char, self.playerhandler.player2_char) + break + # self.playerhandler.player1 = not self.playerhandler.player1 + else: + self.printer.occupied() + self.printer.printfield(self.model.field) + + win = self.check_win(self.model.field, self.playerhandler.player1_char, self.playerhandler.player2_char) + if win == (0, 0): + self.model.savetosavestate() + self.playerhandler.player1 = not self.playerhandler.player1 + self.turn() + elif win == (1, 1): + self.model.deletesavestate() + elif win == (1, 0): + self.model.deletesavestate() + elif win == (0, 1): + self.model.deletesavestate() + self.printer.endmessage(win[0], win[1], self.playerhandler.ai) + self.turn() + + + def check_win(self, ifield, player1_char, player2_char): + # nothing 0, 0; draw 1, 1; win player1 1, 0; win player2 0, 1 + for j in range(0, len(ifield), 2): + if ifield[j][0] == ifield[j][2] == ifield[j][4] == player1_char: + return 1, 0 + elif ifield[j][0] == ifield[j][2] == ifield[j][4] == player2_char: + return 0, 1 + elif ifield[0][j] == ifield[2][j] == ifield[4][j] == player1_char: + return 1, 0 + elif ifield[0][j] == ifield[2][j] == ifield[4][j] == player2_char: + return 0, 1 + + if ifield[0][0] == ifield[2][2] == ifield[4][4] == player1_char: + return 1, 0 + elif ifield[0][0] == ifield[2][2] == ifield[4][4] == player2_char: + return 0, 1 + elif ifield[0][4] == ifield[2][2] == ifield[4][0] == player1_char: + return 1, 0 + elif ifield[0][4] == ifield[2][2] == ifield[4][0] == player2_char: + return 0, 1 + elif all(ifield[j][k] != " " for j in range(len(ifield)) for k in range(len(ifield))): + return 1, 1 + else: + return 0, 0 + + # verbose = True + + def main(self): + inp = None + self.printer.welcomemessage() + if self.model.checksavestate(): + inp = self.printer.checksavestate() + while True: + if inp == "n": + break + + if inp == "y": + self.model.loadsavestate()# self.tictactoe.checksavestateplayer() + spacecount = 0 + for j in range(0, len(self.model.field)): + for k in range(0, len(self.model.field)): + if self.model.field[j][k] == " ": + spacecount += 1 + if spacecount % 2 == 0: + self.playerhandler.player1 = False + break + # self.printer.checkai() + + + # inp = self.printer.invalidsavestate() + + # inp = self.printer.checkai() + while True: + checkai = self.printer.checkai() + if checkai == 1: + self.playerhandler.ai = True + break + elif checkai == 2: + break + elif checkai == 3: + self.printer.invalidai() + + # printer.printfield(self.model.field) + self.printer.startsplaying(self.playerhandler.player1, self.playerhandler.player1_char, + self.playerhandler.player2_char) + self.turn()