Example #1
0
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)
Example #7
0
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'])
Example #8
0
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)
Example #9
0
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)
Example #10
0
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)
Example #11
0
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)
Example #12
0
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)