diff --git a/README.md b/README.md index d6ebd3d..38cd858 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,16 @@ You can then run it (assuming the simulation is already running in another termi ``` python socket_agent.py ``` + +### Running the simulation with Python agents that takes keyboard inputs + +Take a look at the "keyboard_agent.py" file which has an example of how to send keyboard input commands through a socket. + +``` + keyboard_agent.py +``` +A control display will pop up. Click on the display to focus on it and send keyboard commands. The program will convert the commands and send the action commands to the socket environment to carry out the game play. + ### Running the simulation with recorded action history Take a look at the "replay_agent_actions.py" file which has an example of how to send recorded commands from a file through a socket. diff --git a/keyboard_agent.py b/keyboard_agent.py new file mode 100644 index 0000000..ef846b5 --- /dev/null +++ b/keyboard_agent.py @@ -0,0 +1,88 @@ +# Author: Tia Chen +# Email: qingyan.chen@tufts.edu + +import argparse +import json +import socket +import pygame + +from utils import recv_socket_data + +def send_command(command): + print("Sending action: ", command) + sock_game.send(str.encode(command)) # send action to env + + output = recv_socket_data(sock_game) # get observation from env (wait for response before sending next command) + # output = json.loads(output) # Put back if you want to inspect received message + + # print("JSON: ", output) + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + + parser.add_argument( + 'player_id', + type=int, + help="Please provide the player id that you are playing for", + ) + args = parser.parse_args() + + action_commands = ['NOP', 'NORTH', 'SOUTH', 'EAST', 'WEST', 'TOGGLE_CART', 'INTERACT', 'CANCEL'] + + game_commands = ['ESCAPE', 'SAVE', 'TOGGLE_RECORD', 'PAUSE', 'REVERT'] + + print("action_commands: ", action_commands) + print("game_commands: ", game_commands) + + # Connect to Supermarket + HOST = '127.0.0.1' + PORT = 9000 + sock_game = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock_game.connect((HOST, PORT)) + + pygame.init() + + # Set up a display to accept keyboard command + screen_size = (400, 100) + screen = pygame.display.set_mode(screen_size) + pygame.display.set_caption("Control Display") + + running = True + while running: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + elif event.type == pygame.KEYDOWN: + # game events + if event.key == pygame.K_ESCAPE: + send_command('ESCAPE') + elif event.key == pygame.K_s: + send_command('SAVE') + elif event.key == pygame.K_r: + send_command('TOGGLE_RECORD') + elif event.key == pygame.K_p: + send_command('PAUSE') + elif event.key == pygame.K_z: + send_command('REVERT') + elif event.key == pygame.K_c: + send_command(str(args.player_id) + ' TOGGLE_CART') + elif event.key == pygame.K_RETURN: + send_command(str(args.player_id) + ' INTERACT') + elif event.key == pygame.K_b: + send_command(str(args.player_id) + ' CANCEL') + + + # Player events to send repeatedly to smooth transition + keys = pygame.key.get_pressed() + if keys[pygame.K_UP]: + send_command(str(args.player_id) + ' NORTH') + elif keys[pygame.K_DOWN]: + send_command(str(args.player_id) + ' SOUTH') + elif keys[pygame.K_LEFT]: + send_command(str(args.player_id) + ' WEST') + elif keys[pygame.K_RIGHT]: + send_command(str(args.player_id) + ' EAST') + + pygame.quit() + exit() \ No newline at end of file diff --git a/socket_env.py b/socket_env.py index 5349dde..c6c9a94 100755 --- a/socket_env.py +++ b/socket_env.py @@ -2,7 +2,6 @@ import argparse import datetime import json -from pprint import pprint import selectors import socket import types @@ -15,6 +14,8 @@ ACTION_COMMANDS = ['NOP', 'NORTH', 'SOUTH', 'EAST', 'WEST', 'INTERACT', 'TOGGLE_CART', 'CANCEL', 'SELECT','RESET'] +GAME_COMMANDS = ['ESCAPE', 'SAVE', 'TOGGLE_RECORD', 'PAUSE', 'REVERT'] + def serialize_data(data): if isinstance(data, set): return list(data) @@ -261,6 +262,20 @@ def get_action_json(action, env_, obs, reward, done, info_=None, violations=''): # action_json = {"hello": "world"} return action_json +def is_game_command(command_): + return command_ in GAME_COMMANDS + +def get_event(command_): + if command_ == 'ESCAPE': + return pygame.event.Event(pygame.KEYDOWN, key=pygame.K_ESCAPE) + elif command_ == 'SAVE': + return pygame.event.Event(pygame.KEYDOWN, key=pygame.K_s) + elif command_ == 'TOGGLE_RECORD': + return pygame.event.Event(pygame.KEYDOWN, key=pygame.K_r) + elif command_ == 'PAUSE': + return pygame.event.Event(pygame.KEYDOWN, key=pygame.K_p) + elif command_ == 'REVERT': + return pygame.event.Event(pygame.KEYDOWN, key=pygame.K_z) def is_single_player(command_): return ',' not in command_ @@ -449,7 +464,7 @@ def accept_wrapper(sock): curr_action = [(0,0)] * env.unwrapped.num_players e = [] if not args.headless: - handler.handle_events() # TIA TODO: INJECTION OF KEYBOARD COMMANDS + handler.handle_events() env.render() for key, mask in events: if key.data is None: @@ -474,6 +489,9 @@ def accept_wrapper(sock): data.outb = str.encode(json.dumps(json_to_send,default=lambda o: o.__dict__) + "\n") if is_playback_mode(command): env.unwrapped.game.is_playback = True + if is_game_command(command): + keydown_event = get_event(command) + pygame.event.post(keydown_event) if is_single_player(command): player, command, arg = get_player_and_command(command) e.append((key, mask, command))