diff --git a/gauss-turing/game/gauss_turing.py b/gauss-turing/game/gauss_turing.py index 0b8940d..038da06 100644 --- a/gauss-turing/game/gauss_turing.py +++ b/gauss-turing/game/gauss_turing.py @@ -2,11 +2,15 @@ import numpy as np import random import pygame import os +import threading + +from webapp import app from event_server_comm import move_grid BLACK = np.array([0, 0, 0], dtype=np.uint8) WHITE = np.array([255, 255, 255], dtype=np.uint8) +GRAY = np.array([200, 200, 200], dtype=np.uint8) RED = np.array([255, 0, 0], dtype=np.uint8) BLUE = np.array([0, 0, 255], dtype=np.uint8) YELLOW = np.array([255, 255, 0], dtype=np.uint8) @@ -26,7 +30,7 @@ tiledt = np.dtype([('x', np.uint8), ('y', np.uint8), ('color', np.uint8, 3), ('s class Board: - valid_colors = [WHITE, RED, BLUE] + valid_colors = [GRAY, RED, BLUE] def __init__(self, dim_x, dim_y): self.tiles = np.zeros((dim_y, dim_x), dtype=tiledt) @@ -80,11 +84,12 @@ class Robot: } - def __init__(self, x, y, orientation): + def __init__(self, x, y, orientation, use_real_robot=False): self.x = x self.y = y self.orientation = orientation self.position_changed = False + self.use_real_robot = use_real_robot def get_forward_coordinates(self): # get the coordinates of the neighboring tile in the given direction @@ -112,7 +117,8 @@ class Robot: return robot_surf def update_pos(self, dimx, dimy): - move_grid(self.x, self.y, self.orientation, dimx, dimy) + if self.use_real_robot: + move_grid(self.x, self.y, self.orientation, dimx, dimy) self.position_changed = False def __repr__(self): @@ -122,7 +128,7 @@ class Robot: class Command: valid_actions = {'forward', 'left', 'right', 'P0', '-'} - def __init__(self, action=None, color=WHITE): + def __init__(self, action=None, color=GRAY): if not (action in Command.valid_actions and any([np.all(color == c) for c in Board.valid_colors])): raise ValueError("invalid values for command") self.action = action @@ -157,7 +163,7 @@ class Programmer: def __init__(self, prg): self.prg = prg self.available_inputs = [Command('forward'), Command('left'), Command('right'), Command('P0'), - Command('-', color=RED), Command('-', color=BLUE), Command('-', color=WHITE)] + Command('-', color=RED), Command('-', color=BLUE), Command('-', color=GRAY)] self.command_to_edit = 0 self.screen_rect = None @@ -196,6 +202,8 @@ class Program: self.screen_rect = None def step(self, state='running'): + if self.prg_counter >= len(self.cmds): + return 'game_over' cmd = self.cmds[self.prg_counter] self.prg_counter += 1 @@ -207,7 +215,7 @@ class Program: tile = self.board.tiles[y, x] # apply next instruction of the program - if np.all(cmd.color == WHITE) or np.all(cmd.color == tile['color']): + if np.all(cmd.color == GRAY) or np.all(cmd.color == tile['color']): # matching color -> execute command if cmd.action == 'forward': ynew, xnew = self.robot.get_forward_coordinates() @@ -264,7 +272,7 @@ class Program: cmd_surf = cmd.render(scale_fac) else: cmd_surf = pygame.Surface((scale_fac,scale_fac)) - cmd_surf.fill(WHITE) + cmd_surf.fill(GRAY) if prg_counter is not None and i == prg_counter: pygame.draw.rect(cmd_surf, tuple(GREEN), (0, 0, scale_fac, scale_fac), 5) prg_surf.blit(cmd_surf, (i * scale_fac, 0, scale_fac, scale_fac)) @@ -280,8 +288,8 @@ class Program: class Game: - def __init__(self, dimx, dimy, robotx, roboty): - self.robot = Robot(x=robotx, y=roboty, orientation='v') + def __init__(self, dimx, dimy, robotx, roboty, use_real_robot=False): + self.robot = Robot(x=robotx, y=roboty, orientation='v', use_real_robot=use_real_robot) self.board = Board(dimx, dimy) coin1x = np.random.randint(0, dimx) coin1y = np.random.randint(0, dimy) @@ -290,7 +298,7 @@ class Game: # TODO fix number of commands at 5 self.cmds = [Command('forward'), Command('left', color=RED), Command('left', color=BLUE), Command('P0'), Command('-')] - self.state = 'won' + self.state = 'reset' self.prg = Program(self.robot, self.board, self.cmds) @@ -450,6 +458,12 @@ class Game: self.state = self.prg.step(self.state) elif event.key == pygame.K_r: self.state = 'reset' + elif event.type == pygame.USEREVENT: + for i, cmd in enumerate(event.cmds): + self.cmds[i].action = cmd.action + self.cmds[i].color = np.array(cmd.color, dtype=np.uint8) + self.reset() + self.state = 'running' return self.state def reset(self): @@ -488,10 +502,14 @@ class Game: pygame.time.wait(100) if __name__ == "__main__": + # launch webapp in thread + webserver_thread = threading.Thread(target=app.run, kwargs={'host': '0.0.0.0', 'port': 5000}) + webserver_thread.start() + seed = 2 random.seed(seed) np.random.seed(seed) - game = Game(dimx=7, dimy=4, robotx=3, roboty=1) + game = Game(dimx=7, dimy=4, robotx=3, roboty=1, use_real_robot=False) game.run() # TODOs diff --git a/gauss-turing/game/static/-.png b/gauss-turing/game/static/-.png new file mode 100644 index 0000000..493483d Binary files /dev/null and b/gauss-turing/game/static/-.png differ diff --git a/gauss-turing/game/static/P0.png b/gauss-turing/game/static/P0.png new file mode 100644 index 0000000..62536c9 Binary files /dev/null and b/gauss-turing/game/static/P0.png differ diff --git a/gauss-turing/game/static/forward.png b/gauss-turing/game/static/forward.png new file mode 100644 index 0000000..101422c Binary files /dev/null and b/gauss-turing/game/static/forward.png differ diff --git a/gauss-turing/game/static/left.png b/gauss-turing/game/static/left.png new file mode 100644 index 0000000..66ef652 Binary files /dev/null and b/gauss-turing/game/static/left.png differ diff --git a/gauss-turing/game/static/right.png b/gauss-turing/game/static/right.png new file mode 100644 index 0000000..8ade14b Binary files /dev/null and b/gauss-turing/game/static/right.png differ diff --git a/gauss-turing/game/static/style.css b/gauss-turing/game/static/style.css new file mode 100644 index 0000000..e597446 --- /dev/null +++ b/gauss-turing/game/static/style.css @@ -0,0 +1,105 @@ +.main-canvas { + outline: 1px solid #dddddd;; + width: 500px; + height: 220px; + margin: 50px auto 0; + position: relative; +} + +.register { + outline: 3px dashed #dddddd;; + width: 120px; + height: 240px; + margin: 0px auto 0; + position: relative; +} + +.box{ + width: 62px; + height: 100px; + position: absolute !important; + top: 100px; + font-size: 15px; + color: #ffffff; + line-height: 25px; + text-align: center; + cursor: move; +} + +.robotOrientation { + width: 75px; + height: 75px; +} + +.robotOrientation90 { + width: 75px; + height: 75px; + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} + +.robotOrientation180 { + width: 75px; + height: 75px; + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} + +.robotOrientation270 { + width: 75px; + height: 75px; + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -o-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} + +.rotate90 { + width: 100px; + height: 100px; + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} + +.rotate180 { + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} + +.rotate270 { + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -o-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} + +.top-buffer { margin-top:20px; } + + +.card0 { left: 0; top: 0; background-color: #E74C3C; position: absolute !important; +} +.card1 { left: 100px; top: 0; background-color: #8E44AD; position: absolute !important; +} +.card2 { left: 200px; top: 0; background-color: #5DADE2; } +.card3 { left: 300px; top: 0; background-color: #1ABC9C; } +.card4 { left: 400px; top: 0; background-color: #F1C40F; } +.card5 { left: 50px; top: 120px; background-color: #F39C12; } +.card6 { left: 150px; top: 120px; background-color: #34495E; } +.card7 { left: 250px; top: 120px; background-color: #FF00FF; } +.card8 { left: 350px; top: 120px; background-color: #008080; } + +.card_hidden { background-color: #dddddd; } \ No newline at end of file diff --git a/gauss-turing/game/templates/drag_example.html b/gauss-turing/game/templates/drag_example.html new file mode 100644 index 0000000..0b4d623 --- /dev/null +++ b/gauss-turing/game/templates/drag_example.html @@ -0,0 +1,287 @@ + + + + + + Drag + + + + + + + + + + + + +
+ +
+ Aktuelles Programm: +
+ {% for cmd in current_program %} +
+ + {{ loop.index0 }} +
+ {% endfor %} +
+
+ + +
+ Mögliche Befehle: +
+ {% for cmd in valid_commands %} +
+ +
+ {% endfor %} +
+
+ + +
+
+ +
+
+
+
+
+ +
+ Viel Spaß beim Spielen! +
+
+ + + + + + \ No newline at end of file diff --git a/gauss-turing/game/webapp.py b/gauss-turing/game/webapp.py new file mode 100644 index 0000000..a5fdc9d --- /dev/null +++ b/gauss-turing/game/webapp.py @@ -0,0 +1,163 @@ +from flask import Flask, render_template, request, session, make_response +import socket +import time +import numpy as np +from playsound import playsound +from itertools import zip_longest +import random +import json +import pygame + +app = Flask(__name__) +app.secret_key = b'RoboRallyRolling' + +probabilities = [0.21428571428571427, 0.14285714285714285, 0.07142857142857142, 0.07142857142857142, + 0.21428571428571427, 0.21428571428571427, 0.07142857142857142] + +#deck = roborally.CardDeck() + +class Cmd: + possible_moves = ['forward', 'left', 'right', 'P0'] + possible_colors = [(200,200,200), (255, 0, 0), (0,0,255)] + + def __init__(self, action, color): + self.action = action + self.color = color + + def __str__(self): + return "Cmd No. " + self.action + + def __repr__(self): + return self.action + " " + str(self.color) + + +available_robots = { + 0: {'id': 11, 'ip': '192.168.1.11', 'x': 1, 'y': 2, 'orientation': '>'}, + 1: {'id': 12, 'ip': '192.168.1.12', 'x': 3, 'y': 3, 'orientation': '>'} +} + + +players = {} + + +class Player: + MAX_PLAYERS = 4 + player_counter = 0 + + def __init__(self): + if Player.player_counter < Player.MAX_PLAYERS: + self.id = Player.player_counter + Player.player_counter += 1 + + self.max_cards = 9 + + self.player_hand = deck.draw_cards(self.max_cards) + print("current hand: ", [str(c) for c in self.player_hand]) + + self.action_count = 5 + self.action_chosen = False + + self.initialize_robot() + + else: + print("max players reached!") + + def initialize_robot(self): + x = available_robots[self.id]['x'] + y = available_robots[self.id]['y'] + marker_id = available_robots[self.id]['id'] + ip = available_robots[self.id]['ip'] + orientation = available_robots[self.id]['orientation'] + self.robot = game.board.create_robot(x, y, orientation, self.id, marker_id) + + if game.comm_socket is not None: + cmd = f"initialize_robot, {marker_id}, {ip}, {x-1}, {y-1}, {orientation}\n" + game.comm_socket.sendall(cmd.encode()) + data = game.comm_socket.recv(32) + + if data.decode() == 'OK\n': + print("robot sucessfully initialized!") + else: + print("error: could not initialize robot!") + self.robot = None + + def draw_new_cards(self): + self.player_hand += deck.draw_cards(self.max_cards - len(self.player_hand)) + + +@app.route('/send_cmds', methods=['POST', 'GET']) +def send_cmds(): + if request.method == 'POST': + cmds = json.loads(request.form['cmds_json']) + + cmd_list = [] + for cmd_nr in [f"cmd{i}" for i in range(5)]: + cmd = cmds[cmd_nr] + action = cmd['action'] + color_str = cmd['color'] + color_str = color_str.strip("()").split(",") + color = tuple(map(int, color_str)) + cmd_list.append(Cmd(action, color)) + print("got commands: ", cmd_list) + ev = pygame.event.Event(pygame.USEREVENT, {'cmds': cmd_list}) + pygame.event.post(ev) + + # send commands to the game + + # if game.ready(): + # game.process_actions() + # + # return 'OK' + # else: + # return 'please wait' + return "OK" + elif request.method == 'GET': + # GET is used when we have to wait for other players to finish + while not game.processing_done: # wait for other players to choose commands and processing to finish + pass + + return 'OK' + +WHITE = (255, 255, 255) +GRAY = (200, 200, 200) +RED = (255, 0, 0) +BLUE = (0, 0, 255) + +@app.route('/', methods=['GET', 'POST']) +def hello_world(): + prg = [Cmd('forward', GRAY), Cmd('left', GRAY), Cmd('right', BLUE), + Cmd('P0', GRAY), Cmd('right', RED)] + valid_cmds = [Cmd('forward', WHITE), Cmd('right', WHITE), Cmd('left', WHITE), + Cmd('P0', WHITE), Cmd('-', RED), Cmd('-', BLUE), Cmd('-', GRAY)] + + if request.method == 'GET': + robot_info = None + return render_template('drag_example.html', current_program=prg, valid_commands=valid_cmds, robot_info=robot_info) + elif request.method == 'POST': + # print(request.form) + + if request.form.get('drag') and request.form.get('drop'): + # swap cards in the current hand + i1 = int(request.form.get('drag')) # number of first card + i2 = int(request.form.get('drop')) # number of second card + + card1 = deck.deck[i1] # get card by number + card2 = deck.deck[i2] + + print("swapping {} and {}".format(card1, card2)) + + j1 = player_hand.index(card1) # get index of card in the hand + j2 = player_hand.index(card2) + + player_hand[j1], player_hand[j2] = player_hand[j2], player_hand[j1] # swap the cards in the list + + # print("current hand: ", [str(c) for c in player_hand[player_id]]) + + return 'OK' + else: + return render_template('drag_example.html', cmds=player_hand, player_id=player_id) + + +if __name__ == '__main__': + #app.run(host='192.168.1.222', port=5000) + app.run(host='0.0.0.0', port=5000)