Strategická: Komentáře a chyby v češtině
This commit is contained in:
		
							parent
							
								
									de72cb8499
								
							
						
					
					
						commit
						276c55531f
					
				
					 2 changed files with 49 additions and 49 deletions
				
			
		|  | @ -14,13 +14,13 @@ from typing import List, Optional, Tuple | |||
| 
 | ||||
| parser = argparse.ArgumentParser() | ||||
| parser.add_argument("--token", type=str, required=True, help="API token.") | ||||
| parser.add_argument("--server", type=str, default="http://localhost:5000", help="Server address.") | ||||
| parser.add_argument("--game", type=str, default="main", help="'main' or 'test_#'.") | ||||
| parser.add_argument("--command", type=str, nargs="+", default=["python3", "%"], help="Command to execute as strategy code. Use '%' for program.") | ||||
| parser.add_argument("--program", type=str, default=None, help="Program to substitute to command.") | ||||
| parser.add_argument("--copy", default=False, action="store_true", help="Save a copy of the program to ensure the same code is used all the time.") | ||||
| parser.add_argument("--server", type=str, default="http://localhost:5000", help="Adresa severu.") | ||||
| parser.add_argument("--game", type=str, default="main", help="'main' nebo 'test_#'.") | ||||
| parser.add_argument("--command", type=str, nargs="+", default=["python3", "%"], help="Příkaz pro spuštění strategie. '%' bude nahrazeno programem.") | ||||
| parser.add_argument("--program", type=str, default="play.py", help="Program, který má být použít v příkazu.") | ||||
| parser.add_argument("--copy", default=False, action="store_true", help="Vyrob kopii souboru, aby se vždy použil stejný kód.") | ||||
| parser.add_argument("--log-level", type=str, default="info", choices=["error", "warning", "info"]) | ||||
| parser.add_argument("--save-state", type=str, default=None, help="Save state to this file.") | ||||
| parser.add_argument("--save-state", type=str, default=None, help="Pouze ulož herní info do souboru.") | ||||
| 
 | ||||
| 
 | ||||
| TIME_BEFORE_RETRY = 2.0 | ||||
|  | @ -38,7 +38,7 @@ def main(args: argparse.Namespace) -> None: | |||
|         state = get_state(min_round, args) | ||||
|         round = state["round"] | ||||
|         min_round = round + 1 | ||||
|         # if requested, dump state to file instead | ||||
|         # ulož herní stav a ukonči program | ||||
|         if args.save_state is not None: | ||||
|             if args.save_state == "-": | ||||
|                 print(json.dumps(state)) | ||||
|  | @ -55,7 +55,7 @@ def main(args: argparse.Namespace) -> None: | |||
|         try: | ||||
|             turn = json.loads(turn_json) | ||||
|         except json.JSONDecodeError: | ||||
|             logger.error(f"Invalid JSON returned by strategy code.") | ||||
|             logger.error(f"Strategie vypsala nevalidní JSON.") | ||||
|             sys.exit(1) | ||||
| 
 | ||||
|         send_turn(turn, round, args) | ||||
|  | @ -63,7 +63,7 @@ def main(args: argparse.Namespace) -> None: | |||
| 
 | ||||
| def get_command(args) -> List[str]: | ||||
|     if args.program is None: | ||||
|         logger.error("Program not specified.") | ||||
|         logger.error("Specifikuj program.") | ||||
|         sys.exit(1) | ||||
| 
 | ||||
|     program = os.path.realpath(args.program) | ||||
|  | @ -80,7 +80,7 @@ def get_command(args) -> List[str]: | |||
| def run_subprocess( | ||||
|     command: List[str], state_json: str, timeout: Optional[int] | ||||
| ) -> Optional[str]: | ||||
|     """Run user program and return its output.""" | ||||
|     """Spusť strategii a vypiš její výstup.""" | ||||
| 
 | ||||
|     proc = Popen(command, encoding="utf-8", | ||||
|                  stdin=PIPE, stdout=PIPE, stderr=PIPE) | ||||
|  | @ -88,20 +88,22 @@ def run_subprocess( | |||
|         stdout, stderr = proc.communicate(input=state_json, timeout=timeout) | ||||
|     except TimeoutExpired: | ||||
|         proc.kill() | ||||
|         logger.error("Strategy code took too long.") | ||||
|         logger.error("Strategie se počítala příliš dlouho.") | ||||
|         return None | ||||
|     if stderr: | ||||
|         logger.error(f"Strategy code stderr:\n{stderr}") | ||||
|         logger.error(f"Chybový výstup strategie:\n{stderr}") | ||||
|     if proc.returncode != 0: | ||||
|         logger.error("Strategy code exited with non-zero exit code.") | ||||
|         logger.error("Strategie skončila s chybovým návratovým kódem.") | ||||
|         sys.exit(1) | ||||
|     return stdout | ||||
| 
 | ||||
| 
 | ||||
| def get_state(min_round: int, args) -> dict: | ||||
|     """Iteratively try to get game data from the server.""" | ||||
|     """Opakovaně se pokus získat herní data ze serveru.""" | ||||
| 
 | ||||
|     def get_state_once() -> Tuple[Optional[dict], float]: | ||||
|         """Vrací stav případě úspěchu, jinak None a dobu čekání.""" | ||||
| 
 | ||||
|         try: | ||||
|             res = requests.get(f"{args.server}/api/state", params={ | ||||
|                 "game": args.game, | ||||
|  | @ -109,8 +111,8 @@ def get_state(min_round: int, args) -> dict: | |||
|                 "min_round": min_round | ||||
|             }) | ||||
|         except requests.exceptions.RequestException as e: | ||||
|             # server might be down, retry later | ||||
|             logger.warning(f"Request error: {e}") | ||||
|             # server mohl vypadnout, zkus to znovu později | ||||
|             logger.warning(f"Chyba při dotazu na stav: {e}") | ||||
|             return None, TIME_BEFORE_RETRY | ||||
|         if not res.ok: | ||||
|             log_server_error(res) | ||||
|  | @ -118,14 +120,14 @@ def get_state(min_round: int, args) -> dict: | |||
| 
 | ||||
|         state = res.json() | ||||
|         if state["status"] == "ok": | ||||
|             logger.info("Received new state.") | ||||
|             logger.info("Nový stav obdržen.") | ||||
|             return state, 0 | ||||
| 
 | ||||
|         # retry after some time | ||||
|         # musíme chvíli počkat | ||||
|         if state["status"] == "waiting": | ||||
|             logger.info("Server is busy.") | ||||
|             logger.info("Server počítá.") | ||||
|         if state["status"] == "too_early": | ||||
|             logger.info("Round didn't start yet.") | ||||
|             logger.info("Kolo ještě nezačalo.") | ||||
|         return None, state["wait"] | ||||
| 
 | ||||
|     state, wait_time = get_state_once() | ||||
|  | @ -136,10 +138,10 @@ def get_state(min_round: int, args) -> dict: | |||
| 
 | ||||
| 
 | ||||
| def send_turn(turn: dict, round: int, args) -> None: | ||||
|     """Iteratively try to send turn to the server.""" | ||||
|     """Opakovaně se pokus poslat tah na server.""" | ||||
| 
 | ||||
|     def send_turn_once() -> bool: | ||||
|         """Returns True if server answered.""" | ||||
|         """Vrací True pokud server odpověděl.""" | ||||
| 
 | ||||
|         try: | ||||
|             res = requests.post( | ||||
|  | @ -152,30 +154,30 @@ def send_turn(turn: dict, round: int, args) -> None: | |||
|                 json=turn | ||||
|             ) | ||||
|         except requests.exceptions.RequestException as e: | ||||
|             # server might be down, retry later | ||||
|             logger.warning(f"Request error: {e}") | ||||
|             # server mohl vypadnout, zkus to znovu později | ||||
|             logger.warning(f"Chyba při posílání tahu: {e}") | ||||
|             return False | ||||
|         if not res.ok: | ||||
|             log_server_error(res) | ||||
|             sys.exit(1) | ||||
| 
 | ||||
|         # print errors | ||||
|         # because such errors are caused by the submitted turn, | ||||
|         # retrying will not help, so return True | ||||
|         # vypiš chyby | ||||
|         # tyto chyby jsou způsobeny špatným tahem, | ||||
|         # opakování požadavku nepomůže, takže vracíme True | ||||
|         res_json = res.json() | ||||
|         if res_json["status"] == "ok": | ||||
|             logger.info("Turn accepted.") | ||||
|             logger.info("Tah úspěšně přijat.") | ||||
|         elif res_json["status"] == "too_late": | ||||
|             logger.error("Turn submitted too late.") | ||||
|             logger.error("Tah poslán příliš pozdě.") | ||||
|         elif res_json["status"] == "error": | ||||
|             logger.error(f"Turn error: {res_json['description']}") | ||||
|             logger.error(f"Chyba v tahu: {res_json['description']}") | ||||
|         elif res_json["status"] == "warning": | ||||
|             member_warns = "\n".join([ | ||||
|                 f"    {member['id']}: {member['description']}" | ||||
|                 for member in res_json["members"] | ||||
|             ]) | ||||
|             logger.info("Turn accepted with warnings.") | ||||
|             logger.warning(f"Member warnings:\n{member_warns}") | ||||
|             logger.info("Tah přijat s varováními.") | ||||
|             logger.warning(f"Varování pro vojáky:\n{member_warns}") | ||||
|         return True | ||||
| 
 | ||||
|     while not send_turn_once(): | ||||
|  | @ -185,7 +187,7 @@ def send_turn(turn: dict, round: int, args) -> None: | |||
| def log_server_error(res: requests.Response) -> None: | ||||
|     res_json = res.json() | ||||
|     logger.error( | ||||
|         f"Server error: {res.status_code} {res.reason}: " | ||||
|         f"Chyba serveru: {res.status_code} {res.reason}: " | ||||
|         f"{res_json['description']}" | ||||
|     ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,12 +17,12 @@ class Direction(enum.Enum): | |||
|     STAY = None | ||||
| 
 | ||||
|     def combine(self, other) -> Direction: | ||||
|         """Rotate by another direction.""" | ||||
|         """Otoč směr podle jiného otočení.""" | ||||
| 
 | ||||
|         return Direction((self.value + other.value) % 4) | ||||
| 
 | ||||
|     def invert(self) -> Direction: | ||||
|         """Get the opposite direction.""" | ||||
|         """Získej opačný směr.""" | ||||
| 
 | ||||
|         if self == Direction.STAY: | ||||
|             return self | ||||
|  | @ -82,7 +82,7 @@ class Field: | |||
|         return hash((self.i, self.j)) | ||||
| 
 | ||||
|     def get_neighbour_field(self, direction: Direction) -> Field: | ||||
|         """Get the next field in the given direction.""" | ||||
|         """Další políčko v daném směru.""" | ||||
| 
 | ||||
|         if direction == Direction.UP: | ||||
|             neighbour_i = self.i - 1 | ||||
|  | @ -99,7 +99,7 @@ class Field: | |||
|         else: | ||||
|             neighbour_i = self.i | ||||
|             neighbour_j = self.j | ||||
|         # ensure coords are in bounds | ||||
|         # zajisti, aby souřadnice byly v rozsahu herní plochy | ||||
|         neighbour_i %= len(state.world) | ||||
|         neighbour_j %= len(state.world[0]) | ||||
|         return state.world[neighbour_i][neighbour_j] | ||||
|  | @ -116,10 +116,7 @@ class Field: | |||
| 
 | ||||
| 
 | ||||
| class State: | ||||
|     """The entire game state. | ||||
| 
 | ||||
|     Also contains methods for parsing and actions submission. | ||||
|     """ | ||||
|     """Celý herní stav včetně parsování a vypisování.""" | ||||
| 
 | ||||
|     def __init__(self, state: dict) -> None: | ||||
|         self.teams = [Team(i, i == state["team_id"]) | ||||
|  | @ -167,13 +164,13 @@ class State: | |||
|         return fields | ||||
| 
 | ||||
|     def build_turn(self) -> dict: | ||||
|         """Build a dictionary with member actions.""" | ||||
|         """Získej slovník s příkazy pro server.""" | ||||
| 
 | ||||
|         for team in self.teams: | ||||
|             if not team.is_me: | ||||
|                 for member in team.members: | ||||
|                     if member.action is not Direction.STAY: | ||||
|                         raise Exception("Akce přiřazena cizímu týmu") | ||||
|                         raise Exception("Akce přiřazena cizímu týmu.") | ||||
|         return { | ||||
|             "members": [ | ||||
|                 {"id": member.id, "action": str(member.action)} | ||||
|  | @ -188,7 +185,7 @@ state: State | |||
| 
 | ||||
| 
 | ||||
| def find_fields(predicate: Callable[[Field], bool]) -> List[Field]: | ||||
|     """Find all fields that satisfy the given predicate.""" | ||||
|     """Najdi políčka splňující danou podmínku.""" | ||||
| 
 | ||||
|     result = [] | ||||
|     for row in state.world: | ||||
|  | @ -199,14 +196,15 @@ def find_fields(predicate: Callable[[Field], bool]) -> List[Field]: | |||
| 
 | ||||
| 
 | ||||
| def pathfind(member: Member, goal: Field) -> Direction: | ||||
|     """Find the shortest path from member position to goal. | ||||
|     """Najdi nejkratší cestu od vojáka k cílovému políčku. | ||||
| 
 | ||||
|     Returns the first direction to go in. | ||||
|     If there is no path, returns STAY. | ||||
|     Vrátí první krok, který má voják udělat. | ||||
|     Pokud žádná cesta neexistuje, vrátí STAY. | ||||
|     """ | ||||
| 
 | ||||
|     # BFS from goal to member | ||||
|     # this direction makes it easier to realize that no path exists | ||||
|     # BFS od cíle k vojákovi | ||||
|     # tento směr umožní rychle zjistit, že cesta neexistuje, | ||||
|     # a také jednoduše získat první krok | ||||
|     explored: Set[Field] = set() | ||||
|     queue = collections.deque([goal]) | ||||
|     while queue: | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue