-
Notifications
You must be signed in to change notification settings - Fork 0
/
romuald_clever.py
132 lines (104 loc) · 4.7 KB
/
romuald_clever.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# This bot looks one move ahead, and if possible it will make a move to
# block its opponent winning. Otherwise, it picks a move at random.
import copy
import random
from botany_connectfour import game
from collections import defaultdict
def cut_fn(x):
return (x[2],x[3],x[4])
def remaining_to_win(board,line,token):
line_string = "".join([board[l][r] for l,r in line])
if 'X' in line_string and 'O' in line_string:
return (5,token)
else:
letters = line_string.replace('.','')
letter = token
if len(letters)> 0:
letter = letters[0]
return (line_string.count('.') or 5,letter)
def get_letter_of_pos(position,board):
col, row = position
return board[col][row]
def get_traps(board,the_lines,best,token):
dict_traps = defaultdict(list)
for line in the_lines:
dict_traps[remaining_to_win(board,line,token)[0]].append(line)
if min(dict_traps.keys()) == 1:
return dict_traps[1]
output = list()
for i in [key for key in dict_traps.keys() if key<best]:
output += dict_traps[i]
return output
def get_his_deadly_traps(board,the_lines,best,the_toten):
traps = list()
for line in the_lines:
remaining, letter = remaining_to_win(board,line,the_toten)
if remaining == 1 and letter != the_toten:
traps.append(line)
return traps
def select_for_victory(board,outcome_assign,proposals,token):
for column,_,_,_,_ in proposals:
if outcome_assign.get(column) == token:
return column
return column
def get_next_move(board, token):
available_moves = game.available_moves(board)
available_position = [(a,board[a].index('.')) for a in available_moves]
available_play = available_position
if token == 'X':
other_token = 'O'
else:
other_token = 'X'
possible = [line for line in game.LINES_OF_4 if not set(available_position).isdisjoint(line)]
outcome = dict()
best = 5
for line in possible:
remaining, letter = remaining_to_win(board,line,token)
if remaining == 5:
continue
if best > remaining:
outcome = defaultdict(int)
outcome_assign = defaultdict()
best = remaining
if best == remaining:
the_moves = list(set(line) & set(available_play))
for move in the_moves:
outcome[move[0]] += 1
if letter == token:
outcome_assign[move[0]] = letter
#tuple number of line_4, row, cols
proposals = [(i,board[i].index('.'),0,0,j) for i,j in outcome.items()]
if best == 1:
return select_for_victory(board,outcome_assign,proposals,token)
traps = get_traps(board,game.LINES_OF_4,best,token)
#Do not fall in a trap.
proposals_minus_traps = [prop for prop in proposals if not any((prop[0],prop[1]+1) in trap for trap in traps)]
#We have a choice, let's see if we can set a trap
if len(proposals_minus_traps) > 1:
friendly_traps = get_his_deadly_traps(board,game.LINES_OF_4,best,other_token)
available_traps = set(pos for trap in friendly_traps for pos in trap if get_letter_of_pos(pos,board) == ".")
trap_columns = set(pos[0] for pos in available_traps)
the_existing = [e[0] for e in proposals_minus_traps if (e[0],e[1]) in available_traps]
board1 = copy.deepcopy(board)
improved_proposals = list()
for col,row,_,_,remaining in proposals_minus_traps:
board1[col][row] = token
new_friendly_traps = get_his_deadly_traps(board1,(traps+possible),best,other_token)
all_new_traps = set(pos for trap in new_friendly_traps for pos in trap if get_letter_of_pos(pos,board1) == ".")
new_traps = all_new_traps - available_traps
above_each_other = len([trap for trap in new_traps if trap[0] in trap_columns])
improved_proposals.append((col,row,above_each_other,len(new_traps),remaining))
board1[col][row] = '.'
if len(improved_proposals):
proposals_minus_traps = improved_proposals
outputs = [e[0] for e in proposals_minus_traps if cut_fn(e) == max(cut_fn(x) for x in proposals_minus_traps)]
outputs = outputs or [avail[0] for avail in available_play if not any((avail[0],avail[1]+1) in trap for trap in traps)]
if len(outputs) == 0:
deadly_traps = get_his_deadly_traps(board,game.LINES_OF_4,best,token)
outputs = [avail[0] for avail in available_play if not any((avail[0],avail[1]+1) in trap for trap in deadly_traps)]
outputs = outputs or available_moves
try:
output = random.choice(outputs)
except:
output = random.choice(available_moves)
return output