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); }
/// <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); }
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); }
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); }
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); }
// 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(); } }
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); }
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; } }