|
@ -13,13 +13,14 @@ from typing import List, Optional, Tuple |
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser() |
|
|
parser = argparse.ArgumentParser() |
|
|
parser.add_argument("--token", type=str, required=True, help="API token.") |
|
|
parser.add_argument("--token", type=str, required=True, help="API token.") |
|
|
parser.add_argument("--program", type=str, required=True, help="Program to run.") |
|
|
|
|
|
parser.add_argument("--server", type=str, default="http://localhost:5000", help="Server address.") |
|
|
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("--game", type=str, default="main", help="'main' or 'test_#'.") |
|
|
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("--command", type=str, nargs="+", default=["python3", "%"], help="Command to execute as strategy code. Use '%' for program.") |
|
|
parser.add_argument("--log-level", type=str, default="warning", choices=["error", "warning", "info"]) |
|
|
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("--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="Save state to this file.") |
|
|
# parser.add_argument("program", nargs=argparse.REMAINDER, help="Program to run.") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TIME_BEFORE_RETRY = 2.0 |
|
|
TIME_BEFORE_RETRY = 2.0 |
|
@ -29,12 +30,10 @@ logger = logging.getLogger("client") |
|
|
|
|
|
|
|
|
def main(args: argparse.Namespace) -> None: |
|
|
def main(args: argparse.Namespace) -> None: |
|
|
logger.setLevel(args.log_level.upper()) |
|
|
logger.setLevel(args.log_level.upper()) |
|
|
program = args.program |
|
|
|
|
|
if args.copy: |
|
|
|
|
|
program = tempfile.mktemp() |
|
|
|
|
|
shutil.copyfile(args.program, program) |
|
|
|
|
|
program = "./" + program |
|
|
|
|
|
min_round = 0 |
|
|
min_round = 0 |
|
|
|
|
|
program = None |
|
|
|
|
|
if args.save_state is None: |
|
|
|
|
|
program = get_command(args) |
|
|
|
|
|
|
|
|
while True: |
|
|
while True: |
|
|
state = get_state(min_round, args) |
|
|
state = get_state(min_round, args) |
|
@ -60,12 +59,28 @@ def main(args: argparse.Namespace) -> None: |
|
|
send_turn(turn, round, args) |
|
|
send_turn(turn, round, args) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_command(args) -> List[str]: |
|
|
|
|
|
if args.program is None: |
|
|
|
|
|
logger.error("Program not specified.") |
|
|
|
|
|
sys.exit(1) |
|
|
|
|
|
|
|
|
|
|
|
program = args.program |
|
|
|
|
|
if args.copy: |
|
|
|
|
|
program = tempfile.mktemp() |
|
|
|
|
|
shutil.copyfile(args.program, program) |
|
|
|
|
|
|
|
|
|
|
|
command: List[str] = [] |
|
|
|
|
|
for arg in args.command: |
|
|
|
|
|
command.append(arg.replace("%", program)) |
|
|
|
|
|
return command |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run_subprocess( |
|
|
def run_subprocess( |
|
|
program: str, state_json: str, timeout: Optional[float] |
|
|
command: List[str], state_json: str, timeout: Optional[float] |
|
|
) -> Optional[str]: |
|
|
) -> Optional[str]: |
|
|
"""Run user program and return its output.""" |
|
|
"""Run user program and return its output.""" |
|
|
|
|
|
|
|
|
proc = Popen([program], encoding="utf-8", |
|
|
proc = Popen(command, encoding="utf-8", |
|
|
stdin=PIPE, stdout=PIPE, stderr=PIPE) |
|
|
stdin=PIPE, stdout=PIPE, stderr=PIPE) |
|
|
try: |
|
|
try: |
|
|
stdout, stderr = proc.communicate(input=state_json, timeout=timeout) |
|
|
stdout, stderr = proc.communicate(input=state_json, timeout=timeout) |
|
|