private long CalculatePlacementCount(BoardState board, PieceBitmap justPlacedBitmap, int justPlacedX, int justPlacedY, List <PieceDefinition> plannedFuturePieces, int depth) { long placementCount = PowCache[depth]; //We are as deep as we are allowed to go, or we are out of pieces to place if (_depth == depth || plannedFuturePieces.Count == depth) { return(placementCount); } board.Place(justPlacedBitmap, justPlacedX, justPlacedY); //Now calculate how many placements the next piece can have var nextPiece = plannedFuturePieces[depth]; for (var index = 0; index < nextPiece.PossibleOrientations.Length; index++) { var bitmap = nextPiece.PossibleOrientations[index]; for (int x = 0; x < BoardState.Width - bitmap.Width + 1; x++) { for (int y = 0; y < BoardState.Height - bitmap.Height + 1; y++) { if (board.CanPlace(bitmap, x, y)) { placementCount += CalculatePlacementCount(board, bitmap, x, y, plannedFuturePieces, depth + 1); } } } } return(placementCount); }
public override void Reset() { base.Reset(); PieceToPurchase = null; PlaceBitmap = null; PlaceX = -1; PlaceY = -1; }
public Preplacement Preplace(BoardState board, List <PieceDefinition> plannedFuturePieces) { PieceBitmap resultBitmap = null; int resultX = -1; int resultY = -1; //How many placements the next future piece has for our best found placement (more is better) long bestPlacementCount = -1; //Tie break when there is a draw, based on distance to 0,0 (less is better) int bestTieBreaker = -1; foreach (var bitmap in plannedFuturePieces[0].PossibleOrientations) { for (int x = 0; x < BoardState.Width - bitmap.Width + 1; x++) { for (int y = 0; y < BoardState.Height - bitmap.Height + 1; y++) { if (board.CanPlace(bitmap, x, y)) { long placementCount = CalculatePlacementCount(board, bitmap, x, y, plannedFuturePieces, 1); var tieBreaker = x + y; if (placementCount > bestPlacementCount || (placementCount == bestPlacementCount && tieBreaker < bestTieBreaker)) { bestPlacementCount = placementCount; bestTieBreaker = tieBreaker; resultBitmap = bitmap; resultX = x; resultY = y; } } } } } if (resultBitmap == null) { throw new Exception("Cannot place the first piece"); } return(new Preplacement(resultBitmap, resultX, resultY)); }
private void TryPlacement(BoardState board, PieceBitmap bitmap, int x, int y, ref PieceBitmap resultBitmap, ref int resultX, ref int resultY, ref int bestLeastHoles, ref int bestLargestHole, ref int bestDistance, List <int> holes) { board.Place(bitmap, x, y); holes.Clear(); PlacementHelper.HoleCount(board, ref holes); //TODO: Remove LINQ var distance = x + y; //TODO: Try direct if (holes.Count < bestLeastHoles || (holes.Count == bestLeastHoles && holes.Max() > bestLargestHole) || (holes.Count == bestLeastHoles && holes.Max() == bestLargestHole && distance < bestDistance)) { bestLeastHoles = holes.Count; bestLargestHole = holes.Max(); bestDistance = distance; resultBitmap = bitmap; resultX = x; resultY = y; } }
private static void CalculateScore(BoardState board, PieceBitmap bitmap, int placeX, int placeY, bool doubler, out int score) { board.Place(bitmap, placeX, placeY); score = CalculateScore(board, doubler, 0, BoardState.Width, 0, BoardState.Height); }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { resultBitmap = null; resultX = -1; resultY = -1; //TODO: We could do better with a good tiebreaker int bestScore = int.MaxValue; int tieBreakerScore = int.MaxValue; int tiedForBest = 0; foreach (var bitmap in piece.PossibleOrientations) { for (int x = 0; x < BoardState.Width - bitmap.Width + 1; x++) { for (int y = 0; y < BoardState.Height - bitmap.Height + 1; y++) { if (board.CanPlace(bitmap, x, y)) { CalculateScore(board, bitmap, x, y, _doubler, out var score); if (score < bestScore) { bestScore = score; tieBreakerScore = x + y; resultBitmap = bitmap; resultX = x; resultY = y; tiedForBest = 0; } else if (score == bestScore) { tiedForBest++; int ourTieBreaker = x + y; if (ourTieBreaker < tieBreakerScore) { //Console.WriteLine("Beat the tie"); tieBreakerScore = ourTieBreaker; resultBitmap = bitmap; resultX = x; resultY = y; } } } } } } //if (tiedForBest > 0) // Console.WriteLine($"{_doubler} {tiedForBest}"); return(resultBitmap != null); }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { int smallestSize = BoardState.Height * BoardState.Width + 1; resultBitmap = null; resultX = 0; resultY = 0; //TODO: If we weren't a singleton we could track our used Width/Height int currentHeight = CalcUsedHeight(ref board); int currentWidth = CalcUsedWidth(ref board); //Console.WriteLine($"Current {currentWidth}x{currentHeight}"); for (var x = 0; x < BoardState.Width; x++) { for (var y = 0; y < BoardState.Height; y++) { foreach (var bitmap in piece.PossibleOrientations) { var size = Math.Max(currentWidth, x + bitmap.Width) * Math.Max(currentHeight, y + bitmap.Height); if (size < smallestSize && x + bitmap.Width <= BoardState.Width && y + bitmap.Height <= BoardState.Height && board.CanPlace(bitmap, x, y)) { smallestSize = size; resultBitmap = bitmap; resultX = x; resultY = y; } } } } return(resultBitmap != null); }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { foreach (var bitmap in piece.PossibleOrientations) { for (var y = 0; y <= BoardState.Height - bitmap.Height; y++) { for (var x = 0; x <= BoardState.Width - bitmap.Width; x++) { if (board.CanPlace(bitmap, x, y)) { resultBitmap = bitmap; resultX = x; resultY = y; return(true); } } } } resultBitmap = null; resultX = -1; resultY = -1; return(false); }
public void PlayerPlacedPiece(int player, PieceDefinition piece, int x, int y, PieceBitmap bitmap) { Console.WriteLine($"Player {player} placed {piece.Name} at {x},{y}"); if (PrintBoardsAfterPlacement) { PrintBoards(true); } }
public Preplacement(PieceBitmap bitmap, int x, int y) { Bitmap = bitmap; X = x; Y = y; }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { var holes = new List <int>(); int leastHoles = BoardState.Width * BoardState.Height; int largestHoleSize = 0; resultBitmap = null; resultX = -1; resultY = -1; //TODO: Distance could be < the piece size too for (var distance = 0; distance < BoardState.Width + BoardState.Height; distance++) { //TODO: Min(distance, Width - bitmap.MinSideSize) ? for (var x = 0; x <= distance; x++) { var y = distance - x; foreach (var bitmap in piece.PossibleOrientations) { if (x + bitmap.Width <= BoardState.Width && y + bitmap.Height <= BoardState.Height && board.CanPlace(bitmap, x, y)) { var clone = board; clone.Place(bitmap, x, y); holes.Clear(); PlacementHelper.HoleCount(clone, ref holes); //TODO: No Linq if (holes.Count < leastHoles || (holes.Count == leastHoles && holes.Max() > largestHoleSize)) { leastHoles = holes.Count; largestHoleSize = holes.Max(); resultBitmap = bitmap; resultX = x; resultY = y; } } } } if (resultBitmap != null) { return(true); } } return(false); }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { resultBitmap = null; resultX = -1; resultY = -1; int bestLeastHoles = BoardState.Width * BoardState.Height + 1; int bestLargestHole = BoardState.Width * BoardState.Height + 1; int bestDistance = BoardState.Width * BoardState.Height + 1; var holes = new List <int>(); foreach (var bitmap in piece.PossibleOrientations) { //TODO: Try at 0, 0 if (board.CanPlace(bitmap, 0, 0)) { TryPlacement(board, bitmap, 0, 0, ref resultBitmap, ref resultX, ref resultY, ref bestLeastHoles, ref bestLargestHole, ref bestDistance, holes); } for (var x = 0; x <= BoardState.Width - bitmap.Width; x++) { //You can only place in a position if you couldn't place in the previous position, or if you can't place in the next position bool couldPlaceBefore = true; for (var y = 0; y <= BoardState.Height - bitmap.Height; y++) { var canPlaceNow = board.CanPlace(bitmap, x, y); if (!couldPlaceBefore && canPlaceNow) { //Try here TryPlacement(board, bitmap, x, y, ref resultBitmap, ref resultX, ref resultY, ref bestLeastHoles, ref bestLargestHole, ref bestDistance, holes); } if (couldPlaceBefore && !canPlaceNow && y > 0) { //try at previous place // TODO May have already been tried (optimization, record the last tried place?) TryPlacement(board, bitmap, x, y - 1, ref resultBitmap, ref resultX, ref resultY, ref bestLeastHoles, ref bestLargestHole, ref bestDistance, holes); } couldPlaceBefore = canPlaceNow; } } //Do a y then x loop as well for (var y = 0; y <= BoardState.Height - bitmap.Height; y++) { //You can only place in a position if you couldn't place in the previous position, or if you can't place in the next position bool couldPlaceBefore = true; for (var x = 0; x <= BoardState.Width - bitmap.Width; x++) { var canPlaceNow = board.CanPlace(bitmap, x, y); if (!couldPlaceBefore && canPlaceNow) { //Try here //TODO May have already tried this in the x,y loop above TryPlacement(board, bitmap, x, y, ref resultBitmap, ref resultX, ref resultY, ref bestLeastHoles, ref bestLargestHole, ref bestDistance, holes); } if (couldPlaceBefore && !canPlaceNow && x > 0) { //try at previous place // TODO May have already been tried (optimization, record the last tried place?) //TODO May have already tried this in the x,y loop above TryPlacement(board, bitmap, x - 1, y, ref resultBitmap, ref resultX, ref resultY, ref bestLeastHoles, ref bestLargestHole, ref bestDistance, holes); } couldPlaceBefore = canPlaceNow; } } } return(resultBitmap != null); }
public void PlayerPlacedPiece(int player, PieceDefinition piece, int x, int y, PieceBitmap bitmap) { }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int resultX, out int resultY) { _evaluator.BeginEvaluation(board); resultBitmap = null; resultX = -1; resultY = -1; int bestScore = int.MinValue; //Exhaustively place it and make new child nodes for (var index = 0; index < piece.PossibleOrientations.Length; index++) { var bitmap = piece.PossibleOrientations[index]; var searchWidth = BoardState.Width - bitmap.Width + 1; var searchHeight = BoardState.Height - bitmap.Height + 1; //TODO? If this is the first piece, remove mirrors/rotations from the children //if (isFirstPiece) //{ // //TODO: This doesn't stop diagonal mirrors // searchWidth = (BoardState.Width - bitmap.Width) / 2 + 1; // searchHeight = (BoardState.Height - bitmap.Height) / 2 + 1; //} for (int x = 0; x < searchWidth; x++) { for (int y = 0; y < searchHeight; y++) { if (board.CanPlace(bitmap, x, y)) { var clone = board; clone.Place(bitmap, x, y); var score = _evaluator.Evaluate(in clone, x, x + bitmap.Width, y, y + bitmap.Height); if (score > bestScore) { resultBitmap = bitmap; resultX = x; resultY = y; bestScore = score; } } } } } return(resultBitmap != null); }
/// <summary> /// Finds a placement (Not guaranteed to be any good) for the given piece on the given board /// </summary> public static void GetFirstPlacement(BoardState board, PieceDefinition piece, out PieceBitmap bitmap, out int x, out int y) { for (var index = 0; index < piece.PossibleOrientations.Length; index++) { bitmap = piece.PossibleOrientations[index]; for (y = BoardState.Height - bitmap.Height; y >= 0; y--) { for (x = BoardState.Width - bitmap.Width; x >= 0; x--) { if (board.CanPlace(bitmap, x, y)) { return; } } } } throw new Exception("GetFirstPlacement couldn't find a placement"); }
protected override bool TryPlacePiece(BoardState board, PieceDefinition piece, out PieceBitmap resultBitmap, out int x, out int y) { for (var oppositeWallGap = 0; oppositeWallGap < BoardState.Width; oppositeWallGap++) { //TODO: Could use the minimum of the size of the sides of the bitmap in this gap < part to skip some wasteful loops for (var gap = 0; gap < BoardState.Height; gap++) { foreach (var bitmap in piece.PossibleOrientations) { //Try place in x direction if (gap + bitmap.Width <= BoardState.Width && oppositeWallGap + bitmap.Height <= BoardState.Height && board.CanPlace(bitmap, gap, oppositeWallGap)) { resultBitmap = bitmap; x = gap; y = oppositeWallGap; return(true); } //Try place in y direction if (oppositeWallGap + bitmap.Width <= BoardState.Width && gap + bitmap.Height <= BoardState.Height && board.CanPlace(bitmap, oppositeWallGap, gap)) { resultBitmap = bitmap; x = oppositeWallGap; y = gap; return(true); } } } } resultBitmap = null; x = -1; y = -1; return(false); }