def make_move(
        request: chupacabra_pb2.MoveRequest,
        game_map: Dict[str, GameServerStub], session_handler: SessionHandler
) -> game_structs_pb2.GameStatusResponse:
    """Make a move in the game."""
    username = request.game_info.username
    session_id = request.game_info.session_id
    user_data = session_handler.authenticate_session(username, session_id)
    if user_data is None:
        return game_structs_pb2.GameStatusResponse(
            success=False, message=AUTHENTICATION_FAILED)

    game_stub = game_map.get(request.game_info.game_type)
    if game_stub is None:
        return game_structs_pb2.GameStatusResponse(
            success=False,
            message=GAME_TYPE_NOT_FOUND.format(request.game_info.game_type))

    user_game_info = game_server_pb2.UserGameInfo(
        player_id=user_data.user_id, game_id=request.game_info.game_id)
    internal_request = game_server_pb2.MoveRequest(game_info=user_game_info,
                                                   move=request.move)

    response = game_stub.MakeMove(internal_request)
    return response
Beispiel #2
0
def forfeit_game(
    request: game_server_pb2.UserGameInfo
) -> game_structs_pb2.GameStatusResponse:
    """Forfeit the game."""
    handler = get_default_tictactoe_cache_handler()
    validated = _validate_game(request.game_id, request.player_id, handler)

    if validated is False:
        response = game_structs_pb2.GameStatusResponse(
            success=False,
            message='Cannot find game of this id for this user.')
        return response

    # Lock the state so that we can make a move
    lock_key = _make_state_lock_key(request.game_id)
    with handler.lock(lock_key, blocking_timeout=TTT_MOVE_BLOCK_TIME):
        # Now grab the state from redis
        state_key = _make_state_key(request.game_id)
        state = handler.get(state_key)
        if state is None:
            logger.error('Game {} validated but data not found'.format(
                request.game_id))
            not_found_response = game_structs_pb2.GameStatusResponse(
                success=False, message='Game data not found.')
            return not_found_response

        internal_state = ttt.deserialize_state(state)
        # If the game is over, we don't want to do anything
        if internal_state.mode != ttt.PLAY_MODE:
            return _convert_to_status_response(
                request.player_id, 'Game already over. Cannot forfeit.',
                internal_state, False)
        internal_state.mode = ttt.FINISHED_MODE
        winner_idx = None
        for idx, player_id in enumerate(internal_state.player_ids):
            if player_id != request.player_id:
                winner_idx = idx
                break

        if winner_idx is None:
            raise AssertionError('Could not find the winning player.')

        internal_state.winner = winner_idx
        serialized_state = ttt.serialize_state(internal_state)
        timestamp = arrow.utcnow().timestamp
        state_lifetime = int(internal_state.game_expiration_time - timestamp +
                             GAME_PADDED_LIFETIME)
        handler.set(state_key, serialized_state, lifetime=state_lifetime)
        success_message = 'Success. You have forfeited the game.'
        response = _convert_to_status_response(request.player_id,
                                               success_message, internal_state,
                                               True)
        return response
Beispiel #3
0
def make_move(
    request: game_server_pb2.MoveRequest
) -> game_structs_pb2.GameStatusResponse:
    """Make a move."""
    handler = get_default_tictactoe_cache_handler()
    validated = _validate_game(request.game_info.game_id,
                               request.game_info.player_id, handler)

    if validated is False:
        response = game_structs_pb2.GameStatusResponse(
            success=False,
            message='Cannot find game of this id for this user.')
        return response

    # Lock the state so that we can make a move
    lock_key = _make_state_lock_key(request.game_info.game_id)
    with handler.lock(lock_key, blocking_timeout=TTT_MOVE_BLOCK_TIME):
        # Now grab the state from redis
        state_key = _make_state_key(request.game_info.game_id)
        state = handler.get(state_key)
        if state is None:
            logger.error('Game {} validated but data not found.'.format(
                request.game_info.game_id))
            not_found_response = game_structs_pb2.GameStatusResponse(
                success=False, message='Game data not found.')
            return not_found_response

        internal_state = ttt.deserialize_state(state)

        # Make the move
        message, new_state = ttt.make_move(internal_state, request.move,
                                           request.game_info.player_id)

        # If the move was successful, write back into redis and release lock
        if new_state is not None:
            serialized_state = ttt.serialize_state(new_state)
            timestamp = arrow.utcnow().timestamp
            state_lifetime = int(internal_state.game_expiration_time -
                                 timestamp + GAME_PADDED_LIFETIME)
            handler.set(state_key, serialized_state, lifetime=state_lifetime)
            success = True
        else:
            new_state = internal_state
            success = False

    # craft and return the correct response
    response = _convert_to_status_response(request.game_info.player_id,
                                           message, new_state, success)
    return response
Beispiel #4
0
def get_game_status(
    request: game_server_pb2.UserGameInfo
) -> game_structs_pb2.GameStatusResponse:
    """Get the current status of the game."""
    handler = get_default_tictactoe_cache_handler()
    lock_key = _make_state_lock_key(request.game_id)
    with handler.lock(lock_key, TTT_MOVE_BLOCK_TIME):
        message, internal_state, save_new_state = _get_game_state(
            request.game_id, request.player_id, handler)
        if save_new_state:
            serialized_state = ttt.serialize_state(internal_state)
            state_key = _make_state_key(request.game_id)
            timestamp = arrow.utcnow().timestamp
            state_lifetime = int(internal_state.game_expiration_time -
                                 timestamp + GAME_PADDED_LIFETIME)
            if state_lifetime > 0:
                handler.set(state_key,
                            serialized_state,
                            lifetime=state_lifetime)

    if internal_state is None:
        return game_structs_pb2.GameStatusResponse(success=False,
                                                   message=message)

    success_message = 'Success'
    response = _convert_to_status_response(request.player_id, success_message,
                                           internal_state, True)
    return response
Beispiel #5
0
def _convert_to_status_response(
        player_id: str, success_message: str,
        internal_state: ttt.TicTacToeInternalState,
        success: bool) -> game_structs_pb2.GameStatusResponse:
    board = _make_game_board(internal_state.board, internal_state.players)
    current_player = internal_state.player_ids[internal_state.turn]
    if (internal_state.mode == ttt.PLAY_MODE and current_player == player_id):
        legal_moves = [description.PLACE_MARK_DESCRIPTION.name]
    else:
        legal_moves = []

    status = _get_game_status(internal_state.mode, internal_state.winner,
                              internal_state.players)

    state = game_structs_pb2.GameState(
        status=status,
        boards=[board],
        mode=internal_state.mode,
    )

    status_info = game_structs_pb2.GameStatusInfo(
        id=internal_state.id,
        players=internal_state.players,
        state=state,
        legal_moves=legal_moves)

    response = game_structs_pb2.GameStatusResponse(success=success,
                                                   message=success_message,
                                                   status_info=status_info)
    return response
def forfeit_game(
        request: chupacabra_pb2.PlayerGameInfo,
        game_map: Dict[str, GameServerStub], session_handler: SessionHandler
) -> game_structs_pb2.GameStatusResponse:
    """Immediately forfeit the game."""
    username = request.username
    session_id = request.session_id
    user_data = session_handler.authenticate_session(username, session_id)
    if user_data is None:
        return game_structs_pb2.GameStatusResponse(
            success=False, message=AUTHENTICATION_FAILED)

    game_stub = game_map.get(request.game_type)
    if game_stub is None:
        return game_structs_pb2.GameStatusResponse(
            success=False,
            message=GAME_TYPE_NOT_FOUND.format(request.game_type))

    internal_request = game_server_pb2.UserGameInfo(
        player_id=user_data.user_id, game_id=request.game_id)

    response = game_stub.ForfeitGame(internal_request)
    return response
def check_legal_moves(
        request: chupacabra_pb2.PlayerGameInfo,
        game_map: Dict[str, GameServerStub], session_handler: SessionHandler
) -> game_structs_pb2.LegalMovesResponse:
    """Check what types of moves are available for the player at this point in the game."""
    username = request.username
    session_id = request.session_id
    user_data = session_handler.authenticate_session(username, session_id)
    if user_data is None:
        return game_structs_pb2.GameStatusResponse(
            success=False, message=AUTHENTICATION_FAILED)

    game_stub = game_map.get(request.game_type)
    if game_stub is None:
        return game_structs_pb2.GameStatusResponse(
            success=False,
            message=GAME_TYPE_NOT_FOUND.format(request.game_type))

    internal_request = game_server_pb2.UserGameInfo(
        player_id=user_data.user_id, game_id=request.game_id)

    response = game_stub.GetLegalMoves(internal_request)
    return response