|
1 | 1 | # Ben-Ryder 2019
|
2 |
| - |
| 2 | +import math |
3 | 3 | import random
|
4 | 4 | import paths
|
5 | 5 | import constants
|
6 | 6 |
|
7 | 7 | import project.game.calculations as calculations
|
| 8 | +import project.game.shortest_path as shortest_path |
8 | 9 |
|
9 | 10 |
|
10 | 11 | class Model:
|
@@ -329,59 +330,94 @@ class ComputerPlayer(Player):
|
329 | 330 | def __init__(self, model_link, save_data):
|
330 | 331 | super().__init__(model_link, save_data)
|
331 | 332 |
|
332 |
| - def take_go(self, ): |
333 |
| - self.model_link.get_current_player().start_turn() |
| 333 | + def take_go(self): |
| 334 | + self.start_turn() |
334 | 335 |
|
335 |
| - self.handle_cities() |
336 | 336 | self.handle_units()
|
| 337 | + self.handle_cities() |
337 | 338 |
|
338 |
| - self.model_link.get_current_player().end_turn() |
| 339 | + self.end_turn() |
| 340 | + |
| 341 | + def handle_units(self): |
| 342 | + for unit in self.units: |
| 343 | + |
| 344 | + # Conquer: conquer a city if possible. |
| 345 | + if self.model_link.check_conquer(unit): |
| 346 | + self.model_link.conquer(unit.position) |
| 347 | + else: |
| 348 | + # Movement: move into an enemy/unoccupied city, or move closer to one. |
| 349 | + all_moves = self.model_link.get_moves(unit) |
| 350 | + cities = [] |
| 351 | + for position in all_moves: |
| 352 | + tile = self.model_link.world.get_tile(position) |
| 353 | + if tile.get_type() == "c" and tile.get_holder() != self.get_name(): |
| 354 | + cities.append(position) |
| 355 | + |
| 356 | + if len(cities) > 0: # can move into enemy/unoccupied city |
| 357 | + city_position = random.choice(cities) |
| 358 | + self.model_link.move_unit(city_position, unit) |
| 359 | + else: |
| 360 | + # Getting all enemy/unoccupied cities |
| 361 | + all_cities = [] |
| 362 | + for row in self.model_link.world.tiles: |
| 363 | + for tile in row: |
| 364 | + if tile.get_type() == "c" and tile.get_holder() != self.get_name(): |
| 365 | + all_cities.append(tile.get_position()) |
| 366 | + |
| 367 | + # Getting closest city to the current player |
| 368 | + nearest_city = None |
| 369 | + nearest_city_heuristic = None |
| 370 | + for city_position in all_cities: |
| 371 | + x_distance = abs(unit.position[0] - city_position[0]) |
| 372 | + y_distance = abs(unit.position[1] - city_position[1]) |
| 373 | + heuristic = round(math.sqrt(x_distance ** 2 + y_distance ** 2)) |
| 374 | + |
| 375 | + if nearest_city is None: |
| 376 | + nearest_city = city_position |
| 377 | + nearest_city_heuristic = heuristic |
| 378 | + else: |
| 379 | + if heuristic < nearest_city_heuristic: |
| 380 | + nearest_city = city_position |
| 381 | + nearest_city_heuristic = heuristic |
| 382 | + |
| 383 | + # Getting shortest path to the city |
| 384 | + city_path = shortest_path.GridPath(self.model_link.world.get_format(), |
| 385 | + unit.position, nearest_city, |
| 386 | + constants.MAP_WALLS).get_path() |
| 387 | + # Moving first step of the path |
| 388 | + valid_city_path = [move for move in city_path if move in all_moves] |
| 389 | + |
| 390 | + if len(valid_city_path) > 0: |
| 391 | + self.model_link.move_unit(valid_city_path[0], unit) |
| 392 | + elif len(all_moves) > 0: |
| 393 | + random_move = random.choice(all_moves) |
| 394 | + self.model_link.move_unit(random_move, unit) |
| 395 | + |
| 396 | + # Attack: attack the weakest enemy unit in range. |
| 397 | + all_attacks = self.model_link.get_attacks(unit) |
| 398 | + if len(all_attacks) > 0: |
| 399 | + all_units = sorted( |
| 400 | + [self.model_link.get_unit(position) for position in all_attacks], |
| 401 | + key=lambda x: x.health) |
| 402 | + enemy_unit = all_units[0] # target the weakest enemy |
| 403 | + self.model_link.make_attack(unit, enemy_unit) |
339 | 404 |
|
340 | 405 | def handle_cities(self):
|
341 |
| - current_player = self.model_link.get_current_player() |
342 |
| - for city_position in current_player.settlements: |
343 |
| - # Spawning Units |
344 |
| - affordable_units = [name for name, values in constants.UNIT_SPECS.items() |
345 |
| - if current_player.get_ap() - values["spawn_cost"] >= 0] |
346 |
| - unit_choice = random.choice(affordable_units) |
| 406 | + # Upgrading Cities |
| 407 | + for city_position in self.settlements: |
| 408 | + city = self.model_link.world.get_tile(city_position) |
| 409 | + if city.can_upgrade(): |
| 410 | + city.add_sub_level() |
347 | 411 |
|
| 412 | + # Spawning Random Units |
| 413 | + for city_position in self.settlements: |
348 | 414 | city = self.model_link.world.get_tile(city_position)
|
349 |
| - self.model_link.try_spawn(unit_choice, city.get_position()) |
350 | 415 |
|
351 |
| - def handle_units(self): |
352 |
| - current_player = self.model_link.get_current_player() |
353 |
| - for unit in current_player.units: |
354 |
| - if False: # in city conquer it |
355 |
| - pass |
356 |
| - else: |
357 |
| - # breadth_search = breadth_first.BreadthSearch(model.world.get_format()) |
358 |
| - # |
359 |
| - # nearest_city = breadth_search.get_nearest(unit.position, "c") |
360 |
| - # path = shortest_path.GridPath( |
361 |
| - # model.world.get_format(), |
362 |
| - # unit.position, nearest_city, |
363 |
| - # walls=MAP_WALLS |
364 |
| - # ).get_path() |
365 |
| - # print(path) |
366 |
| - |
367 |
| - # See if unit can take a city |
368 |
| - if self.model_link.check_conquer(unit): |
369 |
| - self.model_link.conquer(unit.position) |
370 |
| - else: |
371 |
| - # Make Random Move |
372 |
| - all_moves = self.model_link.get_moves(unit) |
373 |
| - if len(all_moves) > 0: |
374 |
| - move = random.choice(all_moves) |
375 |
| - self.model_link.move_unit(move, unit) |
376 |
| - |
377 |
| - # Make Random Attack (if possible) |
378 |
| - all_attacks = self.model_link.get_attacks(unit) |
379 |
| - if len(all_attacks) > 0: |
380 |
| - all_units = sorted( |
381 |
| - [self.model_link.get_unit(position) for position in all_attacks], |
382 |
| - key=lambda x: x.health) |
383 |
| - enemy_unit = all_units[0] # target the weakest enemy |
384 |
| - self.model_link.make_attack(unit, enemy_unit) |
| 416 | + affordable_units = [name for name, values in constants.UNIT_SPECS.items() |
| 417 | + if self.get_ap() - values["spawn_cost"] >= 0] |
| 418 | + if len(affordable_units) > 0: |
| 419 | + unit_choice = random.choice(affordable_units) |
| 420 | + self.model_link.try_spawn(unit_choice, city.get_position()) |
385 | 421 |
|
386 | 422 |
|
387 | 423 | class Tile:
|
|
0 commit comments