/// <summary> /// Gets all the possible nodes for a given position /// </summary> /// <param name="position">Positional node</param> public List <PositionNode> GetNodes(Position position, sbyte team) { List <PositionNode> nodes = new List <PositionNode>(); sbyte winner = -1; if (position.IsWon(out winner)) { return(nodes); } DiceRoll[] rolls = GetRollsQueue(position, team); for (int r = 0; r < rolls.Length; r++) { MoveCollection collection = GetMoves(position, rolls[r], team); if (collection != null) { PositionNode[] pnodes = new PositionNode[collection.Count]; for (int i = 0; i < collection.Count; i++) { Position node = position.Clone(); PerformMove(node, collection[i]); pnodes[i] = new PositionNode(node, collection[i], rolls[r]); } nodes.AddRange(pnodes); } } return(nodes); }
/// <summary> /// Thinks about the current position given the dice roll and calculates the best move /// </summary> /// <param name="algorithm">Evaluation algorithm to use</param> /// <param name="roll">Roll</param> /// <param name="team">Team to think for</param> /// <param name="depth">Depth to think</param> public Move ThinkBest(Algorithm algorithm, DiceRoll roll, sbyte team, int ms) { MoveCollection collection = GetMoves(roll, team); if (collection.Count == 0) { return(null); } else if (collection.Count == 1) { return(collection[0]); } else if (ms < 0) { return(collection[random.Next(collection.Count)]); } PositionNode[] nodes = new PositionNode[collection.Count]; for (int i = 0; i < collection.Count; i++) { Position node = new Position(this.quadrants); PerformMove(node, collection[i]); nodes[i] = new PositionNode(node, collection[i], roll); } algorithm.Player = team; Vector4[] evaluations = new Vector4[nodes.Length]; for (int j = 0; j < nodes.Length; j++) { PositionNode currentRootMoveNode = nodes[j]; algorithm.Root = currentRootMoveNode; Vector4 moveEval = algorithm.Go(ms / collection.Count); evaluations[j] = moveEval; } int highIndex = 0; double high = evaluations[0].GetMagnitude(team); for (int i = 1; i < evaluations.Length; i++) { double curMag = evaluations[i].GetMagnitude(team); if (curMag > high) { high = curMag; highIndex = i; } } return(collection[highIndex]); }
/// <summary> /// Checks if the move is a possible move for a human (called by Engine) /// </summary> /// <param name="move">Move move</param> public bool IsPossibleMove(DiceRoll roll, Move move, out Move orderCorrect) { MoveCollection collection = GetMoves(roll, move.Team); for (int j = 0; j < collection.Count; j++) { if (collection[j].Equals(move)) { orderCorrect = collection[j]; return(true); } } orderCorrect = null; return(false); }
public MoveCollection ThinkAll(Algorithm algorithm, DiceRoll roll, sbyte team, int ms, out Vector4[] scores) { MoveCollection collection = GetMoves(roll, team); if (collection.Count == 0) { scores = null; return(null); } else if (collection.Count == 1) { scores = new Vector4[1] { algorithm.Eval(this.GetPosition(), roll.IsDoubles() ? team : Board.NO_PLAYER) }; return(collection); } if (ms < 0) { throw new ArgumentException(); } PositionNode[] nodes = new PositionNode[collection.Count]; for (int i = 0; i < collection.Count; i++) { Position node = new Position(this.quadrants); PerformMove(node, collection[i]); nodes[i] = new PositionNode(node, collection[i], roll); } algorithm.Player = team; Vector4[] evaluations = new Vector4[nodes.Length]; for (int j = 0; j < nodes.Length; j++) { PositionNode currentRootMoveNode = nodes[j]; algorithm.Root = currentRootMoveNode; Vector4 moveEval = algorithm.Go(ms / collection.Count); evaluations[j] = moveEval; } SortDecreasing(evaluations, collection, team); scores = evaluations; return(collection); }
/// <summary> /// Checks if the piece move is part of a valid move /// </summary> /// <param name="roll">Current roll</param> /// <param name="move">Move to check</param> /// <param name="team">Team</param> public bool IsPossibleTreeMove(DiceRoll roll, PieceMove move, sbyte team) { MoveCollection collection = GetMoves(roll, team); for (int j = 0; j < collection.Count; j++) { PieceMove[] moves = collection[j].PieceMoves; for (int i = 0; i < moves.Length; i++) { if (moves[i].Equals(move)) { return(true); } } } return(false); }
/// <summary> /// Starts thinking /// </summary> public void Think(DiceRoll roll, Board board) { int timeThink = Difficulty.TimeThink; Algorithm algorithm = GetAlgorithm(); if (timeThink < 0) { base.SetMove(board.ThinkBest(algorithm, roll, Team, timeThink)); return; } int blunderValue = Board.Next(100); if (blunderValue < Difficulty.BlunderPercent) { //Worst move Vector4[] scores; MoveCollection moves = board.ThinkAll(algorithm, roll, Team, ComputerPlayer.Difficulties[ComputerPlayer.Difficulties.Length - 1].TimeThink, out scores); LastEvaluation = GetVariations(moves, scores); if (moves != null) { base.SetMove(moves[moves.Count - 1]); return; } } else { //Best move Vector4[] scores; MoveCollection moves = board.ThinkAll(algorithm, roll, Team, Difficulty.TimeThink, out scores); LastEvaluation = GetVariations(moves, scores); if (moves != null) { base.SetMove(moves[0]); return; } } base.SetMove(null); }
/// <summary> /// Stable insertion sort /// </summary> /// <param name="input">Input of move evaluations</param> /// <param name="collection">Move values</param> /// <param name="team">Team to sort by</param> private void SortDecreasing(Vector4[] input, MoveCollection collection, sbyte team) { for (int i = 1; i < input.Length; i++) { double key = input[i].GetMagnitude(team); Vector4 keyValue = input[i]; Move moveValue = collection[i]; int j = i - 1; while (j >= 0 && input[j].GetMagnitude(team) < key) { input[j + 1] = input[j]; collection[j + 1] = collection[j]; j--; } input[j + 1] = keyValue; collection[j + 1] = moveValue; } }
private Variation[] GetVariations(MoveCollection moves, Vector4[] scores) { if (scores == null) { return(null); } if (moves.Count != scores.Length) { throw new ArgumentException(); } Variation[] vars = new Variation[moves.Count]; for (int i = 0; i < moves.Count; i++) { vars[i] = new Variation(moves[i], scores[i]); } return(vars); }
private double Iterate(Position pos, sbyte us, sbyte evaluating_team, int time) { Stopwatch sw = Stopwatch.StartNew(); double wins = 0; double losses = 0; Board board = new Board(); sbyte team = NextTeam(us); int doublesCount = 0; sbyte lastTeam = 0; int turns = 0; do { //Reset board board.SetPosition(pos); //Pick random nodes and play out game while (!board.IsGameOver()) { lastTeam = team; DiceRoll roll = board.GetRandomRoll(); MoveCollection moves = board.GetMoves(roll, team); if (moves.Count != 0) { Move m = moves[Board.Next(moves.Count)]; if (m != null) { board.PerformMove(m); } } if (roll.IsDoubles()) { doublesCount++; if (doublesCount >= 3) { board.RemoveFrontMarble(team); doublesCount = 0; team = board.NextPlayer(team); turns++; } } else { doublesCount = 0; team = board.NextPlayer(team); turns++; } } if (lastTeam == evaluating_team) { wins++; } else { losses++; } }while (sw.ElapsedMilliseconds < time); return(wins / losses); }
/// <summary> /// Gets all the possible moves for a team given a dice roll /// </summary> /// <param name="roll">Dice roll</param> /// <param name="team">Marble team</param> public MoveCollection GetMoves(Position position, DiceRoll roll, sbyte team) { if (team < 0 || team > TEAM_COUNT) { return(null); } sbyte winner = -1; if (position.IsWon(out winner)) { return(null); } MoveCollection moves = new MoveCollection(this, position); Square[] marbleSquares = GetMarbles(position, team); bool hasMarbleOnSpawn = position.Get(new Square(team, 0)) == team; int activePieces = GetActivePiecesCount(marbleSquares); //Loop until a marble in our base is found for (int i = 0; i < marbleSquares.Length; i++) { //If marble is at start square if (marbleSquares[i] == null) { //If no team marble is on spawn square if (!hasMarbleOnSpawn) { int[] takeOut = roll.CanTakeOutWith(); if (takeOut.Length > 0) { for (int j = 0; j < takeOut.Length; j++) { Square target = new Square(team, takeOut[j]); if (position.Get(target) != team) { moves.Add(new Move(new PieceMove(null, target), team)); } } } } //Add a special case for taking out a piece and using the other die value on another marble if (activePieces > 0) { int[] combinations = roll.GetDoublesTakeOutCombinations(); PieceMove takeOutCombo = new PieceMove(null, new Square(team, 0)); for (int p = 0; p < activePieces; p++) { for (int pc = 0; pc < combinations.Length; pc++) { PieceMove correspondant = new PieceMove(marbleSquares[p], marbleSquares[p].Add(combinations[pc], team)); if (hasMarbleOnSpawn && !correspondant.From.Equals(takeOutCombo.To)) { continue; } moves.Add(new Move(new PieceMove[] { correspondant, takeOutCombo }, team)); } } } break; } } List <int[]> pieceCombinations = GetPieceCombinations(activePieces); for (int c = 0; c < pieceCombinations.Count; c++) { int pieces = pieceCombinations[c].Length; int[][] pieceValues = roll.GetValues(pieces); for (int k = 0; k < pieceValues.Length; k++) { PieceMove[] pieceMoves = new PieceMove[pieces]; for (int j = 0; j < pieces; j++) { Square marblePiece = marbleSquares[pieceCombinations[c][j]]; pieceMoves[j] = new PieceMove(marblePiece, marblePiece.Add(pieceValues[k][j], team)); if (j > 0) { if (pieceMoves[j].From.Equals(pieceMoves[j - 1].To)) { //Swap the move order PieceMove current = pieceMoves[j]; pieceMoves[j] = pieceMoves[j - 1]; pieceMoves[j - 1] = current; } } } Move move = new Move(pieceMoves, team); moves.Add(move); } } return(moves); }
/// <summary> /// Updates the view of the board /// </summary> /// <param name="gameTime">Current GameTime</param> public void Update(GameTime gameTime) { //Update logic KeyboardState kState = Keyboard.GetState(); MouseState mState = MouseHandle.GetState(); //Updates squares UpdateSquares(); if (Playing) { //Update current animation if (currentAnimation != null) { currentAnimation.Update(gameTime); } if (kState.IsKeyDown(Keys.Q) && rollOver) { for (int i = 0; i < currentMove.Count; i++) { if (currentMove[i].IsTakingOutMarble) { PutBackMarble(currentPlayer.Team); } } RemoveMove(); } if (!currentPlayer.IsThinking && CanRoll()) { if (!currentPlayer.IsHuman) { rollOver = false; RollDice(gameTime); } else if (!isDiceRolling && kState.IsKeyDown(Keys.R)) //Check for user starting a roll { rollOver = false; RollDice(gameTime); } } //Check if dice are done rolling if (die1 != -1 && die2 != -1 && !rollOver) { currentRoll = new DiceRoll(die1, die2); OnRollFinished(); } //Check if dice have rolled for too long if (rollStartTime.HasValue) { TimeSpan timeElapsed = gameTime.TotalGameTime.Subtract(rollStartTime.Value); double timeElapsedMs = timeElapsed.TotalMilliseconds; if (timeElapsedMs >= 10000) { StopDice(); UpdateDie(die1Body, ref die1, true); UpdateDie(die2Body, ref die2, true); if (die1 != -1 && die2 != -1) { currentRoll = new DiceRoll(die1, die2); OnRollFinished(); } } } //If the player is a human and hasnt rolled yet, disallow any movement of marbles if (!CanRoll()) { //Update drag UpdateDrag(mState); ////Handle user submitting move if (rollOver && kState.IsKeyDown(Keys.Enter) && currentPlayer.IsHuman) { if (!HasMove) { //Pressed enter without making a move MoveCollection collection = board.GetMoves(currentRoll, currentPlayer.Team); if (collection.Count == 0) { //End the player step ProcessRoll(); SetReadyForRoll(); // } } else { if (currentRoll == null) { RemoveMove(); } else { Move move = GetMove(currentPlayer.Team); if (board.IsPossibleMove(currentRoll, move, out move)) { currentPlayer.SetMove(move); } else { for (int i = 0; i < currentMove.Count; i++) { if (currentMove[i].IsTakingOutMarble) { PutBackMarble(currentPlayer.Team); } } RemoveMove(); } } } } } if (currentPlayer.HasMove) { OnMoveFound(currentPlayer.GetMove()); } //Update dice UpdateDie(die1Body, ref die1, IsNearlyZero(die1Body.LinearVelocity)); UpdateDie(die2Body, ref die2, IsNearlyZero(die2Body.LinearVelocity)); if (!Resizing) { world.Step(1 / 30f, false); //world.Step((float)gameTime.TotalGameTime.TotalSeconds, false, (float)gameTime.ElapsedGameTime.TotalSeconds, 1); } } }