Skip to content

Instantly share code, notes, and snippets.

@ma0c
Created April 19, 2018 14:54
Show Gist options
  • Save ma0c/795604aeed2badac82b9445345eed3ae to your computer and use it in GitHub Desktop.
Save ma0c/795604aeed2badac82b9445345eed3ae to your computer and use it in GitHub Desktop.
Tic Tac Toe Minimal Python
import requests
import time
BOARD_WIDTH = 3
BOARD_HEIGHT = 3
WELCOME_MESSAGE = "Welcome to tictactoe press: \n1. To play\n2. For Instructions\n3. Exit:\n"
UNAVAILABLE_OPTION = "Unavailable option"
GETTING_GAME_MESSAGE = "We're checking for game availability"
INSTRUCTION_MESSAGE = "To play put a number between 1 and 9 that represent the grid"
MAKE_MOVE_MESSAGE = "Make your move [1-9]:\n"
INVALID_MOVE_MESSAGE = "Invalid move, try again"
SLOT_OCCUPIED = "Slot Occupied"
WAITING_FOR_PLAYER = "Waiting for player"
EXIT_MESSAGE = "Have a nice day"
INSTRUCTION_GRID = [str(x) for x in range(1, 10)]
UNAVAILABLE_SERVER = "Unavailable server, please try later"
BACKEND_URL = "http://localhost:8000"
CREATE_OR_JOIN_ENDPOINT = "/create-or-join/"
MAKE_MOVE_ENDPOINT = "/make-move/"
GAME_STATUS_ENDPOINT = "/game-status/"
GET_BOARD_ENDPOINT = "/get-board/"
def print_board(board_str):
"""
from client import print_board
print_board("XO XO X ")
:param board_str:
:return:
"""
# separated_board = "|".join(board_str)
print("|".join(board_str[0:3]))
print("|".join(board_str[3:6]))
print("|".join(board_str[6:9]))
def read_valid_move(board):
user_input = input(MAKE_MOVE_MESSAGE)
try:
int_move = int(user_input.strip())
if 1 <= int_move <= 9:
if board[int_move-1] == " ":
return int_move
else:
print(SLOT_OCCUPIED)
except ValueError:
pass
print(INVALID_MOVE_MESSAGE)
return read_valid_move(board)
def main_menu():
user_input = input(WELCOME_MESSAGE)
try:
int_value = int(user_input.strip())
if int_value == 1:
loop()
elif int_value == 2:
instructions()
elif int_value == 3:
exit_game()
else:
print("Main main Not main main option", int_value)
print(UNAVAILABLE_OPTION)
except ValueError:
print("Main main Not menu option")
print(UNAVAILABLE_OPTION)
def make_move(game_id, move_index, player):
payload = {
'id': game_id,
'move_index': move_index,
'player': player
}
make_move_response = requests.post(
"{}{}".format(BACKEND_URL, MAKE_MOVE_ENDPOINT),
json=payload
)
if make_move_response.status_code == 200:
return make_move_response.json()
else:
print(UNAVAILABLE_SERVER)
exit(0)
def check_status(game_id):
check_status_response = requests.get(
"{}{}?id={}".format(BACKEND_URL, GAME_STATUS_ENDPOINT, game_id)
)
if check_status_response.status_code == 200:
response_json = check_status_response.json()
return response_json.get('turn', game_id)
else:
return game_id
def get_board(game_id):
check_status_response = requests.get(
"{}{}?id={}".format(BACKEND_URL, GET_BOARD_ENDPOINT, game_id)
)
if check_status_response.status_code == 200:
response_json = check_status_response.json()
return response_json
else:
return dict()
def wait_for_play(current_game, turn):
while check_status(current_game) <= turn:
print(WAITING_FOR_PLAYER)
time.sleep(1)
def loop():
print(WELCOME_MESSAGE)
create_or_join_request = requests.get("{}{}".format(BACKEND_URL, CREATE_OR_JOIN_ENDPOINT))
if create_or_join_request.status_code == 200:
response_json = create_or_join_request.json()
current_game = response_json.get('id', 0)
last_player = response_json.get('last_player', 'O')
player = "X" if last_player == "O" else "O"
print("Game number {}".format(current_game))
board = [' ' for _ in range(9)]
turn = response_json.get('turn', 0)
print("You are {}".format(player))
if player == "O":
wait_for_play(current_game, turn)
response_json = get_board(current_game)
while not response_json.get("finished", True):
board = response_json.get('board', board)
print_board(board)
response_json = make_move(
current_game,
read_valid_move(board),
player
)
turn = response_json.get('turn', turn)
board = response_json.get('board', board)
print_board(board)
print(response_json.get('message', ''))
if not response_json.get("finished", True):
# The game is not ended
wait_for_play(current_game, turn)
response_json = get_board(current_game)
if response_json.get("finished", False):
# The opponent won the game
print_board(response_json.get('board', board))
print(response_json.get('message', ''))
else:
# The game ended because I win
pass
main_menu()
else:
print(UNAVAILABLE_SERVER)
def instructions():
print(INSTRUCTION_MESSAGE)
print(print_board(INSTRUCTION_GRID))
main_menu()
def exit_game():
print(EXIT_MESSAGE)
exit(0)
if __name__ == '__main__':
main_menu()
certifi==2018.1.18
chardet==3.0.4
Django==2.0.4
idna==2.6
pytz==2018.4
requests==2.18.4
urllib3==1.22
import sys
import json
from django.conf import settings
from django.conf.urls import url
from django.core.management import execute_from_command_line
from django.http import JsonResponse
from django.views.generic import View
from django.views.decorators.csrf import csrf_exempt
settings.configure(
DEBUG=True,
SECRET_KEY='A-random-secret-key!',
ROOT_URLCONF=sys.modules[__name__],
)
INVALID_PAYLOAD = "Invalid Payload"
INVALID_MOVE_MESSAGE = "Invalid Move"
GAME_NOT_FOUND_MESSAGE = "Game not found"
TURN_INVALID = "Turn invalid please wait for opponent"
GAME_ENDED_WITH_WINNER = "The game is ended and the winner is {}"
GAME_ENDED_WITH_DRAW = "The game is ended there is a draw"
GAMES = list()
# This matrix could be calculated automatically
WINNER_MATRIX = [
[0, 1, 2], # 0
[3, 4, 5], # 1
[6, 7, 8], # 2
[0, 3, 6], # 3
[1, 4, 7], # 4
[2, 5, 8], # 5
[0, 4, 8], # 6
[2, 4, 6] # 7
]
# Also this dict but for AI this should be a better option
CHECK_FOR_WIN = {
0: [0, 3, 6],
1: [0, 4],
2: [0, 5, 7],
3: [1, 3],
4: [1, 4, 6, 7],
5: [1, 5],
6: [2, 3, 7],
7: [2, 4],
8: [2, 5, 6],
}
class CreateOrJoin(View):
def get(self, request, *args, **kwargs):
if not GAMES or GAMES[-1]['turn'] > 1:
# There are no games
json_response = self.create_new_game()
json_response['id'] = len(GAMES)
GAMES.append(json_response)
json_response['last_player'] = "O"
else:
# Return last game
current_game = GAMES[-1]
json_response = current_game.copy()
json_response['last_player'] = "X"
print(GAMES)
return JsonResponse(json_response)
def create_new_game(self):
new_game = dict()
new_game['board'] = [' ' for _ in range(9)]
new_game['turn'] = 0
new_game['finished'] = False
new_game['winner'] = ''
return new_game
class MakeMove(View):
@csrf_exempt
def dispatch(self, request, *args, **kwargs):
return super(MakeMove, self).dispatch(request, *args, **kwargs)
@staticmethod
def check_winner(board, current_player, play):
for possible_win in CHECK_FOR_WIN[play]:
is_a_win = True
for slot in WINNER_MATRIX[possible_win]:
if board[slot] != current_player:
is_a_win = False
break
if is_a_win:
return True
return False
@staticmethod
def check_game_end(turn):
return turn >= 9
def post(self, request, *args, **kwargs):
body = json.loads(request.body)
print(body)
response = dict()
game_index = body.get('id', None)
move_index = body.get('move_index', None)
player = body.get('player', None)
if game_index is None or move_index is None or player is None:
response['status'] = 400
response['message'] = INVALID_PAYLOAD
else:
try:
game_index = int(game_index)
current_game = GAMES[game_index]
if current_game['board'][move_index - 1] == " ":
if current_game['last_player'] == player:
response['status'] = 400
response['message'] = TURN_INVALID
else:
current_game['board'][move_index - 1] = player
current_game['last_player'] = player
current_game['turn'] += 1
if self.check_winner(
current_game['board'],
player,
move_index -1
):
current_game['finished'] = True
current_game['winner'] = player
response['finished'] = True
response['message'] = GAME_ENDED_WITH_WINNER.format(player)
elif self.check_game_end(current_game['turn']):
current_game['finished'] = True
response['finished'] = True
response['message'] = GAME_ENDED_WITH_DRAW
response['status'] = 200
response['message'] = response.get('message', '')
response['board'] = current_game['board']
response['last_player'] = current_game['last_player']
response['turn'] = current_game['turn']
else:
response['status'] = 400
response['message'] = INVALID_MOVE_MESSAGE
except ValueError:
response['status'] = 400
response['message'] = INVALID_MOVE_MESSAGE
except IndexError:
response['status'] = 400
response['message'] = GAME_NOT_FOUND_MESSAGE
response['finished'] = response.get('finished', False)
return JsonResponse(response)
class GameStatus(View):
def get(self, request, *args, **kwargs):
response = dict()
game_index = request.GET.get('id', None)
if game_index is None:
response['status'] = 400
response['message'] = INVALID_PAYLOAD
else:
try:
game_index = int(game_index)
game = GAMES[game_index]
response['status'] = 200
response['turn'] = game['turn']
except ValueError:
response['status'] = 400
response['message'] = INVALID_PAYLOAD
except IndexError:
response['status'] = 400
response['message'] = GAME_NOT_FOUND_MESSAGE
return JsonResponse(response)
class GetBoard(View):
def get(self, request, *args, **kwargs):
response = dict()
game_index = request.GET.get('id', None)
if game_index is None:
response['status'] = 400
response['message'] = INVALID_PAYLOAD
else:
try:
game_index = int(game_index)
game = GAMES[game_index]
response['status'] = 200
response['turn'] = game['turn']
response['board'] = game['board']
response['finished'] = game['finished']
if game['finished']:
if game['winner']:
response['message'] = GAME_ENDED_WITH_WINNER.format(game['winner'])
else:
response['message'] = GAME_ENDED_WITH_DRAW
response['message'] = response.get('message', '')
except ValueError:
response['status'] = 400
response['message'] = INVALID_PAYLOAD
except IndexError:
response['status'] = 400
response['message'] = GAME_NOT_FOUND_MESSAGE
return JsonResponse(response)
urlpatterns = [
url(r'^create-or-join/$', CreateOrJoin.as_view()),
url(r'^make-move/$', MakeMove.as_view()),
url(r'^game-status/$', GameStatus.as_view()),
url(r'^get-board/$', GetBoard.as_view()),
]
if __name__ == '__main__':
execute_from_command_line(sys.argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment