def board(request, game_id): """ Returns the current game board state. :param request: :param game_id: unique identifier of the board :return game board JSON: """ response_status = utils.load_board_db(game_id) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_400_BAD_REQUEST) # hide the UID used by data structure backend from user # del response_status['game_board']['graph']['uid'] return Response(response_status['game_board'])
def move_food(request, game_id, start, dest): """ Moves food from start chamber to destination chamber :param game_id: unique identifier of the board :param start: The chamber to move the food from. :param dest: the chamber where the food should be placed :return game board JSON: """ # Load the game board from database response_status = utils.load_board_db(game_id) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board = response_status['game_board'] # Make sure that the player isn't trying to move to or from surface. if start == 'surface' or dest == 'surface': return Response({'invalid_action': 'no food on surface allowed'}, status=status.HTTP_400_BAD_REQUEST) # If start and dest don't exist for some reason if start not in board['graph']['chambers'] or dest not in board['graph'][ 'chambers']: return Response({'invalid_action': 'invalid chambers'}, status=status.HTTP_400_BAD_REQUEST) # If chambers aren't connected then return if board['graph']['chambers'][start]['tunnels']['next'] != dest: return Response({'invalid_action': 'no tunnel'}, status=status.HTTP_400_BAD_REQUEST) # If there is no queen then game over actually if not board['queen_at_head']: return Response({'invalid_action': 'game over'}, status=status.HTTP_400_BAD_REQUEST) # If there are no chambers player can't move food if board['total_chambers'] == 1: return Response({'invalid_action': 'no chambers'}, status=status.HTTP_400_BAD_REQUEST) # If there are no ants in the start chamber then can't move food if board['graph']['chambers'][start]['num_ants'] == 0: return Response({'invalid_action': 'no ants'}, status=status.HTTP_400_BAD_REQUEST) # If the requested dest chamber is under attack then can't move food if board['graph']['chambers'][dest]['under_attack']: return Response({'invalid_action': 'under attack'}, status=status.HTTP_400_BAD_REQUEST) # If there is no food in the starting chamber then you can't move food if board['graph']['chambers'][start]['food']['total'] == 0: return Response({'invalid_action': 'no food'}, status=status.HTTP_400_BAD_REQUEST) # If the player can't make a move, return error if board['time_tracks']['move/forage'] == 0: return Response({'invalid_action': 'no time'}, status=status.HTTP_400_BAD_REQUEST) # If we were to make it so that the user can only fit up to 6 food in the each # chamber, this might cause an issue with the fact that ants can only move one spot # So I will move food to the next chamber, not matter how much food is in the next chamber # 'Pick up' the first available food of the highest value. # Only allowing the player to move one piece of food at a time, while having no food # limit for chambers, still ensures that the player is motivated to not cram all food into # on chamber. food_picked_up = '' value = 0 if board['graph']['chambers'][start]['food']['donut'] > 0: board['graph']['chambers'][start]['food']['donut'] -= 1 board['graph']['chambers'][start]['food']['total'] -= 3 food_picked_up = 'donut' value = 3 elif board['graph']['chambers'][start]['food']['berry'] > 0: board['graph']['chambers'][start]['food']['berry'] -= 1 board['graph']['chambers'][start]['food']['total'] -= 2 food_picked_up = 'berry' value = 2 elif board['graph']['chambers'][start]['food']['crumb'] > 0: board['graph']['chambers'][start]['food']['crumb'] -= 1 board['graph']['chambers'][start]['food']['total'] -= 1 food_picked_up = 'crumb' value = 1 # Put food in the destination chamber board['graph']['chambers'][dest]['food'][food_picked_up] += 1 board['graph']['chambers'][dest]['food']['total'] += value # Update ant locations board['graph']['chambers'][start]['num_ants'] -= 1 board['graph']['chambers'][dest]['num_ants'] += 1 # Decrement Move/Forage time track board['time_tracks']['move/forage'] -= 1 user_id = board['player_ids'] token = -1 # Update the board on database response_status = utils.update_board_db(board, user_id, token) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board_response = response_status['game_board'] return Response(board_response)
def move_ant(request, game_id, start, dest): """ Moves ant from start chamber to destination chamber :param game_id: unique identifier of the board :param start: The chamber to move from. :param dest: the chamber where to move :return game board JSON: """ # Load the game board from database response_status = utils.load_board_db(game_id) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board = response_status['game_board'] # If start and dest don't exist for some reason if (start not in board['graph']['chambers']) or ( dest not in board['graph']['chambers']): return Response({'invalid_action': 'invalid chambers'}, status=status.HTTP_400_BAD_REQUEST) # If chambers aren't connected then return if board['graph']['chambers'][start]['tunnels']['next'] != dest: return Response({'invalid_action': 'no tunnel'}, status=status.HTTP_400_BAD_REQUEST) # If there is no queen then game over actually if board['queen_at_head'] == False: return Response({'invalid_action': 'game over'}, status=status.HTTP_400_BAD_REQUEST) # If no ant to move if board['graph']['chambers'][start]['num_ants'] == 0: return Response({'invalid_action': 'no ants'}, status=status.HTTP_400_BAD_REQUEST) # If the player can't make a move, return error if board['time_tracks']['move/forage'] == 0: return Response({'invalid_action': 'no time'}, status=status.HTTP_400_BAD_REQUEST) # if at this point, update all relevant game board values # Update ant locations board['graph']['chambers'][start]['num_ants'] -= 1 board['graph']['chambers'][dest]['num_ants'] += 1 if start == 'surface': board['total_surface_ants'] -= 1 # Decrement Move/Forage time track board['time_tracks']['move/forage'] -= 1 user_id = board['player_ids'] token = -1 # Update the board on database response_status = utils.update_board_db(board, user_id, token) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board_response = response_status['game_board'] return Response(board_response)
def forage(request, game_id, difficulty, dest): """ Spawns an ant given the game ID :param game_id: unique identifier of the board :param difficulty: game difficulty :param ant_loc: the chamber in which the ant is located :param dest: the chamber where the food should be placed :return game board JSON: """ # Load the game board from database response_status = utils.load_board_db(game_id) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board = response_status['game_board'] # Make sure that the destination chamber is in the colony if dest not in board['graph']['chambers']: return Response({'invalid_action': 'dest dne'}, status=status.HTTP_400_BAD_REQUEST) # Make sure that the surface is connected to the dest somehow. curr_chamber = 'surface' connected = False while board['graph']['chambers'][curr_chamber]['tunnels']['next'] is not None and \ board['graph']['chambers'][curr_chamber]['tunnels']['next'] != 'surface': if board['graph']['chambers'][curr_chamber]['tunnels']['next'] == dest: connected = True break curr_chamber = board['graph']['surface'][curr_chamber]['tunnels'][ 'next'] if connected == False: return Response({'invalid_action': 'dest unreachable'}, status=status.HTTP_400_BAD_REQUEST) # If there are no chambers player can't forage if board['total_chambers'] == 0: return Response({'invalid_action': 'no chambers'}, status=status.HTTP_400_BAD_REQUEST) # If there is no queen then game over actually if board['queen_at_head'] == False: return Response({'invalid_action': 'lost queen'}, status=status.HTTP_400_BAD_REQUEST) # If there are no worker ants on the surface. if board['total_surface_ants'] == 1: return Response({'invalid_action': 'no surface ants'}, status=status.HTTP_400_BAD_REQUEST) # If the requested chamber is under attack return error if board['graph']['chambers'][dest]['under_attack']: return Response({'invalid_action': 'under attack'}, status=status.HTTP_400_BAD_REQUEST) # If the player can't make a forage move, return error if board['time_tracks']['move/forage'] == 0: return Response({'invalid_action': 'no time'}, status=status.HTTP_400_BAD_REQUEST) # choose a random number then choose the forage type that will be returned rand_food = random.randint(0, 100) crumb_chance = config.FORAGE_CHANCE[difficulty][config.FORAGE_TYPES[0]] berry_chance = config.FORAGE_CHANCE[difficulty][config.FORAGE_TYPES[1]] donut_chance = config.FORAGE_CHANCE[difficulty][config.FORAGE_TYPES[2]] attack_chance = config.FORAGE_CHANCE[difficulty][config.FORAGE_TYPES[3]] # Check if crumb was chosen if rand_food >= 0 and rand_food < crumb_chance: forage_result = config.FORAGE_TYPES[0] # Check if berry was chosen if rand_food >= crumb_chance and rand_food < berry_chance: forage_result = config.FORAGE_TYPES[1] # Check if donut was chosen if rand_food >= berry_chance and rand_food < donut_chance: forage_result = config.FORAGE_TYPES[2] # Check if attack was chosen if rand_food >= donut_chance and rand_food < attack_chance: forage_result = config.FORAGE_TYPES[3] # If the forage resulted in the chamber coming under attack, # Then reflect the change in the board if forage_result == config.FORAGE_TYPES[3]: board['graph']['chambers'][dest]['under_attack'] = True board['total_under_attack'] += 1 board['total_surface_ants'] -= 1 board['graph']['chambers']['surface']['num_ants'] -= 1 board['graph']['chambers'][dest]['num_ants'] += 1 # Otherwise, put the food in the requested chamber, move the ant, and update the board else: # Change food in requested chamber board['graph']['chambers'][dest]['food'][forage_result] += 1 board['graph']['chambers'][dest]['food']['total'] += config.FOOD_VALUE[ forage_result] # Change food stats on for the game board board['total_food_types'][forage_result] += 1 board['total_food'] += config.FOOD_VALUE[forage_result] # Move the ant from og spot to new spot board['total_surface_ants'] -= 1 board['graph']['chambers']['surface']['num_ants'] -= 1 board['graph']['chambers'][dest]['num_ants'] += 1 # Decrement Move/Forage time track board['time_tracks']['move/forage'] -= 1 user_id = board['player_ids'] token = -1 # Update the board on database response_status = utils.update_board_db(board, user_id, token) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board_response = response_status['game_board'] return Response(board_response)
def spawn_ant(request, game_id): """ Spawns an ant given the game ID :param game_id: unique identifier of the board :return game board JSON: """ # Load the game board from database response_status = utils.load_board_db(game_id) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board = response_status['game_board'] if not board['queen_at_head']: return Response({'invalid_action': 'lost queen'}, status=status.HTTP_400_BAD_REQUEST) # Make sure there is enough food to spawn a new ant if board['total_food'] < config.ANT_SPAWN_VAL: return Response({'invalid_action': 'not enough food'}, status=status.HTTP_400_BAD_REQUEST) # Take away food, if they have food that can be curr_food_types = board['total_food_types'] # Find the first chamber with enough food chamber_with_food = None for chamber in board['graph']['chambers'].keys(): if chamber != 'surface' and board['graph']['chambers'][chamber][ 'food']['total'] >= config.ANT_SPAWN_VAL: chamber_with_food = chamber break # If player has a donut take it if curr_food_types[config.FORAGE_TYPES[2]] > 0: board['total_food_types'][config.FORAGE_TYPES[2]] -= 1 board['total_food'] -= config.ANT_SPAWN_VAL board['graph']['chambers'][chamber_with_food]['food'][ config.FORAGE_TYPES[2]] -= 1 board['graph']['chambers'][chamber_with_food]['food'][ 'total'] -= config.ANT_SPAWN_VAL # If player has at least one berry and one crumb, take one of each elif curr_food_types[config.FORAGE_TYPES[1]] > 0 and curr_food_types[ config.FORAGE_TYPES[0]] > 0: board['total_food_types'][config.FORAGE_TYPES[1]] -= 1 board['total_food_types'][config.FORAGE_TYPES[0]] -= 1 board['total_food'] -= config.ANT_SPAWN_VAL board['graph']['chambers'][chamber_with_food]['food'][ config.FORAGE_TYPES[1]] -= 1 board['graph']['chambers'][chamber_with_food]['food'][ config.FORAGE_TYPES[0]] -= 1 board['graph']['chambers'][chamber_with_food]['food'][ 'total'] -= config.ANT_SPAWN_VAL # If player only has crumbs take it elif curr_food_types[config.FORAGE_TYPES[0]] >= config.ANT_SPAWN_VAL: board['total_food_types'][ config.FORAGE_TYPES[0]] -= config.ANT_SPAWN_VAL # If this case is reached, the player has enough food, but only in berry form (not divisible by 3) elif curr_food_types[config.FORAGE_TYPES[1]] >= 2: board['total_food_types'][config.FORAGE_TYPES[1]] -= 2 board['total_food_types'][config.FORAGE_TYPES[0]] += 1 board['total_food'] -= config.ANT_SPAWN_VAL board['graph']['chambers'][chamber_with_food]['food'][ config.FORAGE_TYPES[1]] -= 2 board['graph']['chambers'][chamber_with_food]['food'][ config.FORAGE_TYPES[1]] += 1 board['graph']['chambers'][chamber_with_food]['food'][ 'total'] -= config.ANT_SPAWN_VAL else: return Response({'invalid_action': 'error occurred'}, status=status.HTTP_400_BAD_REQUEST) # if control reaches here, then spawning an ant is successful. Update both total and surface ant values. board['total_ants'] += 1 board['total_surface_ants'] += 1 action = ['spawn_ant'] board['graph'] = doAction(board['graph'], action) user_id = board['player_ids'] token = -1 # Update the board on database response_status = utils.update_board_db(board, user_id, token) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board_response = response_status['game_board'] return Response(board_response)
def fill_chamber(request, game_id, to_fill): """ Attempts to 'fill' (delete) a chamber and all associated tunnels :param game_id: unique identifier of the board :param to_fill: the chamber that the player wishes to delete :return game board JSON: """ # Check if game exists # Load the game board from database response_status = utils.load_board_db(game_id) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board = response_status['game_board'] # Check if to_fill is surface (cannot fill in surface) if to_fill == 'surface': return Response({'invalid_action': 'cannot fill in surface'}, status=status.HTTP_400_BAD_REQUEST) # Check if to_fill exists if to_fill not in board['graph']['chambers']: return Response({'invalid_action': 'chamber does not exist'}, status=status.HTTP_400_BAD_REQUEST) # Check for fill chamber energy if board['time_tracks']['dig/fill_chamber'] == 0: return Response({'invalid_action': 'no more fill chamber moves left!'}, status=status.HTTP_400_BAD_REQUEST) # Check if to_fill has any food in it if (board['graph']['chambers'][to_fill]['food']['crumb'] > 0) \ or (board['graph']['chambers'][to_fill]['food']['berry'] > 0) \ or (board['graph']['chambers'][to_fill]['food']['donut'] > 0): return Response({'invalid_action': 'There is food in this chamber!'}, status=status.HTTP_400_BAD_REQUEST) # Check if there is at least one ant at the prev chamber previous = board['graph']['chambers'][to_fill]['tunnels']['prev'] if board['graph']['chambers'][previous]['num_ants'] == 0: return Response({'invalid_action': 'No ant in previous chamber!'}, status=status.HTTP_400_BAD_REQUEST) # Check if there is a next chamber, and if so, if there is at least one ant in it if board['graph']['chambers'][to_fill]['tunnels']['next'] is not None: next_chamber = board['graph']['chambers'][to_fill]['tunnels']['next'] if board['graph']['chambers'][next_chamber]['num_ants'] == 0: return Response({'invalid_action': 'No ant in next chamber!'}, status=status.HTTP_400_BAD_REQUEST) # If at this point, all checks are made. Update gameboard # link up prev and next board['graph'] = doAction(board['graph'], ('fill_chamber', to_fill)) board['total_chambers'] -= 1 board['time_tracks']['dig/fill_chamber'] -= 1 user_id = board['player_ids'] token = -1 # Update the board on database response_status = utils.update_board_db(board, user_id, token) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board_response = response_status['game_board'] return Response(board_response)
def dig_chamber(request, game_id, origin, move_ant, ant=None): """ Attempts to dig a new chamber off of a current dead-end tunnel :param game_id: unique identifier of the board :param origin: the chamber that the player wishes to dig from :param move_ant: whether the player wishes to move the ant into the new chamber """ # checklist if ant == 'None': ant = None # Check if game exists response_status = utils.load_board_db(game_id) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board = response_status['game_board'] # Check for dig chamber energy if board['time_tracks']['dig/fill_chamber'] == 0: return Response({'invalid_action': 'no more dig chamber moves left!'}, status=status.HTTP_400_BAD_REQUEST) # Check if move_ant is a valid input if move_ant != 'yes': if move_ant != 'no': return Response({'invalid_action': 'invalid free move request!'}, status=status.HTTP_400_BAD_REQUEST) # Check if origin exists if origin != 'surface' and origin not in board['graph']['chambers']: return Response({'invalid_action': 'origin does not exist'}, status=status.HTTP_400_BAD_REQUEST) # check if origin contains at least one ant if origin == 'surface' and board['total_surface_ants'] == 1: return Response({'invalid_action': 'no ants on surface'}, status=status.HTTP_400_BAD_REQUEST) if board['graph']['chambers'][origin]['num_ants'] == 0: return Response({'invalid_action': 'no ants at origin'}, status=status.HTTP_400_BAD_REQUEST) # Check if origin contains an exit tunnel if board['graph']['chambers'][origin]['tunnels']['next'] is not None: return Response({'invalid_action': 'no available tunnel from origin'}, status=status.HTTP_400_BAD_REQUEST) # if origin contains a next tunnel, check if current next is 'none' # if board['graph']['tunnels'][origin][0] == 2 and board['graph']['tunnels'][origin][2] is not None: # return Response({'invalid_action': 'no available tunnel from origin'}, # status=status.HTTP_400_BAD_REQUEST) # if at this point, dig request is valid: update ALL relevant game board variables newchamberid = 'chamber' + str(len(board['graph']['chambers'].keys()) + 1) board['graph'] = doAction(board['graph'], ('dig_chamber', origin)) board['total_chambers'] += 1 if move_ant == 'yes' and ant is not None: board['graph'] = doAction(board['graph'], ('move_ant', ant, newchamberid)) board['time_tracks']['dig/fill_chamber'] -= 1 user_id = board['player_ids'] token = -1 # Update the board on database response_status = utils.update_board_db(board, user_id, token) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board_response = response_status['game_board'] return Response(board_response)
def dig_tunnel(request, game_id, origin, destination): """ Attempts to dig a tunnel from the requested chamber to a requested destination :param game_id: unique identifier of the board :param origin: the chamber that the player wishes to dig from :param destination: the place that the player wishes to dig to (chamber name, 'surface', or 'none' """ # convert string to actual value if destination == 'None': destination = None # Game must exist # Load the game board from database response_status = utils.load_board_db(game_id) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board = response_status['game_board'] # origin and destination MUST be different if origin == destination: return Response({'invalid_action': 'origin cannot match destination'}, status=status.HTTP_400_BAD_REQUEST) # Player must still have dig 'energy' for that day if board['time_tracks']['dig_tunnel_track'] == 0: return Response({'invalid_action': 'no more dig tunnel moves left!'}, status=status.HTTP_400_BAD_REQUEST) # Origin must exist if origin != 'surface' and origin not in board['graph']['chambers']: return Response({'invalid_action': 'origin does not exist'}, status=status.HTTP_400_BAD_REQUEST) # If destination is NOT 'none', it must exist (chamber OR surface) if destination is not None and destination not in board['graph'][ 'chambers']: return Response({'invalid_action': 'destination does not exist'}, status=status.HTTP_400_BAD_REQUEST) # If Origin is surface, colony_entrance MUST be False if origin == 'surface' and board['colony_entrance'] is True: return Response({'invalid_action': 'colony_entrance already exists'}, status=status.HTTP_400_BAD_REQUEST) # There must be at least one ant at origin if origin == 'surface' and board['total_surface_ants'] == 0: return Response({'invalid_action': 'no ants on surface'}, status=status.HTTP_400_BAD_REQUEST) if board['graph']['chambers'][origin]['num_ants'] == 0: return Response({'invalid_action': 'no ants at origin'}, status=status.HTTP_400_BAD_REQUEST) # If destination is NOT none, there must be an ant at the destination if destination is not None and board['graph']['chambers'][destination][ 'num_ants'] == 0: return Response({'invalid_action': 'no ants at destination'}, status=status.HTTP_400_BAD_REQUEST) # Origin chamber must NOT already have an exit tunnel, except if it's to the surface if board['graph']['chambers'][origin]['tunnels']['next'] is not None and \ board['graph']['chambers'][origin]['tunnels']['next'] != 'surface': return Response({'invalid_action': 'exit tunnel exists'}, status=status.HTTP_400_BAD_REQUEST) # destination must NOT already have an entrance tunnel if destination is not None and board['graph']['chambers'][destination][ 'tunnels']['prev'] is not None: return Response({'invalid_action': 'exit tunnel exists'}, status=status.HTTP_400_BAD_REQUEST) # if ALL checks are passed, create new tunnel and update ALL relevant gameboard parameters # num_tunnels board['graph'] = doAction(board['graph'], ('dig_tunnel', origin, destination)) board['total_tunnels'] += 1 if origin == 'surface': board['colony_entrance'] = True if destination == 'surface': board['colony_exit'] = True board['time_tracks']['dig_tunnel_track'] -= 1 user_id = board['player_ids'] token = -1 # Update the board on database response_status = utils.update_board_db(board, user_id, token) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board_response = response_status['game_board'] return Response(board_response)