private MoveSet GetValidGrasshopperMovements(Piece targetPiece) { MoveSet validMoves = new MoveSet(); Position startingPosition = targetPiece.Position; foreach (Direction direction in EnumUtils.Directions) { Position landingPosition = startingPosition.NeighborAt(direction); int distance = 0; while (HasPieceAt(landingPosition)) { // Jump one more in the same direction landingPosition = landingPosition.NeighborAt(direction); distance++; } if (distance > 0) { // Can only move if there's at least one piece in the way Move move = new Move(targetPiece.PieceName, landingPosition); validMoves.Add(move); } } return(validMoves); }
private MoveSet GetValidSpiderMovements(Piece targetPiece) { MoveSet validMoves = new MoveSet(); // Get all slides up to 2 spots away MoveSet upToTwo = GetValidSlides(targetPiece, 2); if (upToTwo.Count > 0) { // Get all slides up to 3 spots away MoveSet upToThree = GetValidSlides(targetPiece, 3); if (upToThree.Count > 0) { // Get all slides ONLY 3 spots away upToThree.Remove(upToTwo); if (upToThree.Count > 0) { validMoves.Add(upToThree); } } } return(validMoves); }
private MoveSet GetValidMoves(PieceName pieceName) { if (null == _cachedValidMovesByPiece) { _cachedValidMovesByPiece = new MoveSet[EnumUtils.NumPieceNames]; } int pieceNameIndex = (int)pieceName; if (null != _cachedValidMovesByPiece[pieceNameIndex]) { // MoveSet is cached in L1 cache ValidMoveCacheMetricsSet["ValidMoves." + EnumUtils.GetShortName(pieceName)].Hit(); } else { // MoveSet is not cached in L1 cache ValidMoveCacheMetricsSet["ValidMoves." + EnumUtils.GetShortName(pieceName)].Miss(); // Calculate MoveSet Piece targetPiece = GetPiece(pieceName); MoveSet moves = GetValidMovesInternal(targetPiece); moves.Lock(); // Populate cache _cachedValidMovesByPiece[pieceNameIndex] = moves; } return(_cachedValidMovesByPiece[pieceNameIndex]); }
private MoveSet GetValidPillbugSpecialAbilityMovements(Piece targetPiece) { MoveSet validMoves = new MoveSet(); Position positionAboveTargetPiece = targetPiece.Position.GetAbove(); for (int dir = 0; dir < EnumUtils.NumDirections; dir++) { Position neighbor = targetPiece.Position.NeighborAt(dir); Piece piece = GetPiece(neighbor); if (null != piece && piece.PieceName != LastPieceMoved && null == piece.PieceAbove && CanMoveWithoutBreakingHive(piece)) { // Piece can be moved Move firstMove = new Move(piece.PieceName, positionAboveTargetPiece); if (GetValidBeetleMovements(piece).Contains(firstMove)) { // Piece can be moved on top Position pieceStartingPosition = piece.Position; MovePiece(piece, positionAboveTargetPiece, false); foreach (Move secondMove in GetValidBeetleMovements(piece)) { if (secondMove.Position.Stack == 0 && secondMove.Position != pieceStartingPosition) { validMoves.Add(secondMove); } } MovePiece(piece, pieceStartingPosition, false); } } } return(validMoves); }
private void SetCurrentPlayerMetrics() { bool pullbugEnabled = EnumUtils.IsEnabled(BugType.Pillbug, ExpansionPieces); bool mosquitoEnabled = EnumUtils.IsEnabled(BugType.Mosquito, ExpansionPieces); MoveSet pillbugMoves = pullbugEnabled ? GetValidMoves(CurrentTurnColor == PlayerColor.White ? PieceName.WhitePillbug : PieceName.BlackPillbug) : null; MoveSet mosquitoMoves = pullbugEnabled && mosquitoEnabled?GetValidMoves(CurrentTurnColor == PlayerColor.White?PieceName.WhiteMosquito : PieceName.BlackMosquito) : null; foreach (PieceName pieceName in CurrentTurnPieces) { Piece targetPiece = GetPiece(pieceName); if (null != targetPiece) { if (targetPiece.InPlay) { _boardMetrics.PiecesInPlay++; _boardMetrics[pieceName].InPlay = 1; } else { _boardMetrics.PiecesInHand++; _boardMetrics[pieceName].InPlay = 0; } // Move metrics bool isPinned = IsPinned(pieceName, out _boardMetrics[pieceName].NoisyMoveCount, out _boardMetrics[pieceName].QuietMoveCount); if (isPinned && pullbugEnabled) { bool pullbugCanMove = pillbugMoves.Contains(pieceName); bool mosquitoCanMove = mosquitoEnabled && mosquitoMoves.Contains(pieceName); if (targetPiece.BugType == BugType.Pillbug) { // Check if the current player's mosquito can move it isPinned = !mosquitoCanMove; } else if (targetPiece.BugType == BugType.Mosquito) { // Check if the current player's pillbug can move it isPinned = !pullbugCanMove; } else { // Check if the current player's pillbug or mosquito can move it isPinned = !(mosquitoCanMove || pullbugCanMove); } } _boardMetrics[pieceName].IsPinned = isPinned ? 1 : 0; _boardMetrics[pieceName].IsCovered = targetPiece.InPlay && null != targetPiece.PieceAbove ? 1 : 0; CountNeighbors(targetPiece, out _boardMetrics[pieceName].FriendlyNeighborCount, out _boardMetrics[pieceName].EnemyNeighborCount); } } }
public async Task <long?> ParallelPerftAsync(int depth, int maxThreads, CancellationToken token) { if (depth == 0) { return(1); } MoveSet validMoves = GetValidMoves(); if (depth == 1) { return(validMoves.Count); } long?nodes = await Task.Run(() => { ParallelOptions po = new ParallelOptions { MaxDegreeOfParallelism = Math.Max(1, maxThreads) }; long n = 0; ParallelLoopResult loopResult = Parallel.ForEach(validMoves, po, async(move, state) => { if (token.IsCancellationRequested) { state.Stop(); return; } GameBoard clone = Clone(); clone.TrustedPlay(move); long?value = await clone.CalculatePerftAsync(depth - 1, token); if (!value.HasValue) { state.Stop(); return; } Interlocked.Add(ref n, value.Value); }); return(loopResult.IsCompleted && !token.IsCancellationRequested ? (long?)n : null); }); return(nodes); }
private MoveSet GetValidSlides(Piece targetPiece, int?maxRange) { MoveSet validMoves = new MoveSet(); Position startingPosition = targetPiece.Position; HashSet <Position> visitedPositions = new HashSet <Position>(); visitedPositions.Add(startingPosition); MovePiece(targetPiece, null, false); GetValidSlides(targetPiece.PieceName, startingPosition, visitedPositions, 0, maxRange, validMoves); MovePiece(targetPiece, startingPosition, false); return(validMoves); }
public void Add(MoveSet moves) { if (null == moves) { throw new ArgumentNullException("moves"); } if (IsLocked) { throw new MoveSetIsLockedException(); } foreach (Move move in moves) { _moves.Add(move); } }
private MoveSet GetValidBeetleMovements(Piece targetPiece) { MoveSet validMoves = new MoveSet(); // Look in all directions for (int direction = 0; direction < EnumUtils.NumDirections; direction++) { Position newPosition = targetPiece.Position.NeighborAt(direction); Piece topNeighbor = GetPieceOnTopInternal(newPosition); // Get positions to left and right or direction we're heading int leftOfTarget = EnumUtils.LeftOf(direction); int rightOfTarget = EnumUtils.RightOf(direction); Position leftNeighborPosition = targetPiece.Position.NeighborAt(leftOfTarget); Position rightNeighborPosition = targetPiece.Position.NeighborAt(rightOfTarget); Piece topLeftNeighbor = GetPieceOnTopInternal(leftNeighborPosition); Piece topRightNeighbor = GetPieceOnTopInternal(rightNeighborPosition); // At least one neighbor is present uint currentHeight = targetPiece.Position.Stack + 1; uint destinationHeight = null != topNeighbor ? topNeighbor.Position.Stack + 1 : 0; uint topLeftNeighborHeight = null != topLeftNeighbor ? topLeftNeighbor.Position.Stack + 1 : 0; uint topRightNeighborHeight = null != topRightNeighbor ? topRightNeighbor.Position.Stack + 1 : 0; // "Take-off" beetle currentHeight--; if (!(currentHeight == 0 && destinationHeight == 0 && topLeftNeighborHeight == 0 && topRightNeighborHeight == 0)) { // Logic from http://boardgamegeek.com/wiki/page/Hive_FAQ#toc9 if (!(destinationHeight < topLeftNeighborHeight && destinationHeight < topRightNeighborHeight && currentHeight < topLeftNeighborHeight && currentHeight < topRightNeighborHeight)) { Position targetPosition = (newPosition.Stack == destinationHeight) ? newPosition : topNeighbor.Position.GetAbove(); Move targetMove = new Move(targetPiece.PieceName, targetPosition); validMoves.Add(targetMove); } } } return(validMoves); }
public MoveSet GetValidMoves() { MoveSet moves = new MoveSet(); if (GameInProgress) { foreach (PieceName pieceName in CurrentTurnPieces) { moves.Add(GetValidMoves(pieceName)); } if (moves.Count == 0) { moves.Add(Move.Pass); } } return(moves); }
public async Task <long?> CalculatePerftAsync(int depth, CancellationToken token) { if (depth == 0) { return(1); } MoveSet validMoves = GetValidMoves(); if (depth == 1) { return(validMoves.Count); } long?nodes = null; foreach (Move move in validMoves) { if (token.IsCancellationRequested) { break; } TrustedPlay(move); long?value = await CalculatePerftAsync(depth - 1, token); UndoLastMove(); if (!value.HasValue) { return(null); } if (!nodes.HasValue) { nodes = 0; } nodes += value; } return(nodes); }
private MoveSet GetValidSpiderMovements(Piece targetPiece) { // Get all slides up to 2 spots away MoveSet upToTwo = GetValidSlides(targetPiece, 2); if (upToTwo.Count > 0) { // Get all slides up to 3 spots away MoveSet upToThree = GetValidSlides(targetPiece, 3); if (upToThree.Count > 0) { // Get all slides ONLY 3 spots away upToThree.Remove(upToTwo); return(upToThree); } } return(MoveSet.EmptySet); }
public static string ToBoardSpaceMoveStringList(Board board, MoveSet moves) { if (null == board) { throw new ArgumentNullException(nameof(board)); } if (null == moves) { throw new ArgumentNullException(nameof(moves)); } StringBuilder sb = new StringBuilder(); foreach (Move move in moves) { sb.AppendFormat("{0}{1}", ToBoardSpaceMoveString(board, move), MoveSet.MoveStringSeparator); } return(sb.ToString().TrimEnd(MoveSet.MoveStringSeparator)); }
public static MoveSet ParseMoveStringList(Board board, string moveStringList) { if (null == board) { throw new ArgumentNullException(nameof(board)); } if (string.IsNullOrWhiteSpace(moveStringList)) { throw new ArgumentNullException(nameof(moveStringList)); } string[] split = moveStringList.Split(new char[] { MoveSet.MoveStringSeparator }, StringSplitOptions.RemoveEmptyEntries); MoveSet moves = new MoveSet(); for (int i = 0; i < split.Length; i++) { Move parseMove = ParseMoveString(board, split[i]); moves.Add(parseMove); } return(moves); }
private MoveSet GetValidLadybugMovements(Piece targetPiece) { MoveSet validMoves = new MoveSet(); Position startingPosition = targetPiece.Position; foreach (Move firstMove in GetValidBeetleMovements(targetPiece)) { if (firstMove.Position.Stack > 0) { MovePiece(targetPiece, firstMove.Position, false); foreach (Move secondMove in GetValidBeetleMovements(targetPiece)) { if (secondMove.Position.Stack > 0) { MovePiece(targetPiece, secondMove.Position, false); foreach (Move thirdMove in GetValidBeetleMovements(targetPiece)) { if (thirdMove.Position.Stack == 0 && thirdMove.Position != startingPosition) { validMoves.Add(thirdMove); } } MovePiece(targetPiece, firstMove.Position, false); } } MovePiece(targetPiece, startingPosition, false); } } return(validMoves); }
private MoveSet GetValidPlacements(Piece targetPiece) { PlayerColor targetColor = CurrentTurnColor; if (targetPiece.Color != targetColor) { return(MoveSet.EmptySet); } if (null == _cachedValidPlacementPositions) { _cachedValidPlacementPositions = new HashSet <Position>(); _visitedPlacements = new HashSet <Position>(); for (int i = 0; i < EnumUtils.NumPieceNames; i++) { Piece piece = _pieces[i]; if (null != piece && piece.InPlay && PieceIsOnTop(piece) && piece.Color == targetColor) { // Piece is in play, on the top and is the right color, look through neighbors Position bottomPosition = GetPieceOnBottom(piece).Position; _visitedPlacements.Add(bottomPosition); for (int j = 0; j < EnumUtils.NumDirections; j++) { Position neighbor = bottomPosition.NeighborAt(j); if (_visitedPlacements.Add(neighbor) && !HasPieceAt(neighbor)) { // Neighboring position is a potential, verify its neighbors are empty or same color bool validPlacement = true; for (int k = 0; k < EnumUtils.NumDirections; k++) { Position surroundingPosition = neighbor.NeighborAt(k); Piece surroundingPiece = GetPieceOnTopInternal(surroundingPosition); if (null != surroundingPiece && surroundingPiece.Color != targetColor) { validPlacement = false; break; } } if (validPlacement) { _cachedValidPlacementPositions.Add(neighbor); } } } } } #if DEBUG ValidMoveCacheMetricsSet["ValidPlacements"].Miss(); #endif } #if DEBUG else { ValidMoveCacheMetricsSet["ValidPlacements"].Hit(); } #endif MoveSet validMoves = new MoveSet(); foreach (Position validPlacement in _cachedValidPlacementPositions) { validMoves.Add(new Move(targetPiece.PieceName, validPlacement)); } return(validMoves); }
private MoveSet GetValidMovesInternal(Piece targetPiece) { if (null != targetPiece && GameInProgress) { if (targetPiece.Color == CurrentTurnColor && PlacingPieceInOrder(targetPiece)) { if (CurrentTurn == 0 && targetPiece.Color == PlayerColor.White && targetPiece.InHand) { // First move must be at the origin and not the White Queen Bee if (targetPiece.PieceName == PieceName.WhiteQueenBee) { return(MoveSet.EmptySet); } return(new MoveSet() { new Move(targetPiece.PieceName, Position.Origin) }); } else if (CurrentTurn == 1 && targetPiece.Color == PlayerColor.Black && targetPiece.InHand) { // Second move must be around the origin and not the Black Queen Bee if (targetPiece.PieceName == PieceName.BlackQueenBee) { return(MoveSet.EmptySet); } MoveSet validMoves = new MoveSet(); for (int i = 0; i < EnumUtils.NumDirections; i++) { Position neighbor = Position.Origin.NeighborAt(i); validMoves.Add(new Move(targetPiece.PieceName, neighbor)); } return(validMoves); } else if (targetPiece.InHand && (CurrentPlayerTurn != 4 || // Normal turn OR (CurrentPlayerTurn == 4 && // Turn 4 and AND (CurrentTurnQueenInPlay || (!CurrentTurnQueenInPlay && targetPiece.BugType == BugType.QueenBee))))) // Queen is in play or you're trying to play it { // Look for valid new placements return(GetValidPlacements(targetPiece)); } else if (targetPiece.PieceName != LastPieceMoved && targetPiece.InPlay && CurrentTurnQueenInPlay && PieceIsOnTop(targetPiece)) { MoveSet validMoves = new MoveSet(); if (CanMoveWithoutBreakingHive(targetPiece)) { // Look for basic valid moves of played pieces who can move switch (targetPiece.BugType) { case BugType.QueenBee: validMoves.Add(GetValidQueenBeeMovements(targetPiece)); break; case BugType.Spider: validMoves.Add(GetValidSpiderMovements(targetPiece)); break; case BugType.Beetle: validMoves.Add(GetValidBeetleMovements(targetPiece)); break; case BugType.Grasshopper: validMoves.Add(GetValidGrasshopperMovements(targetPiece)); break; case BugType.SoldierAnt: validMoves.Add(GetValidSoldierAntMovements(targetPiece)); break; case BugType.Mosquito: validMoves.Add(GetValidMosquitoMovements(targetPiece, false)); break; case BugType.Ladybug: validMoves.Add(GetValidLadybugMovements(targetPiece)); break; case BugType.Pillbug: validMoves.Add(GetValidPillbugBasicMovements(targetPiece)); validMoves.Add(GetValidPillbugSpecialAbilityMovements(targetPiece)); break; } } else { // Check for special ability moves switch (targetPiece.BugType) { case BugType.Mosquito: validMoves.Add(GetValidMosquitoMovements(targetPiece, true)); break; case BugType.Pillbug: validMoves.Add(GetValidPillbugSpecialAbilityMovements(targetPiece)); break; } } return(validMoves); } } } return(MoveSet.EmptySet); }
private MoveSet GetValidMosquitoMovements(Piece targetPiece, bool specialAbilityOnly) { if (targetPiece.Position.Stack > 0 && !specialAbilityOnly) { // Mosquito on top acts like a beetle return(GetValidBeetleMovements(targetPiece)); } MoveSet validMoves = new MoveSet(); bool[] bugTypesEvaluated = new bool[EnumUtils.NumBugTypes]; for (int dir = 0; dir < EnumUtils.NumDirections; dir++) { Position neighbor = targetPiece.Position.NeighborAt(dir); Piece piece = GetPieceOnTopInternal(neighbor); if (null != piece && !bugTypesEvaluated[(int)(piece.BugType)]) { if (specialAbilityOnly) { if (piece.BugType == BugType.Pillbug) { validMoves.Add(GetValidPillbugSpecialAbilityMovements(targetPiece)); } } else { switch (piece.BugType) { case BugType.QueenBee: validMoves.Add(GetValidQueenBeeMovements(targetPiece)); break; case BugType.Spider: validMoves.Add(GetValidSpiderMovements(targetPiece)); break; case BugType.Beetle: validMoves.Add(GetValidBeetleMovements(targetPiece)); break; case BugType.Grasshopper: validMoves.Add(GetValidGrasshopperMovements(targetPiece)); break; case BugType.SoldierAnt: validMoves.Add(GetValidSoldierAntMovements(targetPiece)); break; case BugType.Ladybug: validMoves.Add(GetValidLadybugMovements(targetPiece)); break; case BugType.Pillbug: validMoves.Add(GetValidPillbugBasicMovements(targetPiece)); validMoves.Add(GetValidPillbugSpecialAbilityMovements(targetPiece)); break; } } bugTypesEvaluated[(int)(piece.BugType)] = true; } } return(validMoves); }
private void GetValidSlides(PieceName target, Position currentPosition, HashSet <Position> visitedPositions, int currentRange, int?maxRange, MoveSet validMoves) { if (!maxRange.HasValue || currentRange < maxRange.Value) { for (int slideDirection = 0; slideDirection < EnumUtils.NumDirections; slideDirection++) { Position slidePosition = currentPosition.NeighborAt(slideDirection); if (!visitedPositions.Contains(slidePosition) && !HasPieceAt(slidePosition)) { // Slide position is open int right = EnumUtils.RightOf(slideDirection); int left = EnumUtils.LeftOf(slideDirection); if (HasPieceAt(currentPosition.NeighborAt(right)) != HasPieceAt(currentPosition.NeighborAt(left))) { // Can slide into slide position Move move = new Move(target, slidePosition); if (validMoves.Add(move)) { // Sliding from this position has not been tested yet visitedPositions.Add(move.Position); GetValidSlides(target, slidePosition, visitedPositions, currentRange + 1, maxRange, validMoves); } } } } } }