Skip to content

Commit f233517

Browse files
author
Addis Semagn
committed
upload files
0 parents  commit f233517

13 files changed

+1369
-0
lines changed

#agent.py#

+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
board
2+
An AI player for Othello.
3+
"""
4+
5+
# gotta make moves within 10 seconds
6+
7+
import random
8+
import sys
9+
import time
10+
import math
11+
12+
# You can use the functions in othello_shared to write your AI
13+
from othello_shared import find_lines, get_possible_moves, get_score, play_move
14+
15+
def eprint(*args, **kwargs): #you can use this for debugging, as it will print to sterr and not stdout
16+
print(*args, file=sys.stderr, **kwargs)
17+
18+
# Method to compute utility value of terminal state
19+
def compute_utility(board, color):
20+
score = get_score(board) # (# of dark disks, # of light disks), color 1 for dark and 2 for light
21+
final = (score[0] - score[1]) if color == 1 else (score[1] - score[0])
22+
return final
23+
24+
# Better heuristic value of board
25+
def compute_heuristic(board, color): #not implemented, optional
26+
#IMPLEMENT
27+
return 0 #change this!
28+
29+
############ MINIMAX ###############################
30+
# returns lowest possible utility
31+
def minimax_min_node(board, color, limit, caching = 0):
32+
opponent = 1 if color == 2 else 2
33+
moves = get_possible_moves(board, color)
34+
lowest_utility = math.inf
35+
36+
if len(moves) == 0:
37+
return (0, 0), compute_utility(board, color)
38+
39+
best_move = moves[0]
40+
41+
for move in moves:
42+
board_after_play = play_move(board, color, move[0], move[1])
43+
test_move, utility = minimax_max_node(board_after_play, opponent, limit, caching)
44+
45+
if utility < lowest_utility:
46+
best_move = move
47+
lowest_utility = utility
48+
49+
# return ((0,0),0)
50+
return best_move, lowest_utility
51+
52+
# returns highest possible utility
53+
def minimax_max_node(board, color, limit, caching = 0):
54+
opponent = 1 if color == 2 else 2
55+
moves = get_possible_moves(board, color)
56+
highest_utility = -math.inf
57+
58+
if len(moves) == 0:
59+
return (0, 0), compute_utility(board, color)
60+
61+
best_move = moves[0]
62+
63+
for move in moves:
64+
board_after_play = play_move(board, color, move[0], move[1])
65+
test_move, utility = minimax_min_node(board_after_play, opponent, limit, caching)
66+
67+
if utility > highest_utility:
68+
best_move = move
69+
highest_utility = utility
70+
71+
return best_move, highest_utility
72+
73+
def select_move_minimax(board, color, limit, caching = 0):
74+
"""
75+
Given a board and a player color, decide on a move.
76+
The return value is a tuple of integers (i,j), where
77+
i is the column and j is the row on the board.
78+
Note that other parameters are accepted by this function:
79+
If limit is a positive integer, your code should enfoce a depth limit that is equal to the value of the parameter.
80+
Search only to nodes at a depth-limit equal to the limit. If nodes at this level are non-terminal return a heuristic
81+
value (see compute_utility)
82+
If caching is ON (i.e. 1), use state caching to reduce the number of state evaluations.
83+
If caching is OFF (i.e. 0), do NOT use state caching to reduce the number of state evaluations.
84+
"""
85+
move, utility = minimax_max_node(board, color, limit, caching)
86+
return move
87+
88+
############ ALPHA-BETA PRUNING #####################
89+
def alphabeta_min_node(board, color, alpha, beta, limit, caching = 0, ordering = 0):
90+
opponent = 1 if color == 2 else 2
91+
moves = get_possible_moves(board, color)
92+
lowest_utility = math.inf
93+
94+
if len(moves) == 0:
95+
return (0, 0), compute_utility(board, color)
96+
97+
best_move = moves[0]
98+
99+
for move in moves:
100+
board_after_play = play_move(board, color, move[0], move[1])
101+
test_move, utility = minimax_max_node(board_after_play, opponent, limit, caching)
102+
103+
if utility < lowest_utility:
104+
best_move = move
105+
lowest_utility = utility
106+
107+
if lowest_utility <= alpha:
108+
return best_move, highest_utility
109+
110+
if lowest_utility < beta:
111+
beta = lowest_utility
112+
113+
# return ((0,0),0)
114+
return best_move, lowest_utility
115+
116+
# maximizer
117+
def alphabeta_max_node(board, color, alpha, beta, limit, caching = 0, ordering = 0):
118+
opponent = 1 if color == 2 else 2
119+
moves = get_possible_moves(board, color)
120+
highest_utility = -math.inf
121+
122+
if len(moves) == 0:
123+
return (0, 0), compute_utility(board, color)
124+
125+
best_move = moves[0]
126+
127+
for move in moves:
128+
board_after_play = play_move(board, color, move[0], move[1])
129+
test_move, utility = minimax_min_node(board_after_play, opponent, limit, caching)
130+
131+
if utility > highest_utility:
132+
best_move = move
133+
highest_utility = utility
134+
135+
if highest_utility >= beta:
136+
return best_move, highest_utility
137+
138+
if highest_utility > alpha:
139+
alpha = highest_utility
140+
141+
return best_move, highest_utility
142+
143+
def select_move_alphabeta(board, color, limit, caching = 0, ordering = 0):
144+
"""
145+
Given a board and a player color, decide on a move.
146+
The return value is a tuple of integers (i,j), where
147+
i is the column and j is the row on the board.
148+
149+
Note that other parameters are accepted by this function:
150+
If limit is a positive integer, your code should enfoce a depth limit that is equal to the value of the parameter.
151+
Search only to nodes at a depth-limit equal to the limit. If nodes at this level are non-terminal return a heuristic
152+
value (see compute_utility)
153+
If caching is ON (i.e. 1), use state caching to reduce the number of state evaluations.
154+
If caching is OFF (i.e. 0), do NOT use state caching to reduce the number of state evaluations.
155+
If ordering is ON (i.e. 1), use node ordering to expedite pruning and reduce the number of state evaluations.
156+
If ordering is OFF (i.e. 0), do NOT use node ordering to expedite pruning and reduce the number of state evaluations.
157+
"""
158+
alpha = -math.inf
159+
beta = math.inf
160+
161+
move, utility = alphabeta_max_node(board, color, alpha, beta, limit, caching, ordering)
162+
return move #change this!
163+
164+
####################################################
165+
def run_ai():
166+
"""
167+
This function establishes communication with the game manager.
168+
It first introduces itself and receives its color.
169+
Then it repeatedly receives the current score and current board state
170+
until the game is over.
171+
"""
172+
print("Othello AI") # First line is the name of this AI
173+
arguments = input().split(",")
174+
175+
color = int(arguments[0]) #Player color: 1 for dark (goes first), 2 for light.
176+
limit = int(arguments[1]) #Depth limit
177+
minimax = int(arguments[2]) #Minimax or alpha beta
178+
caching = int(arguments[3]) #Caching
179+
ordering = int(arguments[4]) #Node-ordering (for alpha-beta only)
180+
181+
if (minimax == 1): eprint("Running MINIMAX")
182+
else: eprint("Running ALPHA-BETA")
183+
184+
if (caching == 1): eprint("State Caching is ON")
185+
else: eprint("State Caching is OFF")
186+
187+
if (ordering == 1): eprint("Node Ordering is ON")
188+
else: eprint("Node Ordering is OFF")
189+
190+
if (limit == -1): eprint("Depth Limit is OFF")
191+
else: eprint("Depth Limit is ", limit)
192+
193+
if (minimax == 1 and ordering == 1): eprint("Node Ordering should have no impact on Minimax")
194+
195+
while True: # This is the main loop
196+
# Read in the current game status, for example:
197+
# "SCORE 2 2" or "FINAL 33 31" if the game is over.
198+
# The first number is the score for player 1 (dark), the second for player 2 (light)
199+
next_input = input()
200+
status, dark_score_s, light_score_s = next_input.strip().split()
201+
dark_score = int(dark_score_s)
202+
light_score = int(light_score_s)
203+
204+
if status == "FINAL": # Game is over.
205+
print
206+
else:
207+
board = eval(input()) # Read in the input and turn it into a Python
208+
# object. The format is a list of rows. The
209+
# squares in each row are represented by
210+
# 0 : empty square
211+
# 1 : dark disk (player 1)
212+
# 2 : light disk (player 2)
213+
214+
# Select the move and send it to the manager
215+
if (minimax == 1): #run this if the minimax flag is given
216+
movei, movej = select_move_minimax(board, color, limit, caching)
217+
else: #else run alphabeta
218+
movei, movej = select_move_alphabeta(board, color, limit, caching, ordering)
219+
220+
print("{} {}".format(movei, movej))
221+
222+
if __name__ == "__main__":
223+
run_ai()

__pycache__/agent.cpython-38.pyc

6.46 KB
Binary file not shown.
5.34 KB
Binary file not shown.
1.89 KB
Binary file not shown.

0 commit comments

Comments
 (0)