Strategická: Progress herní logiky
Zatím JEN WIP, není to hotové
This commit is contained in:
		
							parent
							
								
									a2ca047f55
								
							
						
					
					
						commit
						cf6377b21b
					
				
					 1 changed files with 230 additions and 1 deletions
				
			
		|  | @ -26,6 +26,235 @@ class Logic: | |||
| 
 | ||||
| @add_logic | ||||
| class Occupy(Logic): | ||||
|     pass | ||||
|     MOVE_VECTORS = { | ||||
|         None: (0, 0), | ||||
|         "left": (0, -1), | ||||
|         "right": (0, 1), | ||||
|         "up": (-1, 0), | ||||
|         "down": (1, 0) | ||||
|     } | ||||
| 
 | ||||
|     def __init__(self, teams_count: int, configuration: Any): | ||||
|         super().__init__(teams_count, configuration) | ||||
|         self.teams_width = configuration["teams_width"] | ||||
|         self.teams_height = configuration["teams_height"] | ||||
|         assert(teams_count == self.teams_width * self.teams_height) | ||||
|         self.map_width = self.teams_width * configuration["width_per_team"] | ||||
|         self.map_height = self.teams_height * configuration["height_per_team"] | ||||
|      | ||||
|     def generate_soldier(self, team_id, soldier_id): | ||||
|         return { | ||||
|             "type": "soldier", | ||||
|             "team": team_id, | ||||
|             "id": soldier_id, | ||||
|             "remaining_rounds": 1 | ||||
|         } | ||||
|      | ||||
|     # Počáteční stav | ||||
|     def zero_state(self) -> Any: | ||||
|         # TODO: Zatím negeneruju "hills" | ||||
|         map = [ | ||||
|             [ | ||||
|                 { | ||||
|                     "home_for_team": None, | ||||
|                     "occupied_by_team": None, | ||||
|                     "hill": False, | ||||
|                     "members": [] | ||||
|                 } | ||||
|                 for _ in range(self.map_width) | ||||
|             ] | ||||
|             for _ in range(self.map_height) | ||||
|         ] | ||||
|         team_id = 0 | ||||
|         home_y = self.configuration["height_per_team"] // 2 | ||||
|         for _ in range(self.teams_height): | ||||
|             home_x = self.configuration["width_per_team"] // 2 | ||||
|             for _ in range(self.teams_width): | ||||
|                 map[home_y][home_x]["home_for_team"] = team_id | ||||
|                 map[home_y][home_x]["occupied_by_team"] = team_id | ||||
|                 map[home_y][home_x]["members"].append(self.generate_soldier(team_id, 0)) | ||||
|                 team_id += 1 | ||||
|                 home_x += self.configuration["width_per_team"] | ||||
|             home_y += self.configuration["height_per_team"] | ||||
|          | ||||
|         return {"map": map} | ||||
| 
 | ||||
|     # Zatím očekávám, že moves má takovéto prvky: | ||||
|     # { | ||||
|     #     team_id: <int> | ||||
|     #     members: [ | ||||
|     #         id: <int> | ||||
|     #         action: <Optional[str]> | ||||
|     #             # None -> čekej | ||||
|     #             # "left", "right", "up", "down" | ||||
|     #     ] | ||||
|     # } | ||||
|     # VALIDITU MOVES NEOVĚŘUJU | ||||
|     # Metoda funguje velmi primitivně po krocích: | ||||
|     # * zaznamená se poloha objektů na mapě | ||||
|     # * vojáky se pohne podle moves | ||||
|     # * přidají se vojáci v homes | ||||
|     # * odstraní se vojáci podle "soubojů" | ||||
|     # * vygeneruje se json se správnými hodnotami "occupied" a spočítá se skóre | ||||
|     def step(self, state: Any, moves: List[Optional[Any]], round_id: int) -> Tuple[Any, List[int]]: | ||||
|         # souřadnice IDs pro všechny týmy | ||||
|         id_positions = [{} for _ in range(self.teams_count)] | ||||
|         # pohyby IDs pro všechny týmy | ||||
|         id_moves = [{} for _ in range(self.teams_count)] | ||||
|         # všechna IDs týmů | ||||
|         all_ids = [[] for _ in range(self.teams_count)] | ||||
|         # nejvyšší ID každého týmu | ||||
|         highest_ids = [0] * self.teams_count | ||||
|         # homes jednotlivých týmů | ||||
|         home_positions = [None] * self.teams_count | ||||
| 
 | ||||
|         y = 0 | ||||
|         for row in state["map"]: | ||||
|             x = 0 | ||||
|             for field in row: | ||||
|                 if field["home_for_team"] is not None: | ||||
|                     home_positions[field["home_for_team"]] = [y, x] | ||||
|                 for member in field["members"]: | ||||
|                     highest_ids[member["team"]] = max(highest_ids[member["team"]], member["id"]) | ||||
|                     all_ids[member["team"]].append(member["id"]) | ||||
|                     id_positions[member["team"]][member["id"]] = [y, x] | ||||
|                     id_moves[member["team"]][member["id"]] = None | ||||
|                 x += 1 | ||||
|             y += 1 | ||||
| 
 | ||||
|         for move in moves: | ||||
|             team_id = move["team_id"] | ||||
|             for member in move["members"]: | ||||
|                 id_moves[team_id][member["id"]] = member["action"] | ||||
|          | ||||
|         # Místo mapy tabulka seznamů vojáků pro každý tým | ||||
|         soldier_lists = [ | ||||
|             [[[] for _ in range(self.teams_count)] for _ in range(self.map_width)] | ||||
|             for _ in range(self.map_height) | ||||
|         ] | ||||
|         for team_id in range(self.teams_count): | ||||
|             for soldier_id in all_ids[team_id]: | ||||
|                 move_vect = self.MOVE_VECTORS[id_moves[team_id][soldier_id]] | ||||
|                 new_y = (id_positions[team_id][soldier_id][0] + move_vect[0]) % self.map_height | ||||
|                 new_x = (id_positions[team_id][soldier_id][1] + move_vect[1]) % self.map_width | ||||
|                 soldier_lists[new_y][new_x][team_id].append(soldier_id) | ||||
|          | ||||
|         # Přidáme vojáky v homes: | ||||
|         for team_id in range(self.teams_count): | ||||
|             home_pos = home_positions[team_id] | ||||
|             soldier_lists[home_pos[0]][home_pos[1]][team_id].append(highest_ids[team_id] + 1) | ||||
| 
 | ||||
|         # Vojáci se pomlátí: | ||||
|         for y in range(self.map_height): | ||||
|             for x in range(self.map_width): | ||||
|                 team_strengths = [len(soldier_lists[y][x][tid]) for tid in range(self.teams_count)] | ||||
|                 team_strengths.sort() | ||||
|                 for tid in range(self.teams_count): | ||||
|                     soldier_lists[y][x][tid] = soldier_lists[y][x][tid][team_strengths[-2]:] | ||||
| 
 | ||||
|         # Vygenerujeme výsledek: | ||||
|         score = [0] * self.teams_count | ||||
|         new_map = [[] for _ in range(self.map_height)] | ||||
|         y = 0 | ||||
|         for row in state["map"]: | ||||
|             x = 0 | ||||
|             for field in row: | ||||
|                 new_field = { | ||||
|                     "home_for_team": field["home_for_team"], | ||||
|                     "occupied_by_team": field["occupied_by_team"], | ||||
|                     "hill": field["hill"], | ||||
|                     "members": [] | ||||
|                 } | ||||
|                 for team_id in range(self.teams_count): | ||||
|                     for soldier_id in soldier_lists[y][x][team_id]: | ||||
|                         new_field["members"].append(self.generate_soldier(team_id, soldier_id)) | ||||
|                         new_field["occupied_by_team"] = team_id | ||||
|                 if new_field["occupied_by_team"] is not None: | ||||
|                     score[new_field["occupied_by_team"]] += 1 | ||||
|                 new_map[y].append(new_field) | ||||
|                 x += 1 | ||||
|             y += 1 | ||||
|         return ({"map": new_map}, score) | ||||
|      | ||||
|     def generate_warn(self, member_id, description): | ||||
|         return { | ||||
|             "id": member_id, | ||||
|             "description": description | ||||
|         } | ||||
| 
 | ||||
|     # Předpokládám validní `state`, vadit může | ||||
|     # * "hill" | ||||
|     # * nevalidní ID | ||||
|     # * více tahů jedním soldierem | ||||
|     def validate_move(self, state: Any, team_id: int, move: Any, round_id: int) -> Union[None, Any]: | ||||
|         # nakumulované warningy | ||||
|         warns = [] | ||||
|         # souřadnice IDs daného týmu | ||||
|         id_positions = {} | ||||
|         # 2D array s `True`s tam, kde je hill | ||||
|         hills = [[False] * self.map_width for _ in range(self.map_height)] | ||||
|         # ID soldierů, se kterými tým už hnul | ||||
|         ids_moved = {} | ||||
| 
 | ||||
|         y = 0 | ||||
|         for row in state["map"]: | ||||
|             x = 0 | ||||
|             for field in row: | ||||
|                 hills[y][x] = field["hill"] | ||||
|                 for member in field["members"]: | ||||
|                     if member["team"] != team_id: | ||||
|                         continue | ||||
|                     id_positions[member["id"]] = [y, x] | ||||
|                 x += 1 | ||||
|             y += 1 | ||||
|          | ||||
|         for member in move["members"]: | ||||
|             if member["id"] not in id_positions: | ||||
|                 warns.append(self.generate_warn(member["id"], "Neplatné ID!")) | ||||
|                 continue | ||||
|             if member["id"] in ids_moved: | ||||
|                 warns.append(self.generate_warn(member["id"], "Duplicitní pohyb vojákem. Jen jeho poslední pohyb se počítá.")) | ||||
|                 continue | ||||
|             ids_moved[member["id"]] = True | ||||
|             if member["action"] is None: | ||||
|                 continue | ||||
|             move_vect = self.MOVE_VECTORS[member["action"]] | ||||
|             new_position_y = id_positions[member["id"]][0] + move_vect[0] | ||||
|             new_position_x = id_positions[member["id"]][1] + move_vect[1] | ||||
|             if hills[new_position_y][new_position_x]: | ||||
|                 warns.append(self.generate_warn(member["id"], "Voják se snaží vylézt na skálu, což nejde.")) | ||||
|          | ||||
|         if len(warns) == 0: | ||||
|             return None | ||||
|         else: | ||||
|             return {"status": "warning", "members": warns} | ||||
| 
 | ||||
|     def home_position(self, state: Any, team_id): | ||||
|         y = 0 | ||||
|         for row in state["map"]: | ||||
|             x = 0 | ||||
|             for field in row: | ||||
|                 if field["home_for_team"] == team_id: | ||||
|                     return [y, x] | ||||
|                 x += 1 | ||||
|             y += 1 | ||||
| 
 | ||||
|     # Akorát vycentruju home týmu. | ||||
|     # TODO: Chceme přečíslovat týmy ("můj tým je vždy 0")? | ||||
|     def personalize_state(self, state: Any, team_id: int, round_id: int) -> Any: | ||||
|         # Zjisti pozici domečku tohoto týmu: | ||||
|         home_yx = self.home_position(state, team_id) | ||||
|         y_diff = (self.map_height // 2) - home_yx[0] | ||||
|         x_diff = (self.map_width // 2) - home_yx[1] | ||||
| 
 | ||||
|         # Vycentruj: | ||||
|         map_personalized = [ | ||||
|             [ | ||||
|                 state["map"][(y - y_diff) % self.map_height][(x - x_diff) % self.map_width] | ||||
|                 for x in range(self.map_width) | ||||
|             ] | ||||
|             for y in range(self.map_height) | ||||
|         ] | ||||
|          | ||||
|         return {"map": map_personalized} | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Martin Koreček
						Martin Koreček