-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcombat.py
More file actions
154 lines (122 loc) · 5.18 KB
/
combat.py
File metadata and controls
154 lines (122 loc) · 5.18 KB
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import random
from typing import List, Tuple
import numpy as np
from world import World
class Combat:
destination: int
player_health: int
player_max_health: int
enemy_health: int
enemy_max_health: int
is_boss: bool
last_outcome: str
enemy_strategy: str
history: List[Tuple[int, int, str]]
heals_remaining: int
added_heal: bool
def __init__(self) -> None:
self.player_health = 100
self.player_max_health = 100
self.enemy_health = 100
self.enemy_max_health = 100
self.is_boss = False
self.destination = -1
self.last_outcome = "none"
self.enemy_strategy = "random"
self.heals_remaining = 5
self.added_heal = False
self.history = []
def battle_started(self, location: int, destination: int, world: World) -> None:
self.is_boss = world.cities.goal_city == destination
if world != None:
self.enemy_health = self.calculate_enemy_health(location, destination, world)
else: # for simulating without a full game state in the neural network training
self.enemy_health = 100
self.enemy_max_health = self.enemy_health
self.history = []
self.enemy_strategy = random.choice(["stubborn", "antsy", "schemer", "skipper"])
self.destination = destination
self.player_health = self.player_max_health
def calculate_enemy_health(self, city_1: int, city_2: int, world: World) -> int:
is_boss = world.cities.goal_city == city_2
city_1_pos = world.cities.cities[city_1].location
city_2_pos = world.cities.cities[city_2].location
number_of_points=30
xs=np.linspace(city_1_pos[0],city_2_pos[0],number_of_points+2)
ys=np.linspace(city_1_pos[1],city_2_pos[1],number_of_points+2)
total_elevation = 0
for i in range(len(xs)):
total_elevation += world.world_elevation[int(xs[i]), int(ys[i])]
distance = ((city_1_pos[0] - city_2_pos[0]) ** 2 + (city_1_pos[1] - city_2_pos[1]) ** 2) ** 0.5
if is_boss:
return 500 + int(total_elevation * 20)
else:
return round(int(total_elevation) * (distance / 20))
def has_encounter(self, city_1: int, city_2: int, world: World) -> bool:
if city_1 == city_2:
return False
has_road = False
# if there is no route
for start, end, color in world.cities.routes:
if (start == city_1 and end == city_2) or (start == city_2 and end == city_1):
if city_2 != world.cities.goal_city:
has_road = True
break
return not has_road
def calculate_damage(self, health: int) -> int:
return health // 10
# if enemy_move is specified it lets you bypass the enemy move selector
def run_turn(self, player_move: int, enemy_move=None) -> Tuple[str, int, bool]:
outcome = ""
if enemy_move is None:
enemy_move = self.select_enemy_move()
if player_move == enemy_move:
outcome = "draw"
elif (player_move + 1) % 3 == enemy_move:
self.player_health -= self.calculate_damage(self.enemy_max_health)
outcome = "loss"
else:
self.enemy_health -= self.calculate_damage(self.player_max_health)
outcome = "win"
self.history.append((player_move, enemy_move, outcome))
self.last_outcome = outcome
self.added_heal = False
if self.player_health <= 0: # player loses
self.heals_remaining -= 1
elif self.enemy_health <= 0: # player wins
# handle healing
if random.randint(0, 2) == 0:
self.heals_remaining += 1
self.added_heal = True
# give health increase
self.player_max_health += self.enemy_max_health // 10
else:
return outcome, enemy_move, False
return outcome, enemy_move, True
def select_enemy_move(self) -> int:
if self.enemy_strategy == "stubborn": # picks an attack and uses it every time
if len(self.history) == 0:
return random.randint(0, 2)
else:
return self.history[-1][1]
elif self.enemy_strategy == "antsy": # changes move to the next one every turn
if len(self.history) == 0:
return random.randint(0, 2)
else:
return (self.history[-1][1] + 1) % 3
elif self.enemy_strategy == "schemer": # picks a move and uses it for 3 turns, before picking another move
if len(self.history) == 0:
return random.randint(0, 2)
else:
if len(self.history) % 3 == 0:
return random.randint(0, 2)
else:
return self.history[-1][1]
elif self.enemy_strategy == "skipper": # same as antsy, but skips a move
if len(self.history) == 0:
return random.randint(0, 2)
else:
return (self.history[-1][1] + 2) % 3
else:
print("Invalid attack pattern chosen:", self.enemy_strategy)
return 0