diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..76b9408 --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/jupyternotebooks,macos +# Edit at https://www.toptal.com/developers/gitignore?templates=jupyternotebooks,macos + +### JupyterNotebooks ### +# gitignore template for Jupyter Notebooks +# website: http://jupyter.org/ + +.ipynb_checkpoints +*/.ipynb_checkpoints/* + +# IPython +profile_default/ +ipython_config.py + +# Remove previous ipynb_checkpoints +# git rm -r .ipynb_checkpoints/ + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# End of https://www.toptal.com/developers/gitignore/api/jupyternotebooks,macos \ No newline at end of file diff --git a/your-project/DAFT Presentation Tic_Tac_Toe.key b/your-project/DAFT Presentation Tic_Tac_Toe.key new file mode 100755 index 0000000..6da8528 Binary files /dev/null and b/your-project/DAFT Presentation Tic_Tac_Toe.key differ diff --git a/your-project/README.md b/your-project/README.md index 2a8493d..151716d 100644 --- a/your-project/README.md +++ b/your-project/README.md @@ -1,9 +1,9 @@ Ironhack Logo -# Title of Your Project -*[Your Name]* +# Tic Tac Toe +*Ignacio Rus Prados* -*[Your Cohort, Campus & Date]* +*DAFT-MAR21, Remote, 25/03/2021* ## Content - [Project Description](#project-description) @@ -13,22 +13,45 @@ - [Links](#links) ## Project Description -Write a short description of your project. Write 1-2 sentences about the game you chose to build and why. + +I decided to code my own version of the well-known Tic Tac Toe game. It provides a visual representation of the board and it is interactive, challenging the player to beat the computer (SPOILER ALERT: it's impossible). I chose this game because I thought it would be challenging to find a way to code the game rules, and even harder to code the AI without specifying every possible move. ## Rules -Briefly describe the rules of the game. + +Tic Tac Toe challenges two players to beat each other by placing, one at a time and switching turns, noughts and crosses in a 3x3 board. The player who succeeds in placing three of their marks in a diagonal, horizontal, or vertical row is the winner. ## Workflow -Outline the workflow you used in your project. What are the steps you went through? + +First I created an extensive txt file with the pseudocode that helped me to organize the project and separate it in different sections. Then I proceeded to code the different parts of the code in (more or less) the following order: + +-Visual interface and basic interaction: asking the player if they want to be first/second or if they want to play again) + +-Interaction with the player: giving the ability to place markers + +-Rules of the game: checking when a player has won (or if it's a tie) + +-Computer AI: strategy to always find the best move. + +I also took care of readibility, error handling and such throughout the whole process. ## Organization -How did you organize your work? Did you use any tools like a kanban board? -What does your repository look like? Explain your folder and file structure. +I used the Trello template to organize my work and keep track of all remaining tasks. + +My repository consists of: + +- Folder: Project-Week-1-Build-Your-Own-Game + - Kick-Off.md (Instructions for the project) + - .gitignore + - Folder: your-project + - DAFT Presentation Tic_Tac_Toe.key (presentation of the project) + - README.md ("Read me" file including a summary of my project. You are literally looking at it) + - Folder: TicTacToe + - pseudocode.txt (text file including the pseudocode) + - TicTacToe.ipynb (a python3-jupyter-notebook file including all the code that makes up the game) + - tictactoe.py (an python3 file that can run the game by typing "python3 tictactoe.py" in Terminal) ## Links -Include links to your repository, slides and kanban board. Feel free to include any other links associated with your project. -[Repository](https://github.com/) -[Slides](https://slides.com/) -[Trello](https://trello.com/en) +[Repository](https://github.com/IgnacioRus/Project-Week-1-Build-Your-Own-Game) +[Trello](https://trello.com/b/ymfsxblR/tic-tac-toe-plan) diff --git a/your-project/TicTacToe/TicTacToe.ipynb b/your-project/TicTacToe/TicTacToe.ipynb new file mode 100644 index 0000000..3577bca --- /dev/null +++ b/your-project/TicTacToe/TicTacToe.ipynb @@ -0,0 +1,453 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 47, + "id": "innovative-working", + "metadata": { + "ExecuteTime": { + "end_time": "2021-03-25T20:39:43.606777Z", + "start_time": "2021-03-25T20:39:43.575098Z" + }, + "code_folding": [ + 44, + 152, + 207 + ], + "scrolled": true + }, + "outputs": [], + "source": [ + "import time\n", + "import sys\n", + "\n", + "def graph(state_dict):\n", + "\n", + "#\n", + "# Checks the keys 1, 2, 3, 4, 5, 6, 7, 8 and 9 (that correspond to positions of the game) and prints their values\n", + "# together with the board graphics. The values of the dictionary should be O or X.\n", + "#\n", + "# \n", + "# INPUT: state_dict (dict): Dictionary with the symbols (X for player, O for computer or \" \" if not played yet) \n", + "# placed in each position.\n", + "# \n", + "# OUTPUT: None\n", + "#\n", + " \n", + " print(\"\\n\")\n", + " print(\" \"+state_dict[\"1\"]+\" | \"+state_dict[\"2\"]+\" | \"+state_dict[\"3\"]+\" \")\n", + " print(\"---·---·---\")\n", + " print(\" \"+state_dict[\"4\"]+\" | \"+state_dict[\"5\"]+\" | \"+state_dict[\"6\"]+\" \")\n", + " print(\"---·---·---\")\n", + " print(\" \"+state_dict[\"7\"]+\" | \"+state_dict[\"8\"]+\" | \"+state_dict[\"9\"]+\" \")\n", + "\n", + " return\n", + "\n", + "\n", + "def find_best_move(free_pos,my_wincons,player_wincons,my_wincons_dict,player_wincons_dict):\n", + "\n", + "#\n", + "# Finds the best move for the computer. It's a badass function\n", + "#\n", + "#\n", + "# INPUT: free_pos (list): list that includes all the available positions in the board as strings (e.g. [\"1\",\"3\"]\n", + "# if only positions 1 and 3 are free)\n", + "#\n", + "# my_wincons (list): list that includes all the possible 3-in-a-row combinations for the computer given\n", + "# the current state of the game (e.g [\"123\",\"159\",\"369\"])\n", + "#\n", + "# my_wincons_dict (dict): a dictionary that, for every possible 3-in-a-row combination (key), gives the\n", + "# number of positions already occupied by the computer (value). If the player is\n", + "# occupying one of those positions, the value is automatically switched to \"-1\"\n", + "#\n", + "# player_wincons (list): list that includes all the possible 3-in-a-row combinations for the player\n", + "# given the current state of the game (e.g [\"123\",\"159\",\"369\"])\n", + "#\n", + "# player_wincons_dict (dict): a dictionary that, for every possible 3-in-a-row combination (key), gives\n", + "# the number of positions already occupied by the player (value). If the\n", + "# computer is occupying one of those positions, the value is automatically\n", + "# switched to \"-1\"\n", + "#\n", + "# OUTPUT: best_move (str): the best possible move in the world I promise\n", + "#\n", + " my_best_moves = []\n", + " player_best_moves = []\n", + " player_fork = []\n", + " max_counter = 0\n", + " maxp_counter = 0\n", + " \n", + " \n", + " if \"5\" in free_pos: #Always center first\n", + " return \"5\"\n", + " \n", + " if len(free_pos)==7: #Opposite corner\n", + " corner_sum = 0\n", + " for pos in free_pos:\n", + " corner_sum += int(pos)\n", + " if corner_sum%2 != 0:\n", + " return str(-30+corner_sum)\n", + " \n", + " for pos in free_pos:\n", + " my_counter = 0\n", + " player_counter = 0\n", + " my_fork_counter = 0\n", + " player_fork_counter = 0\n", + " \n", + " for wincon in my_wincons:\n", + " if pos in wincon:\n", + " my_counter += 1\n", + " if my_wincons_dict[wincon] == 1:\n", + " my_fork_counter += 1\n", + " if my_fork_counter == 2:\n", + " return pos\n", + " \n", + " if my_counter >= max_counter:\n", + " \n", + " if my_counter > max_counter:\n", + " my_best_moves = []\n", + " max_counter = my_counter\n", + " my_best_moves.append(pos)\n", + " \n", + " for wincon2 in player_wincons:\n", + " if pos in wincon2:\n", + " player_counter += 1\n", + " if player_wincons_dict[wincon2] == 1:\n", + " player_fork_counter += 1\n", + " if player_fork_counter == 2:\n", + " player_fork.append(pos) \n", + " \n", + " if player_counter >= maxp_counter:\n", + " \n", + " if player_counter > maxp_counter:\n", + " player_best_moves = []\n", + " maxp_counter = player_counter\n", + " player_best_moves.append(pos)\n", + " \n", + " if len(player_fork) != 0:\n", + " print(my_best_moves)\n", + " for fork in player_fork:\n", + " if fork in my_best_moves:\n", + " return fork\n", + " return player_fork[0]\n", + " \n", + " for best in my_best_moves:\n", + " if best in player_best_moves:\n", + " return best\n", + "\n", + " \n", + " return my_best_moves[0]\n", + "\n", + "\n", + "def tictactoe():\n", + "\n", + "# ***************************************\n", + "#\n", + "# THE GAME\n", + "#\n", + "# ***************************************\n", + "\n", + "#\n", + "# **************** Printing instructions ***************\n", + "#\n", + " \n", + " print(\"\\n\")\n", + " print(\"\\n\")\n", + " print(\"INSTRUCTIONS: \\n\")\n", + " print(\"Each position of the board has an assigned number from 1 to 9. In each of your turns, choose a free position in the board an introduce the corresponding number to play in that position. You can see the correspondence in the following diagram: \\n\")\n", + " state_dict_help = {\"1\":\"1\",\"2\":\"2\", \"3\":\"3\", \"4\":\"4\", \"5\":\"5\", \"6\":\"6\", \"7\":\"7\", \"8\":\"8\", \"9\":\"9\"}\n", + " graph(state_dict_help)\n", + " \n", + " time.sleep(1)\n", + " \n", + " play_again = True\n", + " \n", + " while play_again:\n", + " \n", + "#\n", + "# **************** Restarting variables ***************\n", + "#\n", + " first_error = True\n", + " again_error = True\n", + " move_error = True\n", + " state_dict = {\"1\":\" \",\"2\":\" \", \"3\":\" \", \"4\":\" \", \"5\":\" \", \"6\":\" \", \"7\":\" \", \"8\":\" \", \"9\":\" \"}\n", + " \n", + " free_pos = [\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\"]\n", + " win = False\n", + " \n", + " my_wincons = [\"123\",\"456\",\"789\",\"159\",\"357\",\"147\",\"258\",\"369\"]\n", + " my_wincons_dict = {\"123\":0,\"456\":0,\"789\":0,\"159\":0,\"357\":0,\"147\":0,\"258\":0,\"369\":0}\n", + " \n", + " player_wincons = [\"123\",\"456\",\"789\",\"159\",\"357\",\"147\",\"258\",\"369\"]\n", + " player_wincons_dict = {\"123\":0,\"456\":0,\"789\":0,\"159\":0,\"357\":0,\"147\":0,\"258\":0,\"369\":0}\n", + "#\n", + "# **************** Who goes first ***************\n", + "#\n", + " while first_error: #Playing first or second input\n", + " \n", + " print(\"\\n\")\n", + " first_yn = input(\"Do you want to go first? (Y/N): \",)\n", + " print(\"\\n\")\n", + " \n", + " if \"y\" in first_yn.lower():\n", + " \n", + " player_turn = True\n", + " print(\"You chose playing first\")\n", + " \n", + " first_error = False\n", + " print(\"\\n\")\n", + " print(\"The game starts!\")\n", + " graph(state_dict)\n", + " \n", + " time.sleep(1)\n", + " \n", + " elif \"n\" in first_yn.lower():\n", + " \n", + " player_turn = False\n", + " print(\"You chose playing second\")\n", + " \n", + " first_error = False\n", + " print(\"\\n\")\n", + " print(\"The game starts!\")\n", + " \n", + " time.sleep(1)\n", + " \n", + " else:\n", + " print(\"Input was invalid. Please, answer with 'Y' (Yes) or 'N' (No)\") \n", + " \n", + "#\n", + "# **************** Game starts ***************\n", + "#\n", + " while win == False:\n", + "\n", + "#\n", + "# **************** Player Turn ***************\n", + "#\n", + " \n", + " if player_turn == True:\n", + " \n", + " \n", + " while player_turn: #Player move input \n", + " \n", + " print(\"\\n\")\n", + " player_move = input(\"Your turn! Choose a position where you want to play: \")\n", + " print(\"\\n\")\n", + " \n", + " if player_move in free_pos:\n", + " \n", + " player_turn = False\n", + " \n", + " elif player_move == \"00\":\n", + " sys.exit()\n", + " \n", + " else:\n", + " \n", + " print(\"Input was invalid. Please, choose one of the available positions. Available positions are: \\n\",free_pos) \n", + " \n", + " state_dict[player_move] = \"X\"\n", + " free_pos.remove(player_move)\n", + " \n", + " print(\"You played in position\",player_move,\"! Take a look at it and regret your life choices\")\n", + " graph(state_dict)\n", + " \n", + " time.sleep(2)\n", + " \n", + " for wincon in player_wincons: #update player wincons\n", + "\n", + " if player_move in wincon:\n", + "\n", + " player_wincons_dict[wincon] += 1\n", + "\n", + " if player_wincons_dict[wincon] == 3:\n", + " \n", + " win = True\n", + " break\n", + " \n", + " my_wincons_temp = list(my_wincons)\n", + " for wincon2 in my_wincons_temp: #update computer wincons\n", + "\n", + " if player_move in wincon2:\n", + "\n", + " my_wincons_dict[wincon2] = -1\n", + " my_wincons.remove(wincon2)\n", + " \n", + " if win:\n", + " \n", + " print(\"\\n\")\n", + " print(\"Amazing! You beat the computer!\")\n", + " \n", + " \n", + "\n", + "#\n", + "# **************** Computer Turn ***************\n", + "# \n", + " else: \n", + " \n", + " no_move = True\n", + " for wincon in my_wincons: #if the computer can win in one move\n", + " \n", + " if my_wincons_dict[wincon]==2:\n", + " for pos in free_pos:\n", + " if pos in wincon:\n", + " no_move = False\n", + " my_move = pos\n", + " break\n", + " break\n", + " \n", + " if no_move: #if the computer can lose in one move\n", + " \n", + " for wincon in player_wincons:\n", + " \n", + " if player_wincons_dict[wincon]==2:\n", + " for pos in free_pos:\n", + " if pos in wincon:\n", + " no_move = False\n", + " my_move = pos\n", + " break\n", + " break\n", + " \n", + " if no_move: #A.I. motherfucker\n", + " \n", + " my_move = find_best_move(free_pos,my_wincons,player_wincons,my_wincons_dict,player_wincons_dict)\n", + " \n", + " state_dict[my_move] = \"O\"\n", + " free_pos.remove(my_move)\n", + " \n", + " print(\"\\n\")\n", + " print(\"The computer played in the position\",my_move,\"!\")\n", + " graph(state_dict)\n", + " \n", + " player_turn = True \n", + " \n", + " for wincon in my_wincons:\n", + " \n", + " if my_move in wincon:\n", + "\n", + " my_wincons_dict[wincon] += 1\n", + "\n", + " if my_wincons_dict[wincon] == 3:\n", + " \n", + " win = True\n", + " break\n", + " player_wincons_temp = list(player_wincons)\n", + " for wincon2 in player_wincons_temp:\n", + " if my_move in wincon2:\n", + " player_wincons_dict[wincon2] = -1\n", + " player_wincons.remove(wincon2)\n", + " \n", + " if win:\n", + " \n", + " print(\"\\n\")\n", + " print(\"The computer beat you! At least you can say you tried ;)\")\n", + " time.sleep(2)\n", + " \n", + " if len(player_wincons) == 0 and len(my_wincons) == 0:\n", + "\n", + " print(\"\\n\")\n", + " print(\"No one can win, it's a tie! What a boring game :S\")\n", + " time.sleep(2)\n", + " win = True\n", + "\n", + "#\n", + "# **************** Another game? ***************\n", + "# \n", + " while again_error: #Asking to play again \n", + " \n", + " print(\"\\n\") \n", + " again_yn = input(\"Do you want to go play again? (Y/N): \")\n", + " print(\"\\n\")\n", + " \n", + " if \"y\" in again_yn.lower():\n", + " \n", + " print(\"Let's play again!\")\n", + " again_error = False\n", + " \n", + " \n", + " elif \"n\" in again_yn.lower():\n", + " \n", + " play_again = False\n", + " again_error = False\n", + " \n", + " else:\n", + " print(\"Input was invalid. Please, answer with 'Y' (Yes) or 'N' (No)\")\n", + " \n", + "#\n", + "# **************** End of the game ***************\n", + "# \n", + " print(\"Thanks for playing! :)\")\n", + " print(\"\\n\")\n", + " \n", + " return \n", + "\n", + "tictactoe()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.2" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/your-project/TicTacToe/pseudocode.txt b/your-project/TicTacToe/pseudocode.txt new file mode 100644 index 0000000..408d444 --- /dev/null +++ b/your-project/TicTacToe/pseudocode.txt @@ -0,0 +1,171 @@ +Pseudo code: + + + +def tictactoe() + +*****INFO***** + +#info/rules + +************** + +while loop to play again: + + -> Input to choose player: go first? (Y/N) + + restart variables + + print game status (graph function) + + while no one wins and moves left: + + if player turn: + + ->Input to make a move + + make the move and update the state of the game with global variables (move function) + + print game status ("you moved!") ??? (graph function) + + check win conditions + + give turn to computer + + else: + + if we can win (caniwin function): + move and win using move function + + elif we can lose (canilose function): + move and save using move function + + else: + find best move (bestmove function) + + make the move (move function) + + print game status "the computer moved" (graph function) + + give turn to player + + declare winner + + -> Input want to play again? Y/N + + +************************FUNCTIONS************************ + +(graph function) + +def graph(state_dict) + +# +# Checks the keys 1, 2, 3, 4, 5, 6, 7, 8 and 9 (that correspond to positions of the game) and prints their values +# together with the board graphics. The values of the dictionary should be O or X +# + +(move function) + +def makemove(move,player,??) + +# +# +# +# + + change game status + update win conditions (update_win_cons function) ??? + + return new_state_dict, ?? + +(update_win_cons function) + +def update_win_cons(player=True,move,move_wincons,move_wincons_dict,notmove_wincons,notmove_wincons_dict) + +# +# +# +# + +for each moving_player_wincon: + + + + + + +(caniwin function) + +def caniwin(my_wincons,my_wincons_dict) + +# +#check if any of the wincons left has only one move left in the dictionary +# +# + +for every wincon left: + check values in my_wincons_dict + if value==2: + find move missing from wincon + break + +return move + + +(canilose function) + +def canilose(player_wincons,player_wincons_dict) + +# +#check if any of the wincons left has only one move left in the dictionary +# +# + +for every wincon left: + check values in player_wincons_dict + if dict(wincon)==2: + find move missing from wincon + break + +return move + +(bestmove function) + +def find_best_move(number_of_moves,free_pos,player_wincons,player_wincons_dict,my_wincons,my_wincons_dict + +if it's my first move: + if center is free: + best_move=center + else: + best_move is any corner + +solution for second move? + +if third or higher move: + for each free position: + initiate my_counter + initiate player_counter + max counter + for each of my wincons: + if free position is in the wincon: + my_counter +1 + if counter is greater than or equal max_counter: + if counter is greater than max_counter: + restart my_best_moves + add free_position to my_best_moves + + for each of player wincons: + if free position is in the wincon: + player_counter +1 + if counter is greater than or equal max_counter: + if counter is greater than max_counter: + restart player_best_moves + add free_position to player_best_moves + + for each my_best_move: + if move is in player_best_move: + best_move found + break + +return best_move \ No newline at end of file diff --git a/your-project/TicTacToe/tictactoe.py b/your-project/TicTacToe/tictactoe.py new file mode 100644 index 0000000..49e6e60 --- /dev/null +++ b/your-project/TicTacToe/tictactoe.py @@ -0,0 +1,361 @@ +import time +import sys + +def graph(state_dict): + +# +# Checks the keys 1, 2, 3, 4, 5, 6, 7, 8 and 9 (that correspond to positions of the game) and prints their values +# together with the board graphics. The values of the dictionary should be O or X. +# +# +# INPUT: state_dict (dict): Dictionary with the symbols (X for player, O for computer or " " if not played yet) +# placed in each position. +# +# OUTPUT: None +# + + print("\n") + print(" "+state_dict["1"]+" | "+state_dict["2"]+" | "+state_dict["3"]+" ") + print("---·---·---") + print(" "+state_dict["4"]+" | "+state_dict["5"]+" | "+state_dict["6"]+" ") + print("---·---·---") + print(" "+state_dict["7"]+" | "+state_dict["8"]+" | "+state_dict["9"]+" ") + + return + + +def find_best_move(free_pos,my_wincons,player_wincons,my_wincons_dict,player_wincons_dict): + +# +# Finds the best move for the computer. It's a badass function +# +# +# INPUT: free_pos (list): list that includes all the available positions in the board as strings (e.g. ["1","3"] +# if only positions 1 and 3 are free) +# +# my_wincons (list): list that includes all the possible 3-in-a-row combinations for the computer given +# the current state of the game (e.g ["123","159","369"]) +# +# my_wincons_dict (dict): a dictionary that, for every possible 3-in-a-row combination (key), gives the +# number of positions already occupied by the computer (value). If the player is +# occupying one of those positions, the value is automatically switched to "-1" +# +# player_wincons (list): list that includes all the possible 3-in-a-row combinations for the player +# given the current state of the game (e.g ["123","159","369"]) +# +# player_wincons_dict (dict): a dictionary that, for every possible 3-in-a-row combination (key), gives +# the number of positions already occupied by the player (value). If the +# computer is occupying one of those positions, the value is automatically +# switched to "-1" +# +# OUTPUT: best_move (str): the best possible move in the world I promise +# + my_best_moves = [] + player_best_moves = [] + player_fork = [] + max_counter = 0 + maxp_counter = 0 + + + if "5" in free_pos: #Always center first + return "5" + + if len(free_pos)==7: #Opposite corner + corner_sum = 0 + for pos in free_pos: + corner_sum += int(pos) + if corner_sum%2 != 0: + return str(-30+corner_sum) + + for pos in free_pos: + my_counter = 0 + player_counter = 0 + my_fork_counter = 0 + player_fork_counter = 0 + + for wincon in my_wincons: + if pos in wincon: + my_counter += 1 + if my_wincons_dict[wincon] == 1: + my_fork_counter += 1 + if my_fork_counter == 2: + return pos + + if my_counter >= max_counter: + + if my_counter > max_counter: + my_best_moves = [] + max_counter = my_counter + my_best_moves.append(pos) + + for wincon2 in player_wincons: + if pos in wincon2: + player_counter += 1 + if player_wincons_dict[wincon2] == 1: + player_fork_counter += 1 + if player_fork_counter == 2: + player_fork.append(pos) + + if player_counter >= maxp_counter: + + if player_counter > maxp_counter: + player_best_moves = [] + maxp_counter = player_counter + player_best_moves.append(pos) + + if len(player_fork) != 0: + print(my_best_moves) + for fork in player_fork: + if fork in my_best_moves: + return fork + return player_fork[0] + + for best in my_best_moves: + if best in player_best_moves: + return best + + + return my_best_moves[0] + + +def tictactoe(): + +# *************************************** +# +# THE GAME +# +# *************************************** + +# +# **************** Printing instructions *************** +# + + print("\n") + print("\n") + print("INSTRUCTIONS: \n") + print("Each position of the board has an assigned number from 1 to 9. In each of your turns, choose a free position in the board an introduce the corresponding number to play in that position. You can see the correspondence in the following diagram: \n") + state_dict_help = {"1":"1","2":"2", "3":"3", "4":"4", "5":"5", "6":"6", "7":"7", "8":"8", "9":"9"} + graph(state_dict_help) + + time.sleep(1) + + play_again = True + + while play_again: + +# +# **************** Restarting variables *************** +# + first_error = True + again_error = True + move_error = True + state_dict = {"1":" ","2":" ", "3":" ", "4":" ", "5":" ", "6":" ", "7":" ", "8":" ", "9":" "} + + free_pos = ["1","2","3","4","5","6","7","8","9"] + win = False + + my_wincons = ["123","456","789","159","357","147","258","369"] + my_wincons_dict = {"123":0,"456":0,"789":0,"159":0,"357":0,"147":0,"258":0,"369":0} + + player_wincons = ["123","456","789","159","357","147","258","369"] + player_wincons_dict = {"123":0,"456":0,"789":0,"159":0,"357":0,"147":0,"258":0,"369":0} +# +# **************** Who goes first *************** +# + while first_error: #Playing first or second input + + print("\n") + first_yn = input("Do you want to go first? (Y/N): ",) + print("\n") + + if "y" in first_yn.lower(): + + player_turn = True + print("You chose playing first") + + first_error = False + print("\n") + print("The game starts!") + graph(state_dict) + + time.sleep(1) + + elif "n" in first_yn.lower(): + + player_turn = False + print("You chose playing second") + + first_error = False + print("\n") + print("The game starts!") + + time.sleep(1) + + else: + print("Input was invalid. Please, answer with 'Y' (Yes) or 'N' (No)") + +# +# **************** Game starts *************** +# + while win == False: + +# +# **************** Player Turn *************** +# + + if player_turn == True: + + + while player_turn: #Player move input + + print("\n") + player_move = input("Your turn! Choose a position where you want to play: ") + print("\n") + + if player_move in free_pos: + + player_turn = False + + elif player_move == "00": + sys.exit() + + else: + + print("Input was invalid. Please, choose one of the available positions. Available positions are: \n",free_pos) + + state_dict[player_move] = "X" + free_pos.remove(player_move) + + print("You played in position",player_move,"! Take a look at it and regret your life choices") + graph(state_dict) + + time.sleep(2) + + for wincon in player_wincons: #update player wincons + + if player_move in wincon: + + player_wincons_dict[wincon] += 1 + + if player_wincons_dict[wincon] == 3: + + win = True + break + + my_wincons_temp = list(my_wincons) + for wincon2 in my_wincons_temp: #update computer wincons + + if player_move in wincon2: + + my_wincons_dict[wincon2] = -1 + my_wincons.remove(wincon2) + + if win: + + print("\n") + print("Amazing! You beat the computer!") + + + +# +# **************** Computer Turn *************** +# + else: + + no_move = True + for wincon in my_wincons: #if the computer can win in one move + + if my_wincons_dict[wincon]==2: + for pos in free_pos: + if pos in wincon: + no_move = False + my_move = pos + break + break + + if no_move: #if the computer can lose in one move + + for wincon in player_wincons: + + if player_wincons_dict[wincon]==2: + for pos in free_pos: + if pos in wincon: + no_move = False + my_move = pos + break + break + + if no_move: #A.I. motherfucker + + my_move = find_best_move(free_pos,my_wincons,player_wincons,my_wincons_dict,player_wincons_dict) + + state_dict[my_move] = "O" + free_pos.remove(my_move) + + print("\n") + print("The computer played in the position",my_move,"!") + graph(state_dict) + + player_turn = True + + for wincon in my_wincons: + + if my_move in wincon: + + my_wincons_dict[wincon] += 1 + + if my_wincons_dict[wincon] == 3: + + win = True + break + player_wincons_temp = list(player_wincons) + for wincon2 in player_wincons_temp: + if my_move in wincon2: + player_wincons_dict[wincon2] = -1 + player_wincons.remove(wincon2) + + if win: + + print("\n") + print("The computer beat you! At least you can say you tried ;)") + time.sleep(2) + + if len(player_wincons) == 0 and len(my_wincons) == 0: + + print("\n") + print("No one can win, it's a tie! What a boring game :S") + time.sleep(2) + win = True + +# +# **************** Another game? *************** +# + while again_error: #Asking to play again + + print("\n") + again_yn = input("Do you want to go play again? (Y/N): ") + print("\n") + + if "y" in again_yn.lower(): + + print("Let's play again!") + again_error = False + + + elif "n" in again_yn.lower(): + + play_again = False + again_error = False + + else: + print("Input was invalid. Please, answer with 'Y' (Yes) or 'N' (No)") + +# +# **************** End of the game *************** +# + print("Thanks for playing! :)") + print("\n") + + return + +tictactoe() \ No newline at end of file