예제 #1
0
        public GoGameStateResponse GetGameState(Guid gameid)
        {
            GoGameStateResponse rval;

            try
            {
                var state = _goGRepository.GetGameState(gameid);
                if (state == null)
                {
                    throw new GoEngineException(GoResultCode.GameDoesNotExist, "GameId not found.");
                }
                state.Operation = FuegoEngine.Instance.GetCurrentOperation(gameid);
                rval            = new GoGameStateResponse(GoResultCode.Success, state);
            }
            catch (GoEngineException gex)
            {
                _logger.LogServerError(gameid, gex, "GameId: " + gameid);
                rval = new GoGameStateResponse(gex.Code, null);
            }
            catch (Exception ex)
            {
                _logger.LogServerError(gameid, ex, null);
                rval = new GoGameStateResponse(GoResultCode.ServerInternalError, null);
            }
            return(rval);
        }
예제 #2
0
        /// <summary>
        /// Starts the fuego engine and resets its game state to the given state.
        /// </summary>
        /// <param name="gameid"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public async Task <GoGameStateResponse> StartAsync(Guid gameid, GoGameState state)
        {
            GoGameStateResponse rval;

            try
            {
                // Either we're starting a new game, or a game already exist and we're just
                // setting up fuego.
                Debug.Assert(state != null || _state != null, "state != null || _state != null");

                _fuego = new FuegoInstance();

                await Task.Factory.StartNew(() => StartProcess(state));

                rval = new GoGameStateResponse(GoResultCode.Success, state);
            }
            catch (GoEngineException gex)
            {
                rval = new GoGameStateResponse(gex.Code, null);
            }
            catch (Exception ex)
            {
                rval = new GoGameStateResponse(GoResultCode.ServerInternalError, null);
            }

            return(rval);
        }
예제 #3
0
        public GoResponse GetGameExists(Guid gameid)
        {
            GoResponse rval;

            try
            {
                var exists = _goGRepository.GetGameExists(gameid);
                rval = new GoResponse(exists ? GoResultCode.Success : GoResultCode.GameDoesNotExist);
            }
            catch (Exception ex)
            {
                _logger.LogServerError(gameid, ex, null);
                rval = new GoGameStateResponse(GoResultCode.ServerInternalError, null);
            }
            return(rval);
        }
예제 #4
0
        public GoGameStateResponse Undo(Guid gameid)
        {
            GoGameStateResponse rval;

            try
            {
                var gameState = FuegoEngine.Instance.Undo(gameid);
                rval = new GoGameStateResponse(GoResultCode.Success, gameState);
            }
            catch (GoEngineException gex)
            {
                _logger.LogEngineException(gameid, gex, "Undo move failed.");
                rval = new GoGameStateResponse(gex.Code, null);
            }
            catch (Exception ex)
            {
                _logger.LogServerError(gameid, ex, "Undo move failed.");
                rval = new GoGameStateResponse(GoResultCode.ServerInternalError, null);
            }
            return(rval);
        }
예제 #5
0
        public GoGameStateResponse Start(Guid gameid, GoGameState state)
        {
            GoGameStateResponse rval;

            try
            {
                // TODO: This code assumes only one player is AI, and uses its level setting.
                FuegoEngine.Instance.Start(gameid, state);
                rval = new GoGameStateResponse(GoResultCode.Success, state);
            }
            catch (GoEngineException gex)
            {
                _logger.LogEngineException(gameid, gex, state);
                rval = new GoGameStateResponse(gex.Code, null);
            }
            catch (Exception ex)
            {
                _logger.LogServerError(gameid, ex, state);
                rval = new GoGameStateResponse(GoResultCode.ServerInternalError, null);
            }
            return(rval);
        }
예제 #6
0
        // Tries to get state from repo.  Then, calls ContinueGameFromState()
        // to sync our state with it.  Displays appropriate messages and retries as necessary.
        private async void LoadGameFromRepoAsync(string msg)
        {
            GoGameStateResponse resp = null;

            MessageText = msg;
            IsBusy      = true;

            if (ActiveGame != Guid.Empty)
            {
                if (AbortOperation)
                {
                    return;
                }

                var exists = await DataRepository.GetGameExists(ActiveGame);

                if (exists.ResultCode == GoResultCode.GameDoesNotExist)
                {
                    if (AbortOperation)
                    {
                        return;
                    }

                    resp = await DataRepository.StartAsync(ActiveGame, null);

                    Debug.Assert(resp != null && resp.ResultCode == GoResultCode.Success, "resp != null && resp.ResultCode == GoResultCode.Success");
                }
            }

            if (AbortOperation)
            {
                return;
            }

            resp = await DataRepository.GetGameStateAsync(ActiveGame);

            IsBusy      = false;
            MessageText = null;

            Debug.Assert(resp != null, "resp != null");

            if (AbortOperation)
            {
                return;
            }

            if (resp.ResultCode == GoResultCode.Success)
            {
                ContinueGameFromState(resp.GameState);

                // Reflect actual operation happening on server and retry sync.
                switch (resp.GameState.Operation)
                {
                case GoOperation.GenMove:
                    WaitAndRetryLoadGameFromServerAsync(5000, "Fuego is thinking...");
                    break;

                case GoOperation.Starting:
                    WaitAndRetryLoadGameFromServerAsync(5000, "Starting game...");
                    break;

                case GoOperation.Hint:
                case GoOperation.NormalMove:
                case GoOperation.Pass:
                case GoOperation.Resign:
                    WaitAndRetryLoadGameFromServerAsync(5000, "Syncronizing...");
                    break;

                case GoOperation.Idle:
                    RunOnUIThread(() =>
                    {
                        if (!AbortOperation && Status == GoGameStatus.Active)
                        {
                            //RunOnUIThread(PlayCurrentUser);
                            PlayCurrentUser();
                        }
                        else
                        {
                            Debug.Assert(false, "This shouldn't happen.");
                        }
                    });
                    break;
                }
            }
            else
            {
                await DisplayErrorCode(resp.ResultCode);

                GoBackDeferred();
            }
        }
예제 #7
0
        public async Task <GoGameStateResponse> UndoAsync(Guid id)
        {
            await LoadState();

            GoGameStateResponse rval = null;

            try
            {
                await Task.Run(
                    async() =>
                {
                    await EnsureFuegoStartedAndMatchingGame(id);

                    _state.Operation = GoOperation.Undo;

                    // Note that resignation is stored as a single move, but fuego.exe doesn't know about resignations so
                    // no need to send an undo command to the engine.

                    int undo = 0;

                    if (_state.Status == GoGameStatus.Ended)
                    {
                        // GenMoveAsync() records the last PASS move, but it UNDOES the last generated PASS
                        // in our _fuego instance so that final_status_list dead will still reliably
                        // calculate dead stones (by simulation).
                        // Therefore, if status is Ended, we only need to remove one _fuege move
                        // while popping two items off of GoMoveHistory.
                        undo = 2;
                        ParseResponse(WriteCommand("gg-undo", "1"));
                    }
                    else if (_state.Status == GoGameStatus.BlackWonDueToResignation)
                    {
                        var humanColor = _state.Player1.PlayerType == PlayerType.Human ? GoColor.Black : GoColor.White;
                        undo           = humanColor == GoColor.Black ? 2 : 1;

                        if (_state.GoMoveHistory.Count > 1 &&
                            _state.GoMoveHistory[_state.GoMoveHistory.Count - 2].Move.Color == humanColor)
                        {
                            ParseResponse(WriteCommand("gg-undo", "1"));
                        }
                    }
                    else if (_state.Status == GoGameStatus.WhiteWonDueToResignation)
                    {
                        var humanColor = _state.Player1.PlayerType == PlayerType.Human ? GoColor.Black : GoColor.White;
                        undo           = humanColor == GoColor.White ? 2 : 1;

                        if (_state.GoMoveHistory.Count > 1 &&
                            _state.GoMoveHistory[_state.GoMoveHistory.Count - 2].Move.Color == humanColor)
                        {
                            ParseResponse(WriteCommand("gg-undo", "1"));
                        }
                    }
                    else
                    {
                        var his   = _state.GoMoveHistory;
                        var count = his.Count;

                        var humanColor = _state.Player1.PlayerType == PlayerType.Human ? GoColor.Black : GoColor.White;

                        // Reverse to before most recent human move.
                        for (int i = count - 1; i >= 0; i--)
                        {
                            if (his[i].Move.Color == humanColor)
                            {
                                undo = count - i;
                                break;
                            }
                        }

                        if (undo == 0)
                        {
                            throw new Exception("Can't undo because there are no human moves yet.");
                        }

                        ParseResponse(WriteCommand("gg-undo", undo.ToString(CultureInfo.InvariantCulture)));
                    }

                    UndoMoves(undo);

                    _state.Operation = GoOperation.Idle;

                    rval = new GoGameStateResponse(GoResultCode.Success, _state);

                    await SaveState();
                });
            }
            catch (GoEngineException gex)
            {
                rval = new GoGameStateResponse(gex.Code, null);
            }
            catch (Exception)
            {
                rval = new GoGameStateResponse(GoResultCode.InternalError, null);
            }

            Debug.Assert(rval != null, "rval != null");
            return(rval);
        }
예제 #8
0
        public async Task <GoGameStateResponse> UndoAsync(Guid gameid)
        {
            GoGameStateResponse rval = null;

            try
            {
                await Task.Factory.StartNew(
                    () =>
                {
                    EnsureFuegoStarted().Wait();

                    _state.Operation = GoOperation.Undo;
                    SaveState();

                    // Note that resignation is stored as a single move, but fuego.exe doesn't know about resignations so
                    // no need to send an undo command to the engine.

                    int undo = 0;

                    if (_state.Status == GoGameStatus.BlackWonDueToResignation)
                    {
                        var humanColor = _state.Player1.PlayerType == PlayerType.Human ? GoColor.Black : GoColor.White;
                        undo           = humanColor == GoColor.Black ? 2 : 1;

                        if (_state.GoMoveHistory.Count > 1 &&
                            _state.GoMoveHistory[_state.GoMoveHistory.Count - 2].Move.Color == humanColor)
                        {
                            ParseResponse(WriteCommand("gg-undo", "1"));
                        }
                    }
                    else if (_state.Status == GoGameStatus.WhiteWonDueToResignation)
                    {
                        var humanColor = _state.Player1.PlayerType == PlayerType.Human ? GoColor.Black : GoColor.White;
                        undo           = humanColor == GoColor.White ? 2 : 1;

                        if (_state.GoMoveHistory.Count > 1 &&
                            _state.GoMoveHistory[_state.GoMoveHistory.Count - 2].Move.Color == humanColor)
                        {
                            ParseResponse(WriteCommand("gg-undo", "1"));
                        }
                    }
                    else
                    {
                        var his   = _state.GoMoveHistory;
                        var count = his.Count;

                        var humanColor = _state.Player1.PlayerType == PlayerType.Human ? GoColor.Black : GoColor.White;

                        // Reverse to before most recent human move.
                        for (int i = count - 1; i >= 0; i--)
                        {
                            if (his[i].Move.Color == humanColor)
                            {
                                undo = count - i;
                                break;
                            }
                        }

                        if (undo == 0)
                        {
                            throw new Exception("Can't undo because there are no human moves yet.");
                        }

                        ParseResponse(WriteCommand("gg-undo", undo.ToString(CultureInfo.InvariantCulture)));
                    }

                    UndoMovesInState(undo);

                    _state.Operation = GoOperation.Idle;
                    SaveState();

                    rval = new GoGameStateResponse(GoResultCode.Success, _state);
                });
            }
            catch (GoEngineException gex)
            {
                rval = new GoGameStateResponse(gex.Code, null);
            }
            catch (Exception ex)
            {
                rval = new GoGameStateResponse(GoResultCode.ServerInternalError, null);
            }

            Debug.Assert(rval != null, "rval != null");
            return(rval);
        }
        private async void StartNewGame()
        {
            try
            {
                bool success             = false;
                GoGameStateResponse resp = null;

                for (int tries = 0; !AbortOperation && !success && tries < 5; tries++)
                {
                    BusyMessage = "Starting game...";
                    IsBusy      = true;

                    var tmpNewGame = Guid.NewGuid();

                    // Create game from user's selections.
                    var p1 = new GoPlayer();
                    var p2 = new GoPlayer();
                    if (Color == (int)GoColor.Black)
                    {
                        p1.Name       = Name;
                        p1.PlayerType = PlayerType.Human;

                        p2.Name       = "Fuego";
                        p2.PlayerType = PlayerType.AI;
                        p2.Level      = DifficultyLevel;
                    }
                    else
                    {
                        p2.Name       = Name;
                        p2.PlayerType = PlayerType.Human;

                        p1.Name       = "Fuego";
                        p1.PlayerType = PlayerType.AI;
                        p1.Level      = DifficultyLevel;
                    }
                    var tmpState = new GoGameState(
                        tmpNewGame,
                        (byte)BoardEdgeSize,
                        p1, p2,
                        GoGameStatus.Active,
                        GoColor.Black,
                        "",
                        "",
                        new List <GoMoveHistoryItem>(),
                        0);
                    resp = await DataRepository.StartAsync(tmpNewGame, tmpState);

                    BusyMessage = null;
                    IsBusy      = false;

                    ActiveGame = tmpNewGame;
                    success    = true;
                }

                if (AbortOperation)
                {
                    return;
                }

                if (success)
                {
                    NavService.Navigate("Game", ActiveGame);
                }
                else
                {
                    if (resp != null)
                    {
                        await DisplayErrorCode(resp.ResultCode);
                    }
                }
            }
            catch (Exception ex)
            {
            }
            finally
            {
                BusyMessage = null;
                IsBusy      = false;
            }
        }