from flask import Flask, render_template, request, session, make_response import random import socket import time app = Flask(__name__) app.secret_key = b'RoboRallyRolling' random.seed(0) moves = ['forward', 'forward x2', 'forward x3', 'backward', 'turn left', 'turn right', 'turn around'] probabilities = [0.21428571428571427, 0.14285714285714285, 0.07142857142857142, 0.07142857142857142, 0.21428571428571427, 0.21428571428571427, 0.07142857142857142] class Robot: def __init__(self, x, y, orientation, id): self.x = x self.y = y self.orientation = orientation self.id = id def move(self, type): pass def __str__(self): return str(self.id) class Tile: # possible modifiers: # conveyors: <, >, ^, v # repair station: r # flag: f def __init__(self, x, y, modifier=None): self.modifier = modifier self.occupant = None self.x = x self.y = y def is_empty(self): return self.occupant is None def __str__(self): if self.is_empty(): if self.modifier is None: return ' ' else: return self.modifier else: return str(self.occupant) class Board: x_dims = 12 # number of tiles in x direction y_dims = 6 # number of tiles in y direction def __init__(self): self.board = {} for x in range(Board.x_dims): for y in range(Board.y_dims): if x == 0 and (y >= 1) and (y <= 4): self.board[(x,y)] = Tile(x,y,'v') else: self.board[(x, y)] = Tile(x, y) self.board[(0,0)].occupant = Robot(0,0,'>',1) self.board[(2,0)].occupant = Robot(2,0,'v',2) def apply_actions(self, actions): # apply the actions to the board and generate a list of movement commands # sort actions by priority sorted_actions = sorted(actions, key=lambda a: a[1].priority) pass def __str__(self): output = '#' * (Board.x_dims + 2) + '\n' for y in range(Board.y_dims): output += '#' for x in range(Board.x_dims): output += str(self.board[(x,y)]) output += '#\n' output += '#' * (Board.x_dims + 2) return output class Game: def __init__(self): self.action_stack = {} self.processing_done = False # indicates whether all commands in the current round have been processed self.board = Board() self.comm_socket = socket.socket() # socket for communicating with the program controlling the robots try: self.comm_socket.connect(('192.168.1.222', 1337)) except socket.error: print("could not connect to robot control socket!") def ready(self): # have all players chosen an action? return len(self.action_stack.keys()) == Player.player_counter def register_actions(self, player_id, actions): if not player_id in self.action_stack.keys(): print("registered actions: ", [str(a) for a in actions]) self.action_stack[player_id] = actions deck.return_cards(actions) # put cards back into the deck self.processing_done = False return True else: print("actions already chosen!") return False def process_actions(self): # send commands to the robots in the order of priority for i in range(5): current_actions = [] for p in self.action_stack.keys(): current_actions += [(p, self.action_stack[p][i])] print("current actions = ", current_actions) # generate list of movement commands to send to the control program self.board.apply_actions(current_actions) if False: # send movements to the program for c in current_actions: if c[0] == 0: print("{}, {}\n".format(c[1].action, 11)) self.comm_socket.sendall("{}, {}\n".format(c[1].action, 11).encode()) elif c[0] == 1: print("{}, {}\n".format(c[1].action, 14)) self.comm_socket.sendall("{}, {}\n".format(c[1].action, 14).encode()) data = self.comm_socket.recv(32) if data == b'OK\n': print("an error occured while processing the commands") self.processing_done = True self.action_stack = {} return time.sleep(0.5) #self.comm_socket.send() # clear the action stack for the next round self.action_stack = {} self.processing_done = True class Card: card_counter = 0 def __init__(self): self.number = Card.card_counter Card.card_counter += 1 self.action = random.choice(moves) self.priority = random.randint(0, 100) def __str__(self): return "Card No. " + str(self.number) + " " + self.action + " " + str(self.priority) class CardDeck: def __init__(self, n=84): self.deck = {} # generate cards for i in range(0,n): self.deck[i] = Card() self.dealt = set() self.discard_pile = set() def draw_cards(self, n=1): available = set(self.deck.keys()).difference(self.dealt) #print("{} cards are available".format(len(available))) if len(available) < n: drawn = list(available) # give out remaining cards #print("drawing remaining {} cards".format(len(drawn))) self.dealt = self.dealt.union(drawn) # put the cards from the discard pile back into the game self.dealt = self.dealt - self.discard_pile self.discard_pile = set() # reset the discard pile # draw rest of cards available = set(self.deck.keys()).difference(self.dealt) #print("drawing another {} cards".format(n - len(drawn))) drawn += random.sample(available, n - len(drawn)) else: drawn = random.sample(available, n) #print("cards drawn: {}".format(drawn)) self.dealt = self.dealt.union(drawn) return [self.deck[i] for i in drawn] def return_cards(self, cards): self.discard_pile = self.discard_pile.union(set([c.number for c in cards])) pass deck = CardDeck() class Player: MAX_PLAYERS = 3 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 else: print("max players reached!") def draw_new_cards(self): self.player_hand += deck.draw_cards(self.max_cards - len(self.player_hand)) players = {} game = Game() @app.route('/send_cmds', methods=['POST', 'GET']) def send_cmds(): if request.method == 'POST': # POST is used for submitting commands player_id = session['player_id'] p = players[player_id] if game.register_actions(p.id, p.player_hand[0:p.action_count]): p.player_hand = p.player_hand[p.action_count:] # discard used cards p.draw_new_cards() if game.ready(): game.process_actions() return 'OK' else: return 'please wait' 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' @app.route('/', methods=['GET', 'POST']) def hello_world(): if not 'player_id' in session: if Player.player_counter < Player.MAX_PLAYERS: # new player p = Player() session['player_id'] = p.id players[p.id] = p player_id = session['player_id'] else: return "Sorry, maximum number of players reached!" else: player_id = session['player_id'] if Player.player_counter < player_id + 1: session.clear() response = make_response('Please reload the page!') #response.set_cookie('player_id', '', expires=0) return response player_hand = players[player_id].player_hand if request.method == 'GET': return render_template('drag_example.html', cmds=player_hand, player_id=player_id) 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='0.0.0.0', port=5000)