LAB ASSIGNMENT 02:
TASKS:
CODE:
#!/usr/bin/env python
# coding: utf-8
# # DOT AND BOXES
# In[2]:
N, M = 5, 5
n_players = 2
marks = ['X', 'O']
count_boxes = [0,0]
grid = [['.' for i in range(M-1)] for _ in range(N-1)]
horizontal_grid = [[False for i in range(M)] for j in range(N+1)]
vertical_grid = [[False for i in range(M+1)] for j in range(N)]
#This function prints the grid of Dots-and-Boxes as the game progresses
def print_grid():
for i in range(n_players):
print('Player %d: %c ' % (i+1, marks[i]), end='')
if i < n_players-1:
print('vs ', end='')
print()
print('--' + '------' * (M-1))
for i in range(N):
print(' . ', end = '')
for j in range(M):
print('---' if horizontal_grid[i][j] else ' ', end = '')
if j < M-1:
print(' . ', end = '')
print()
for j in range(M+1):
print(' | ' if vertical_grid[i][j] else ' ', end = '')
if i < N-1 and j < M-1:
print(grid[i][j] if grid[i][j] != '.' else ' ', end='')
print(' ', end = '')
print()
for i in range(n_players):
print('Player %c is %d'% (marks[i], count_boxes[i]))
print('--' + '------' * (M-1))
#This function checks if the grid is full or not
def check_full():
for i in range(N - 1):
for j in range(M - 1):
if(horizontal_grid[i][j] == False or vertical_grid[i][j] == False):
return False
return True
#This function checks if the given side is empty or not
def check_empty_side(i1, j1, i2, j2):
if(i1 == i2):
if(not horizontal_grid[i1][j1]):
return True
if(j1 == j2):
if(vertical_grid[i1][j1] == False):
return True
return False
#This function checks if the given position is valid in the grid or not
def check_valid_position(i, j):
if(i >= 0 and i < N and j >= 0 and j < M):
return True
return False
#This function checks if given side is valid or not
def check_valid_side(i1, j1, i2, j2):
if((i1 == i2 and abs(j1 - j2) == 1) or (j1 == j2 and abs(i1 - i2) == 1)):
return True
return False
#This function sets the given side
def set_side(i1, j1, i2, j2):
if(i1 == i2):
horizontal_grid[i1][j1] = True
else:
vertical_grid[i1][j1] = True
def is_complete_box(i, j):
if (horizontal_grid[i][j] and vertical_grid[i][j] and horizontal_grid[i + 1][j] and vertical_grid[i][j + 1]):
return True
return False
def set_box(i,j,player):
grid[i][j] = marks[player]
count_boxes[player] += 1
def set_neighbor_box( i1, j1, i2, j2, player):
if(i1 == i2 and i1 != 0 and i1 != N - 1):
if(is_complete_box(i1 - 1,j1)):
set_box(i1 - 1, j1, player)
return True
elif(j1 == j2 and j1 != 0 and j1 != M - 1):
if(is_complete_box(i1,j1-1)):
set_box(i1, j1-1, player)
return True
return False
#This function checks and sets the neighbor completed boxes
def set_neighbor_boxes(i1, j1, i2, j2, player):
flag = False
if (i1 == i2 and i1 == N - 1):
if (is_complete_box(i1 - 1, j1)):
set_box(i1 - 1, j1, player)
flag = True
elif (j1 == j2 and j1 == M - 1):
if (is_complete_box(i1, j1 - 1)):
set_box(i1, j1 - 1, player)
flag = True
elif (is_complete_box(i1, j1)):
set_box(i1, j1, player)
flag = True
if (set_neighbor_box(i1, j1, i2, j2, player)):
flag = True
return flag
#This function arranges the points of the side
def arrange_side_points(i1, j1, i2, j2):
mini = min(i1,i2)
maxi = max(i1,i2)
i1 = mini
i2 = maxi
mini = min(j1,j2)
maxi= max(j1,j2)
j1 = mini
j2 = maxi
return i1, j1, i2, j2
#This function clears the game structures
def grid_clear():
for i in range(N-1):
for j in range(M-1):
grid[i][j] = '.'
for i in range(N):
for j in range(M):
horizontal_grid[i][j] = False
vertical_grid[i][j] = False
count_boxes[0] = 0
count_boxes[1] = 0
#This function reads a valid and arranged side input
def read_input():
i1, j1, i2, j2 = map(int, input('enter your move: ').split())
i1, j1, i2, j2 = arrange_side_points(i1, j1, i2, j2)
while not check_valid_position(i1, j1) or not check_valid_position(i2, j2) or not
check_valid_side(i1, j1, i2, j2) or not check_empty_side(i1, j1, i2, j2):
i1, j1, i2, j2 = map(int, input('enter move: ').split())
i1, j1, i2, j2 = arrange_side_points(i1, j1, i2, j2)
return i1, j1, i2, j2
#MAIN FUNCTION
def play_game():
print("Dots Boxes Game")
print("Welcome. to the DOT BOX GAME")
print("***********")
player = 0
while True:
#Prints the grid
print_grid()
#Read an input position from the player
print('Player %s is playing now' % marks[player])
i1, j1, i2, j2 = read_input()
print(i1)
print(j2)
#Set the input position with the mark
set_side(i1, j1, i2, j2)
#Set the neighbor boxes with the mark
box_complete = set_neighbor_boxes(i1, j1, i2, j2, player)
#Check if the state of the grid has a complete state
if check_full():
#Prints the grid
print_grid()
#Announcement of the final statement
if count_boxes.count(max(count_boxes)) == 1:
idx_max_player = count_boxes.index(max(count_boxes))
print('Congrats, Player %s is won!' % marks[idx_max_player])
else:
print("Woah! That's a tie!")
break
#Keep the player if there is a complete box
if not box_complete:
#Player number changes after each turn
player = (player + 1) % n_players
while True:
grid_clear()
play_game()
c = input('Play Again [Y/N] ')
if c not in 'yY':
break
# # MINIMAX
# In[1]:
#!/usr/bin/env python3
from math import inf as infinity
from random import choice
import platform
import time
from os import system
"""
An implementation of Minimax AI Algorithm in Tic Tac Toe,
using Python.
This software is available under GPL license.
Author: Clederson Cruz
Year: 2017
License: GNU GENERAL PUBLIC LICENSE (GPL)
"""
HUMAN = -1
COMP = +1
board = [
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
def evaluate(state):
"""
Function to heuristic evaluation of state.
:param state: the state of the current board
:return: +1 if the computer wins; -1 if the human wins; 0 draw
"""
if wins(state, COMP):
score = +1
elif wins(state, HUMAN):
score = -1
else:
score = 0
return score
def wins(state, player):
"""
This function tests if a specific player wins. Possibilities:
* Three rows [X X X] or [O O O]
* Three cols [X X X] or [O O O]
* Two diagonals [X X X] or [O O O]
:param state: the state of the current board
:param player: a human or a computer
:return: True if the player wins
"""
win_state = [
[state[0][0], state[0][1], state[0][2]],
[state[1][0], state[1][1], state[1][2]],
[state[2][0], state[2][1], state[2][2]],
[state[0][0], state[1][0], state[2][0]],
[state[0][1], state[1][1], state[2][1]],
[state[0][2], state[1][2], state[2][2]],
[state[0][0], state[1][1], state[2][2]],
[state[2][0], state[1][1], state[0][2]],
if [player, player, player] in win_state:
return True
else:
return False
def game_over(state):
"""
This function test if the human or computer wins
:param state: the state of the current board
:return: True if the human or computer wins
"""
return wins(state, HUMAN) or wins(state, COMP)
def empty_cells(state):
"""
Each empty cell will be added into cells' list
:param state: the state of the current board
:return: a list of empty cells
"""
cells = []
for x, row in enumerate(state):
for y, cell in enumerate(row):
if cell == 0:
[Link]([x, y])
return cells
def valid_move(x, y):
"""
A move is valid if the chosen cell is empty
:param x: X coordinate
:param y: Y coordinate
:return: True if the board[x][y] is empty
"""
if [x, y] in empty_cells(board):
return True
else:
return False
def set_move(x, y, player):
"""
Set the move on board, if the coordinates are valid
:param x: X coordinate
:param y: Y coordinate
:param player: the current player
"""
if valid_move(x, y):
board[x][y] = player
return True
else:
return False
def minimax(state, depth, player):
if player == COMP:
best = [-1, -1, -infinity]
else:
best = [-1, -1, +infinity]
if depth == 0 or game_over(state):
score = evaluate(state)
return [-1, -1, score]
for cell in empty_cells(state):
x, y = cell[0], cell[1]
state[x][y] = player
score = minimax(state, depth - 1, -player)
state[x][y] = 0
score[0], score[1] = x, y
if player == COMP:
if score[2] > best[2]:
best = score # max value
else:
if score[2] < best[2]:
best = score # min value
return best
def clean():
"""
Clears the console
"""
os_name = [Link]().lower()
if 'windows' in os_name:
system('cls')
else:
system('clear')
def render(state, c_choice, h_choice):
"""
Print the board on console
:param state: current state of the board
"""
print(state)
chars = {
-1: h_choice,
+1: c_choice,
0: ' '
str_line = '---------------'
print('\n' + str_line)
for row in state:
for cell in row:
symbol = chars[cell]
print(f'| {symbol} |', end='')
print('\n' + str_line)
def ai_turn(c_choice, h_choice):
"""
It calls the minimax function if the depth < 9,
else it choices a random coordinate.
:param c_choice: computer's choice X or O
:param h_choice: human's choice X or O
:return:
"""
depth = len(empty_cells(board))
if depth == 0 or game_over(board):
return
clean()
print(f'Computer turn [{c_choice}]')
render(board, c_choice, h_choice)
if depth == 9:
x = choice([0, 1, 2])
y = choice([0, 1, 2])
else:
move = minimax(board, depth, COMP)
x, y = move[0], move[1]
set_move(x, y, COMP)
[Link](1)
def human_turn(c_choice, h_choice):
"""
The Human plays choosing a valid move.
:param c_choice: computer's choice X or O
:param h_choice: human's choice X or O
:return:
"""
depth = len(empty_cells(board))
if depth == 0 or game_over(board):
return
# Dictionary of valid moves
move = -1
moves = {
1: [0, 0], 2: [0, 1], 3: [0, 2],
4: [1, 0], 5: [1, 1], 6: [1, 2],
7: [2, 0], 8: [2, 1], 9: [2, 2],
print(move)
clean()
print(f'Human turn [{h_choice}]')
# print(moves)
render(board, c_choice, h_choice)
while move < 1 or move > 9:
try:
move = int(input('Use numpad (1..9): '))
coord = moves[move]
can_move = set_move(coord[0], coord[1], HUMAN)
if not can_move:
print('Bad move')
move = -1
except (EOFError, KeyboardInterrupt):
print('Bye')
exit()
except (KeyError, ValueError):
print('Bad choice')
def main():
"""
Main function that calls all functions
"""
clean()
h_choice = '' # X or O
c_choice = '' # X or O
first = '' # if human is the first
# Human chooses X or O to play
while h_choice != 'O' and h_choice != 'X':
try:
print('')
h_choice = input('Choose X or O\nChosen: ').upper()
except (EOFError, KeyboardInterrupt):
print('Bye')
exit()
except (KeyError, ValueError):
print('Bad choice')
# Setting computer's choice
if h_choice == 'X':
c_choice = 'O'
else:
c_choice = 'X'
# Human may starts first
clean()
while first != 'Y' and first != 'N':
try:
first = input('First to start?[y/n]: ').upper()
except (EOFError, KeyboardInterrupt):
print('Bye')
exit()
except (KeyError, ValueError):
print('Bad choice')
# Main loop of this game
while len(empty_cells(board)) > 0 and not game_over(board):
if first == 'N':
ai_turn(c_choice, h_choice)
first = ''
human_turn(c_choice, h_choice)
ai_turn(c_choice, h_choice)
# Game over message
if wins(board, HUMAN):
clean()
print(f'Human turn [{h_choice}]')
render(board, c_choice, h_choice)
print('YOU WIN!')
elif wins(board, COMP):
clean()
print(f'Computer turn [{c_choice}]')
render(board, c_choice, h_choice)
print('YOU LOSE!')
else:
clean()
render(board, c_choice, h_choice)
print('DRAW!')
exit()
if _name_ == '_main_':
main()
# # [Link]
# In[4]:
#Using wikipedia pseudocode without depth
def alphabeta(game_state, alpha=-2, beta=2, our_turn=True):
if game_state.is_gameover():
return game_state.score(), None
if our_turn:
score = -2 #worst non-possible score. A win, tie, or even a loss will change this
for move in game_state.get_possible_moves():
child = game_state.get_next_state(move, True)
temp_max, _ = alphabeta(child, alpha, beta, False)
print(temp_max)
if temp_max > score:
score = temp_max
best_move = move
alpha = max(alpha, score)
# print(alpha)
if beta <= alpha:
break
return score, best_move
else:
score = 2 #worst non-possible score. A win, tie, or even a loss will change this
for move in game_state.get_possible_moves():
child = game_state.get_next_state(move, False)
temp_min, _ = alphabeta(child, alpha, beta, True)
print(temp_min)
if temp_min < score:
score = temp_min
best_move = move
beta = min(beta, score)
# print(beta)
if beta <= alpha:
break
return score, best_move
# In[5]:
#!/usr/bin/env python3
import random
from time import sleep
import alphabeta as ab
import gamestate as gs
def get_p_move(game):
while True:
raw_move = input('Your move (1-9) > ')
if raw_move.isdigit():
p_move = int(raw_move) - 1
if p_move > -1 and p_move < 9:
if [Link][p_move] == '_':
break
return p_move
def run_game(game, player_goes_first):
if player_goes_first:
while True:
game.pretty_print()
p_move = get_p_move(game)
game = game.get_next_state(p_move, False)
if game.is_gameover(): break
score, ai_move = [Link](game)
game = game.get_next_state(ai_move, True)
if game.is_gameover(): break
else:
while True:
score, ai_move = [Link](game)
game = game.get_next_state(ai_move, True)
if game.is_gameover(): break
game.pretty_print()
p_move = get_p_move(game)
game = game.get_next_state(p_move, False)
if game.is_gameover(): break
game.pretty_print()
print('The computer ' + game.return_state(score))
def get_symbols():
human_char = input('Pick your symbol > ')
if len(human_char) > 1 or human_char == '' or human_char == ' ' or human_char == '_':
exit()
elif human_char == 'X' or human_char == 'x':
ai_char = 'O'
else:
ai_char = 'X'
return human_char, ai_char
if _name_ == '_main_':
try:
human_char, ai_char = get_symbols()
start_board = ['_'] * 9
player_goes_first = bool([Link](0,2))
input('You go first:{}\nenter to continue\n'.format(player_goes_first))
game = [Link](start_board,char=ai_char, oppchar=human_char)
run_game(game, player_goes_first)
except KeyboardInterrupt:
print('\n')
exit()
# In[ ]