def save_board(request): """ Saves the active game from the list of active games in the database to the user's profile. Game is only saved if the user is authenticated, i.e. if the user has the matching token, else UNAUTHORIZED error is returned. Game that is being saved must exist in the list of active games. user_id: unique user identifier (same as username). token: authentication token that allow access to the user's account. game_id: ID of the saved game. :param request: POST request with fields 'user_id', 'game_id', 'token'. :return: success message, or error status. """ required_fields = ['user_id', 'game_id', 'token'] # Check if the post request contain the required fields if set(required_fields) != set(list(request.data.keys())): return Response({'error': str('Missing required fields!')}, status=status.HTTP_400_BAD_REQUEST) # POST Request content data = request.data # check for not allowed characters if check_special_characters(str(data['user_id'])) or check_special_characters(str(data['game_id'])) \ or check_special_characters(str(data['token'])): return Response({'error': str('Unaccepted character passed!')}, status=status.HTTP_400_BAD_REQUEST) # Here check if user_id matches the token with the database if not db.check_user(data['user_id'], data['token']): return Response({'error': str('UNAUTHORIZED')}, status=status.HTTP_401_UNAUTHORIZED) # Load the game board from the database response_status = game_utils.load_board_db(data['game_id']) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) board = response_status['game_board'] # Here append new game board to user's profile. Note that this board already have an ID. if not db.save_game(data['user_id'], board): return Response({'error': str('Error when saving the game!')}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) return Response({'status': 'success'})
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 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'] # 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 # 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 # 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 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 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 is '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']['chamber_list']: 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']['num_food'][to_fill] != 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']['num_tunnels'][to_fill]['prev'] if board['graph']['num_ants'][previous] == 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']['num_tunnels'][to_fill]['next'] is not 'none': next_chamber = board['graph']['num_tunnels'][to_fill]['next'] if board['graph']['num_ants'][next_chamber] == 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 if board['graph']['num_tunnels'][to_fill]['next'] is not 'none': next_chamber = board['graph']['num_tunnels'][to_fill]['next'] board['graph']['num_tunnels'][previous]['next'] = next_chamber board['graph']['num_tunnels'][next_chamber]['prev'] = previous else: board['graph']['num_tunnels'][previous]['next'] = 'none' # Delete to_fill board['graph']['chamber_list'].remove(to_fill) del board['graph']['num_tunnels'][to_fill] del board['graph']['num_food'][to_fill] del board['graph']['num_ants'][to_fill] del board['graph']['under_attack'][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) ##### NOTE: THIS IMPLEMENTATION WILL LIKELY CHANGE IN THE NEAR FUTURE # HOWEVER, GENERAL LOGIC SHOULD STAY THE SAME # @api_view(['GET']) # def move_ant(request, game_id, origin): """
def dig_chamber(request, game_id, origin, move_ant): """ 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 # 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 is not 'yes': if move_ant is not 'no': return Response({'invalid_action': 'invalid free move request!'}, status=status.HTTP_400_BAD_REQUEST) # Check if origin exists if origin is not 'surface' and origin not in board['graph']['chamber_list']: return Response({'invalid_action': 'origin does not exist'}, status=status.HTTP_400_BAD_REQUEST) # check if origin contains at least one ant if origin is 'surface' and board['total_surface_ants'] == 0: return Response({'invalid_action': 'no ants on surface'}, status=status.HTTP_400_BAD_REQUEST) if board['graph']['num_ants'][origin] == 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']['num_tunnels'][origin]['exit'] is False: 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']['num_tunnels'][origin]['next'] 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 board['total_chambers'] += 1 chamber_number = str(board['total_chambers']) chamber_id = "chamber" + chamber_number board['graph']['chamber_list'].append(chamber_id) board['graph']['num_tunnels'][chamber_id]['entrance'] = True board['graph']['num_tunnels'][chamber_id]['exit'] = False board['graph']['num_tunnels'][chamber_id]['next'] = 'none' board['graph']['num_tunnels'][chamber_id]['prev'] = origin board['graph']['num_food'][chamber_id] = 0 if move_ant is 'yes': board['graph']['num_ants'][chamber_id] = 1 if origin is not 'surface': board['graph']['num_ants'][origin] -= 1 else: board['total_surface_ants'] -= 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_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' """ # 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 is 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 is not 'surface' and origin not in board['graph']['chamber_list']: 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'][ 'chamber_list']: 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 is '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 is 'surface' and board['total_surface_ants'] == 0: return Response({'invalid_action': 'no ants on surface'}, status=status.HTTP_400_BAD_REQUEST) if board['graph']['num_ants'][origin] == 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']['num_ants'][ destination] == 0: return Response({'invalid_action': 'no ants at destination'}, status=status.HTTP_400_BAD_REQUEST) # Origin chamber must NOT already have an exit tunnel if board['graph']['num_tunnels'][origin]['exit'] is True: 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']['num_tunnels'][ destination]['entrance'] is True: 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']['num_tunnels'][origin]['exit'] = True board['graph']['num_tunnels'][origin]['next'] = destination if destination is not 'none': board['graph']['num_tunnels'][destination]['entrance'] = True if origin is 'surface': board['colony_entrance'] = True if destination is '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)
def load_board(request): """ POST request API call to load in a saved game board. This API call activates the saved gave in the user's profile by moving the saved board to the list of active games. User must be authenticated, i.e. token must match with user's profile. Once the game loaded, i.e. moved to the active games, board can be interacted with using the Game Board API. User must have the claimed game board defined by the game_id. user_id: unique user identifier (same as username). token: authentication token that allow access to the user's account. game_id: ID of the saved game. :param request: POST request with fields 'user_id', 'game_id', 'token' :return: Game Board instance """ required_fields = ['user_id', 'game_id', 'token'] # Check if the post request contain the required fields if set(required_fields) != set(list(request.data.keys())): return Response({'error': str('Missing required fields!')}, status=status.HTTP_400_BAD_REQUEST) # POST Request content data = request.data if check_special_characters(str(data['user_id'])) or check_special_characters(str(data['game_id'])) \ or check_special_characters(str(data['token'])): return Response({'error': str('Unaccepted character passed!')}, status=status.HTTP_400_BAD_REQUEST) # Here check if user_id matches the token with the database if not db.check_user(data['user_id'], data['token']): return Response({'error': str('UNAUTHORIZED')}, status=status.HTTP_401_UNAUTHORIZED) # Load the game from user's saved profile game_board = db.load_board(data['user_id'], data['game_id']) if not game_board: return Response({'error': 'you got some messed up arguments (NICK)'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) game_board['game_id'] = str(uuid.uuid1()) # indicate that this board is being loaded from the profile game_board['profile_load'] = True # Here I am just going to move this board to active games using the api we already have. # Note that board is still saved on user's profile, but we are just creating a new active game. response_status = game_utils.create_board_db(game_board) if response_status['error']: return Response({'error': response_status['reason']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) active_game_id = response_status['game_id'] # Here i am just going to return the game board itself from the active games # From this point front-end can continue using the Game Board API to interact with the game response_status = game_utils.load_board_db(active_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 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)