/// <summary> /// Plays a sound if its is appropriate in the given state /// </summary> /// <param name="currentState">Current game tree node</param> protected async Task PlaySoundIfAppropriate(GameTreeNode state) { if (state.Branches.Count == 0) { // This is the final node. if (state.Move != null && state.Move.Kind != MoveKind.None) { bool humanPlayed = (Game.Controller.Players[state.Move.WhoMoves].IsHuman); bool notificationDemanded = (humanPlayed ? _gameSettings.Audio.PlayWhenYouPlaceStone : _gameSettings.Audio.PlayWhenOthersPlaceStone); if (notificationDemanded) { if (state.Move.Kind == MoveKind.PlaceStone) { await Sounds.PlaceStone.PlayAsync(); if (state.Move.Captures.Count > 0) { await Sounds.Capture.PlayAsync(); } } else if (state.Move.Kind == MoveKind.Pass) { await Sounds.Pass.PlayAsync(); } } } } }
public IShadowItem GetShadowItem(IToolServices toolService) { if (toolService.Node.Equals(toolService.GameTree.GameTreeRoot)) { int width = toolService.GameTree.BoardSize.Width; int height = toolService.GameTree.BoardSize.Height; MoveResult[,] moveResults = new MoveResult[width, height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { moveResults[x, y] = MoveResult.Legal; } } _currentNode = toolService.Node; } else if (!toolService.Node.Equals(_currentNode) || _currentNode == null) { _moveResults = toolService.Ruleset.GetMoveResult(toolService.Node); _currentNode = toolService.Node; } MoveResult result = _moveResults[toolService.PointerOverPosition.X, toolService.PointerOverPosition.Y]; StoneColor nextPlayer = toolService.Node.Move.WhoMoves.GetOpponentColor(toolService.Node, toolService.GameTree.GameTreeRoot); if (result == MoveResult.Legal) { return(new Stone(nextPlayer, toolService.PointerOverPosition)); } else { return(new None()); } }
private GameTreeNodeCallbackResultBehavior WalkGameTree(GameTreeNode node, int horizontalOffset, ref int verticalOffset, int parentVerticalOffset, GameTreeNodeCallback nodeResultCallback) { var resultBehavior = nodeResultCallback(node, horizontalOffset, verticalOffset, parentVerticalOffset); if (resultBehavior == GameTreeNodeCallbackResultBehavior.Stop) { return(resultBehavior); } int nodeOffset = verticalOffset; foreach (GameTreeNode childNode in node.Branches) { resultBehavior = WalkGameTree(childNode, horizontalOffset + 1, ref verticalOffset, nodeOffset, nodeResultCallback); if (resultBehavior == GameTreeNodeCallbackResultBehavior.Stop) { if (node.Branches.Count > 0) { verticalOffset--; } return(resultBehavior); } verticalOffset++; } if (node.Branches.Count > 0) { verticalOffset--; } return(GameTreeNodeCallbackResultBehavior.Continue); }
protected TsumegoProblem(string name, SgfGameTree tree, StoneColor colorToPlay) { this.Name = name; this.SgfGameTree = tree; this.ColorToPlay = colorToPlay; this.InitialTree = SpawnThisProblem(); }
private async Task InitializeVM(BoardViewModel viewModel) { if (viewModel == null) { return; } ViewModel.NodeChanged += (sender, node) => _currentGameTreeNode = node; _currentGameTreeNode = ViewModel.GameTreeNode; _boardControlState = ViewModel.BoardControlState; _renderService = new RenderService(_boardControlState); _inputService = new InputService(_boardControlState); await RenderService.AwaitResources(); canvas.Draw += canvas_Draw; canvas.Update += canvas_Update; canvas.PointerMoved += canvas_PointerMoved; canvas.PointerPressed += canvas_PointerPressed; canvas.PointerReleased += canvas_PointerReleased; canvas.PointerExited += Canvas_PointerExited; _inputService.PointerTapped += (sender, ev) => ViewModel.BoardTap(ev); }
public void TestFSimulateAllChildrenOnce() { UltimateBoard b = Games.GetBoard(Games.Draw, 53); b.Play((1, 0, 1, 0)); b.Play((1, 0, 0, 0)); b.Play((0, 1, 2, 0)); b.Play((1, 0, 1, 2)); // This board position has four available plays. GameTreeNode t = new GameTreeNode((1, 0, 1, 2)); for (int i = 0; i < 5; i++) { // The second iteration adds the four children and does a simulation on one // of them. The next three should each do a simulation on a different child // without adding any grandchildren. t.Simulate(new UltimateBoard(b)); } List <(int, int, int, int)> avail = b.GetAvailablePlays(); StringBuilder results = new StringBuilder(); foreach ((int, int, int, int)play in avail) { GameTreeNode grandchild = null; try { grandchild = t.GetChild(play).GetChild((1, 0, 0, 2)); // (1, 0, 0, 2) is an available response to each available play. results.Append(grandchild.Play.ToString()); } catch // The above will throw an exception if the grandchild hasn't been added. { results.Append("OK;"); } } Assert.That(results.ToString(), Is.EqualTo("OK;OK;OK;OK;")); // t should not contain any of the grandchildren. }
public void TestCSimulateDraw() { UltimateBoard b = Games.GetBoard(Games.Draw, Games.Draw.Length); GameTreeNode t = new GameTreeNode(Games.Draw[Games.Draw.Length - 1]); Assert.That(t.Simulate(b), Is.EqualTo(0.5f)); }
public GameTreeAction <A> GetBestAction(int depth) { if (depth != 0) { GameTreeAction <A> bestAction = null; var nextDepth = depth - 1; foreach (var nextAction in NodeData.GetNextActions(NodeColor)) { nextAction.score = CurrentScore + (NodeColor.IsRed ? nextAction.score : -nextAction.score); var nextNode = new GameTreeNode <D, A>(this, nextAction); var bestNextAction = nextNode.GetBestAction(nextDepth); if (TestAndUpdateThreshold(bestNextAction.score)) { bestAction = bestNextAction; if (NeedsCutTreeNode()) { break; } } } if (nodeParent == null) { return(bestAction); } if (bestAction != null) { nodeAction.score = bestAction.score; } } return(nodeAction); }
/// <summary> /// Sets the provided node as the selected node. /// LiveGameViewModel gets also notified about the change. /// </summary> /// <param name="node">a node to set as selected</param> public void SetSelectedNode(GameTreeNode node) { // Set selected node, this also rises redraw request in the UWP.UI SelectedGameTreeNode = node; // Notify the ViewModel about the change OnGameTreeSelectionChanged(); }
private void DrawStones(GameTreeNode gameState, CanvasDrawingSession session) { if (gameState != null) { if (gameState.Tsumego.MarkedPositions.Any() && _settings.Tsumego.ShowPossibleMoves) { foreach (var position in gameState.Tsumego.MarkedPositions) { DrawStoneCellBackground(session, position.X, position.Y, Color.FromArgb(100, 255, 50, 0)); } } GameBoard boardState = gameState.BoardState; for (int x = SharedBoardControlState.OriginX; x < this.SharedBoardControlState.BoardWidth + SharedBoardControlState.OriginX; x++) { for (int y = SharedBoardControlState.OriginY; y < this.SharedBoardControlState.BoardHeight + SharedBoardControlState.OriginY; y++) { int translatedYCoordinate = (this.SharedBoardControlState.BoardHeight - y - 1); if (boardState[x, y] != StoneColor.None) { DrawStone(session, x, y, boardState[x, y], 1); if (_highlightLastMove) { if (gameState?.Move?.Kind == MoveKind.PlaceStone && gameState.Move.Coordinates.X == x && gameState.Move.Coordinates.Y == y) { session.DrawEllipse( new Vector2( (x - SharedBoardControlState.OriginX) * _cellSize + _halfSize, (translatedYCoordinate + SharedBoardControlState.OriginY) * _cellSize + _halfSize), _cellSize * 0.2f, _cellSize * 0.2f, boardState[x, y] == StoneColor.White ? Colors.Black : Colors.White, 3); } } } if (SharedBoardControlState.ShowTerritory && SharedBoardControlState.TerritoryMap != null) { if (SharedBoardControlState.TerritoryMap.DeadPositions.Contains(new Position(x, y))) { DrawCrossOutMark(session, x, y, Colors.Red, Colors.Transparent); } DrawTerritoryMark(session, x, y, SharedBoardControlState.TerritoryMap.Board[x, y]); } } } } }
private TreeNode <LabeledState <GameState, TOutput> > GetFullTree(GameTreeNode <GameState, GameAction> gameNode, ITreeValueEvaluator <GameState, LabeledState <GameState, TOutput> > outputFunction) { TreeNode <LabeledState <GameState, TOutput> > result; if (gameNode.Children.Count == 0) { var output = outputFunction.EvaluateLeaf(gameNode.State); result = new TreeNode <LabeledState <GameState, TOutput> >(output); } else { result = new TreeNode <LabeledState <GameState, TOutput> >(); foreach (var childState in gameNode.Children) { TreeNode <LabeledState <GameState, TOutput> > child = GetFullTree(childState.Value, outputFunction); result.Children.Add(child); } IEnumerable <LabeledState <GameState, TOutput> > childrenStates = result.Children.Select(c => c.Data); result.Data = outputFunction.EvaluateNode(gameNode.State, childrenStates); } return(result); }
/// <summary> /// the computers play /// </summary> private void ComputerPlay() { DisableAllButtons(); uxTextBox.Text = "My Turn."; Update(); for (int i = 0; i < 25000; i++) { UltimateBoard temp = new UltimateBoard(_currentGamePosition); _portionOfGameTree.Simulate(temp); } GameTreeNode t = _portionOfGameTree.GetBestChild(); (int, int, int, int)p = t.Play; _currentGamePosition.Play(p); uxFlowLayoutPanel.Controls[p.Item1].Controls[p.Item2].Controls[p.Item3].Controls[p.Item4].Text = _SymbolOComputer; if (!GameIsover("I")) { _portionOfGameTree = t; foreach ((int, int, int, int)loc in _currentGamePosition.GetAvailablePlays()) { uxFlowLayoutPanel.Controls[loc.Item1].Controls[loc.Item2].Controls[loc.Item3].Controls[loc.Item4].Enabled = true; } uxTextBox.Text = "Your Turn."; } }
public IShadowItem GetShadowItem(IToolServices toolServices) { if (_shadows == null || !toolServices.Node.Equals(_currentNode)) { _shadows = toolServices.Node.Markups.FillSimpleShadowMap(toolServices.GameTree.BoardSize, SimpleMarkup); _currentNode = toolServices.Node; } char shadow = _shadows[toolServices.PointerOverPosition.X, toolServices.PointerOverPosition.Y]; if (shadow == 'r') { return(new None()); } else { switch (SimpleMarkup) { case SimpleMarkupKind.Circle: return(new Circle(toolServices.PointerOverPosition)); case SimpleMarkupKind.Cross: return(new Cross(toolServices.PointerOverPosition)); case SimpleMarkupKind.Square: return(new Square(toolServices.PointerOverPosition)); case SimpleMarkupKind.Triangle: return(new Triangle(toolServices.PointerOverPosition)); } } return(new None()); }
private void LoadProblem(TsumegoProblem problem) { Rectangle rect = problem.GetBoundingBoard(); BoardViewModel.BoardControlState.OriginX = rect.X; BoardViewModel.BoardControlState.OriginY = rect.Y; BoardViewModel.BoardControlState.BoardWidth = rect.Width; BoardViewModel.BoardControlState.BoardHeight = rect.Height; _currentProblem = problem; _currentProblemTree = _currentProblem.SpawnThisProblem(); CurrentProblemName = _currentProblem.Name; CurrentProblemInstructions = _currentProblemTree.Comment; CurrentNode = _currentProblemTree; _playerToMove = _currentProblem.ColorToPlay; _humansColor = _playerToMove; if (_humansColor == StoneColor.Black) { CurrentNodeStatus = Localizer.Tsumego_BlackToPlay; } else { CurrentNodeStatus = Localizer.Tsumego_WhiteToPlay; } WrongVisible = false; CorrectVisible = false; GoToPreviousProblemCommand.RaiseCanExecuteChanged(); GoToNextProblemCommand.RaiseCanExecuteChanged(); UndoOneMoveCommand.RaiseCanExecuteChanged(); RaisePropertyChanged(nameof(CurrentProblemPermanentlySolved)); }
protected override async void OnCurrentNodeChanged(GameTreeNode newNode) { ITabInfo tabInfo = Mvx.Resolve <ITabProvider>().GetTabForViewModel(this); // This method is invoked by an event coming from Controller // If we are in the analyze mode, we want to change current node manually. if (IsAnalyzeModeEnabled) { // Notify Timeline VM that the game timeline has changed GameTreeViewModel.RaiseGameTreeChanged(); await PlaySoundIfAppropriate(newNode); tabInfo.IsBlinking = true; return; } // TODO (future work) Martin validate this hotfix // With handicap this method is fired much sooned and the ViewModel is not yet set, returning null. // Check for this case. if (newNode != null && tabInfo != null) { if (!IsTimelineInPast) { RefreshBoard(Game.Controller.GameTree.LastNode); // TODO (future work) Vita, Aniko: This will not work well with neither timeline nor analyze mode, I think } UpdateTimeline(); RefreshInstructionCaption(); // It is ABSOLUTELY necessary for this to be the last statement in this method, // because we need the UpdateTimeline calls to be in order. await PlaySoundIfAppropriate(newNode); tabInfo.IsBlinking = true; } }
public void Execute(IToolServices toolService) { StoneColor previousPlayer = toolService.Node.Move.WhoMoves; StoneColor nextPlayer = StoneColor.None; //set next player if (previousPlayer == StoneColor.White) { nextPlayer = StoneColor.Black; } else if (previousPlayer == StoneColor.Black) { nextPlayer = StoneColor.White; } else { if (toolService.Node.Equals(toolService.GameTree.GameTreeRoot)) { nextPlayer = StoneColor.Black; } else { nextPlayer = StoneColor.White; } } GameTreeNode newNode = new GameTreeNode(Move.Pass(nextPlayer)); newNode.BoardState = new GameBoard(toolService.Node.BoardState); newNode.GroupState = new GroupState(toolService.Node.GroupState, toolService.Ruleset.RulesetInfo); toolService.Node.Branches.AddNode(newNode); toolService.SetNode(newNode); toolService.PlayPassSound(); }
/// <summary> /// There are two ways to score. One is based on territory, the other on area. /// This method uses the appropriate counting method according to the used ruleset and players' agreement. /// </summary> /// <param name="currentNode">Node of tree representing the previous move.</param> /// <param name="deadPositions">List of dead stones.</param> /// <param name="komi">Komi compensation.</param> /// <returns>The score of players.</returns> public override Scores CountScore(GameTreeNode currentNode, IEnumerable <Position> deadPositions, float komi) { Scores scores; if (_countingType == CountingType.Area) { scores = CountArea(currentNode, deadPositions); } else { scores = CountTerritory(currentNode, deadPositions); } //passing = 1 bonus point to opponent IEnumerable <GameTreeNode> history = currentNode.GetNodeHistory(); foreach (GameTreeNode node in history) { if (node.Move.Kind == MoveKind.Pass) { if (node.Move.WhoMoves == StoneColor.Black) { scores.WhiteScore++; } else if (node.Move.WhoMoves == StoneColor.White) { scores.BlackScore++; } } } scores.WhiteScore += komi; return(scores); }
// Calculating pointer over node private GameTreeNode GetNodeAtPoint(Point point, GameTreeNode node) { GameTreeNode resultNode = null; int resultVerticalOffset = 0; WalkGameTree(node, 0, ref resultVerticalOffset, 0, (currentNode, horizontalOffset, verticalOffset, parentVerticalOffset) => { Rect nodeRect = new Rect( horizontalOffset * NODESIZE + horizontalOffset * NODESPACING, verticalOffset * NODESIZE + verticalOffset * NODESPACING, NODESIZE, NODESIZE); if (nodeRect.Contains(point)) { resultNode = currentNode; return(GameTreeNodeCallbackResultBehavior.Stop); } return(GameTreeNodeCallbackResultBehavior.Continue); }); return(resultNode); }
public void TestCSimulateOWin() { UltimateBoard b = Games.GetBoard(Games.OWins, Games.OWins.Length); GameTreeNode t = new GameTreeNode(Games.OWins[Games.OWins.Length - 1]); Assert.That(t.Simulate(b), Is.EqualTo(1)); }
private void SwitchToNextLevelNode() { GameTreeNode node = ViewModel.SelectedGameTreeNode; GameTreeNode nodeParent = ViewModel.SelectedGameTreeNode.Parent; int targetMoveNumber = node.MoveNumber; int searchMoveNumber = targetMoveNumber; while (nodeParent != null) { int nodeBranchIndex = nodeParent.Branches.IndexOf(node); // Search previous siblings for (int i = nodeBranchIndex + 1; i < nodeParent.Branches.Count; i++) { GameTreeNode searchNode = SwitchToNextLevelNodeDFS(nodeParent.Branches[i], searchMoveNumber, targetMoveNumber); if (searchNode != null) { ViewModel.SetSelectedNode(searchNode); return; } } node = nodeParent; nodeParent = nodeParent.Parent; searchMoveNumber--; } }
public void TestDFirstSimulation() { UltimateBoard b = Games.GetBoard(Games.Draw, 53); b.Play((1, 0, 1, 0)); b.Play((1, 0, 0, 0)); b.Play((0, 1, 2, 0)); b.Play((1, 0, 1, 2)); b.Play((0, 2, 0, 1)); // This board position has only one available play. GameTreeNode t = new GameTreeNode((0, 2, 0, 1)); float score = t.Simulate(b); GameTreeNode child = null; try { child = t.GetChild((1, 0, 0, 2)); // The only possible child. } catch (Exception) { // Ignore any exception. } Assert.Multiple(() => { Assert.That(score, Is.EqualTo(0)); // The only play wins for the opponent. Assert.That(child, Is.Null); // Check that no child was retrieved. }); }
//////////////// // Game View Model Services //////////////// protected void RefreshBoard(GameTreeNode boardState) { BoardViewModel.GameTreeNode = boardState; BoardViewModel.BoardControlState.TEMP_MoveLegality = Game.Controller.Ruleset.GetMoveResult(boardState); // TODO (future work) Petr: GameTree has now LastNodeChanged event - use it to fix this - for now make public and. Called from GameViewModel BoardViewModel.Redraw(); }
private GameTreeNode MinMax(GameState currentState, int depth, double alpha, double beta, bool maximizingPlayer) { GameTreeNode bestMove = null; if (depth == 0 || currentState.WinningPlayer != PlayerNumber.None) { double evaluation = heuristic.Evaluate(currentState); bestMove = new GameTreeNode(currentState, evaluation); } else if (maximizingPlayer) { double maxEval = double.NegativeInfinity; List <GameState> nextStates = currentState.GetAllPossibleNextStates(PlayerNumber.FirstPlayer); foreach (var nextState in nextStates) { GameTreeNode bestChild = MinMax(nextState, depth - 1, alpha, beta, false); if (bestChild == null) { currentState.GetAllPossibleNextStates(PlayerNumber.FirstPlayer); } if (maxEval < bestChild.Evaluation) { bestMove = new GameTreeNode(nextState, bestChild.Evaluation); maxEval = bestChild.Evaluation; } alpha = Math.Max(alpha, bestChild.Evaluation); if (beta <= alpha) { break; } } } else { double minEval = double.PositiveInfinity; List <GameState> nextStates = currentState.GetAllPossibleNextStates(PlayerNumber.SecondPlayer); foreach (var nextState in nextStates) { GameTreeNode bestChild = MinMax(nextState, depth - 1, alpha, beta, true); if (bestChild == null) { currentState.GetAllPossibleNextStates(PlayerNumber.SecondPlayer); } if (minEval > bestChild.Evaluation) { bestMove = new GameTreeNode(nextState, bestChild.Evaluation); minEval = bestChild.Evaluation; } beta = Math.Min(beta, bestChild.Evaluation); if (beta <= alpha) { break; } } } return(bestMove); }
public void CustomNodeInfoCanBeCreatedWithFunctor() { GameTreeNode node = new GameTreeNode(); var info = node.GetOrCreateNodeInfo(() => new TestGameTreeNodeInfo("test")); Assert.IsNotNull(info); Assert.AreEqual("test", info.TestInfo); }
public void CustomNodeInfoCanBeCreatedAutomatically() { GameTreeNode node = new GameTreeNode(Move.NoneMove); var info = node.GetOrCreateNodeInfo <TestGameTreeNodeInfo>(); Assert.IsNotNull(info); Assert.AreEqual("hello", info.TestInfo); }
/// <summary> /// There are two ways to score. One is based on territory, the other on area. /// This method uses the appropriate counting method according to the used ruleset and players' agreement. /// </summary> /// <param name="currentNode">Node of tree representing the previous move.</param> /// <param name="deadPositions">List of dead stones.</param> /// <param name="komi">Komi compensation.</param> /// <returns>The score of players.</returns> public override Scores CountScore(GameTreeNode currentNode, IEnumerable <Position> deadPositions, float komi) { var scores = CountArea(currentNode, deadPositions); scores.WhiteScore += komi; return(scores); }
private void SwitchToFirstChildNode() { GameTreeNode node = ViewModel.SelectedGameTreeNode; if (node.NextNode != null) { ViewModel.SetSelectedNode(node.NextNode); } }
private void SwitchToParentNode() { GameTreeNode node = ViewModel.SelectedGameTreeNode; if (node.Parent != null) { ViewModel.SetSelectedNode(node.Parent); } }
//////// // // IToolServices public API implementation // // - this is intended to be used only by ITools. //////// public void SetNode(GameTreeNode node) { if (node == null) { throw new ArgumentException($"{nameof(node)} cant be null"); } Node = node; NodeChanged?.Invoke(this, node); }
public void ModificationsOfNodeInfoOutsideArePreserved() { GameTreeNode node = new GameTreeNode(); var info = node.GetOrCreateNodeInfo <TestGameTreeNodeInfo>(); info.TestInfo = "new value"; var newInfo = node.GetOrCreateNodeInfo <TestGameTreeNodeInfo>(); Assert.AreEqual("new value", newInfo.TestInfo); }
private void AssertExpectedResult( GameTreeNode<int> root, int ply, int expected ) { var ai1 = CreateMinimax( ply ); var ai2 = CreateMinimaxAlphaBeta( ply ); var m1 = ai1.FindBestMove( root ); var m2 = ai2.FindBestMove( root ); Assert.AreEqual( expected, m1 ); Assert.AreEqual( expected, m2 ); }