/// <summary> /// Scans the board bitmap for highlighted marbles and returns their positions. /// </summary> /// <param name="boardBmp">Bitmap of the game board.</param> private List <Point> ScanBoardForHighlightedMarbles(Bitmap boardBmp) { var highlightedPoints = new List <Point>(); // Browse the board for (int boardX = 0; boardX < SigmarCoordinateHelper.BoardSize; boardX++) { for (int boardY = 0; boardY < SigmarCoordinateHelper.BoardSize; boardY++) { if (!SigmarCoordinateHelper.IsValidBoardCoordinate(boardX, boardY)) { // Invalid coordinate. Don't bother. continue; } // Get the rectangle on the image matching the marble to recognize at the current board position var targetRectangle = SigmarCoordinateHelper.GetMarbleRectangle(boardX, boardY); // Get some pixels around the marble and figure out if they are bright enough to be highlights var targetColorBottom = boardBmp.GetPixel(targetRectangle.X + targetRectangle.Width / 2, targetRectangle.Bottom - 2); var targetColorTop = boardBmp.GetPixel(targetRectangle.X + targetRectangle.Width / 2 - 8, targetRectangle.Top); if (targetColorBottom.GetBrightness() > 0.85f || targetColorTop.GetBrightness() > 0.85f) { highlightedPoints.Add(new Point(boardX, boardY)); } } } return(highlightedPoints); }
/// <summary> /// Scans the board bitmap for Vitae marbles (there is no highlight button for Mors and Vitae). /// </summary> /// <param name="boardBmp">Bitmap of the game board.</param> /// <param name="potentialPoints">Points with board coordinates to look for on the board.</param> private List <Point> ScanBoardForVitae(Bitmap boardBmp, IEnumerable <Point> potentialPoints) { var highlightedPoints = new List <Point>(); // Browse the board foreach (var point in potentialPoints) { if (!SigmarCoordinateHelper.IsValidBoardCoordinate(point.X, point.Y)) { // Invalid coordinate. Don't bother. continue; } // Get the rectangle on the image matching the marble to recognize at the current board position var targetRectangle = SigmarCoordinateHelper.GetMarbleRectangle(point.X, point.Y); // Get some pixel in the center of the first pixel row and try to approximate it as the highlight color var arrowPixel = boardBmp.GetPixel(targetRectangle.Left + 26, targetRectangle.Top + 26); var marblePixel = boardBmp.GetPixel(targetRectangle.Left + 26, targetRectangle.Top + 41); if (arrowPixel.GetBrightness() > marblePixel.GetBrightness()) { highlightedPoints.Add(point); } } return(highlightedPoints); }
/// <summary> /// Browses the board and returns marbles that are considered playable: they have at least 3 empty tiles around them, /// and for metals, they are the first remaining in the sequence. /// </summary> /// <param name="board">Board to browse.</param> private IEnumerable <Marble> GetPlayableMarbles(Board board) { var firstMetalTileInSequence = board.GetFirstMetalRemainingInSequence(); for (int x = 0; x < board.Tiles.GetLength(0); x++) { for (int y = 0; y < board.Tiles.GetLength(1); y++) { var tile = board.Tiles[x, y]; if (tile == Tile.Empty) { continue; } if (tile >= Tile.Lead && tile <= Tile.Gold && tile != firstMetalTileInSequence) { // We are on a metal tile that cannot be played yet because there is another metal coming before it in the sequence. continue; } // We are looking for 3 contiguous neighbors that are free int lastFreeContiguousNeighbors = 0; int?firstFreeSequence = null; foreach (var neighbor in GetNeighbors(new Point(x, y))) { // A neighbor is considered free if it's out of the board or if it's an empty tile if (!SigmarCoordinateHelper.IsValidBoardCoordinate(neighbor.X, neighbor.Y) || board.Tiles[neighbor.X, neighbor.Y] == Tile.Empty) { // This neighbor is free. Increment the sequence. lastFreeContiguousNeighbors++; // If we already found 3 contiguous neighbors, we're good. Stop searching. if (lastFreeContiguousNeighbors == 3) { break; } } else { // This neighbor isn't free. // We have to reset the sequence of contiguous free neighbors. // We just keep the first sequence in memory so that it can be added to the last sequence. if (firstFreeSequence == null) { firstFreeSequence = lastFreeContiguousNeighbors; } lastFreeContiguousNeighbors = 0; } } // We have finished browsing the neighbors in a clockwise fashion (so that every last one is contiguous from the previous one). // To determine if the spot at (x,y) is free, we have to check if there are 3 contiguous free neighbors. // We sum the last free contiguous neighbors number with the first free sequence, so that our starting point doesn't impact the result. // I hope that makes sense. if (lastFreeContiguousNeighbors + firstFreeSequence.GetValueOrDefault() >= 3) { // The tile at (x,y) is free. So we return it. yield return(new Marble(x, y, tile)); } } } }