forked from bcorfman/raven-checkers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
onekingattack.py
95 lines (76 loc) · 3.16 KB
/
onekingattack.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
from goal import Goal
from composite import CompositeGoal
class GoalOneKingAttack(CompositeGoal):
def __init__(self, owner):
CompositeGoal.__init__(self, owner)
def activate(self):
self.status = self.ACTIVE
self.remove_all_subgoals()
# because goals are *pushed* onto the front of the subgoal list they must
# be added in reverse order.
self.add_subgoal(GoalPinEnemy(self.owner))
self.add_subgoal(GoalMoveTowardEnemy(self.owner))
def process(self):
self.activate_if_inactive()
return self.process_subgoals()
def terminate(self):
self.status = self.INACTIVE
class GoalMoveTowardEnemy(Goal):
def __init__(self, owner):
Goal.__init__(self, owner)
def activate(self):
self.status = self.ACTIVE
def process(self):
# if status is inactive, activate
self.activate_if_inactive()
# only moves (not captures) are a valid goal
if self.owner.captures:
self.status = self.FAILED
return
# identify player king and enemy king
plr_color = self.owner.to_move
enemy_color = self.owner.enemy
player = self.owner.get_pieces(plr_color)[0]
p_idx, _ = player
p_row, p_col = self.owner.row_col_for_index(p_idx)
enemy = self.owner.get_pieces(enemy_color)[0]
e_idx, _ = enemy
e_row, e_col = self.owner.row_col_for_index(e_idx)
# if distance between player and enemy is already down
# to 2 rows or 2 cols, then goal is complete.
if ((abs(p_row - e_row) == 2 and abs(p_col - e_col) == 0) or
(abs(p_row - e_row) == 0 and abs(p_col - e_col) == 2)):
self.status = self.COMPLETED
# select the available move that decreases the distance
# between the player and the enemy. If no such move exists,
# the goal has failed.
good_move = None
for m in self.owner.moves:
# try a move and gather the new row & col for the player
self.owner.make_move(m, False, False)
plr_update = self.owner.get_pieces(plr_color)[0]
pu_idx, _ = plr_update
pu_row, pu_col = self.owner.row_col_for_index(pu_idx)
self.owner.undo_move(m, False, False)
new_diff = abs(pu_row - e_row) + abs(pu_col - e_col)
old_diff = abs(p_row - e_row) + abs(p_col - e_col)
if new_diff < old_diff:
good_move = m
break
if good_move:
self.owner.make_move(good_move, True, True)
else:
self.status = self.FAILED
def terminate(self):
self.status = self.INACTIVE
class GoalPinEnemy(Goal):
def __init__(self, owner):
Goal.__init__(self, owner)
def activate(self):
self.status = self.ACTIVE
def process(self):
# for now, I'm not even sure I need this goal, but I'm saving it
# as a placeholder.
self.status = self.COMPLETED
def terminate(self):
self.status = self.INACTIVE