public void addSinglePieceToClusterCorrectLiberties() { //arrange GoBoard testgame = new GoBoard(5); Coordinate loc = new Coordinate(3, 3); testgame.addPiece(loc, Space.Black); PieceCluster simpleCluster = new PieceCluster(loc, Space.Black, testgame); Coordinate loc2 = new Coordinate(4, 2); testgame.addPiece(loc2, Space.White); Coordinate loc3 = new Coordinate(4, 3); testgame.addPiece(loc3, Space.Black); simpleCluster.piecesAdd(loc3); simpleCluster.removeLiberty(loc3); simpleCluster.addLibertiesOf(loc3); int expected = 5; //act int actual = simpleCluster.Liberties.Count; //assert Assert.AreEqual(expected, actual); }
public void basicClusterHasFourLiberties() { //arrange GoBoard testgame = new GoBoard(5); Coordinate loc = new Coordinate(3, 3); testgame.addPiece(loc, Space.Black); int expected = 4; //act PieceCluster simpleCluster = new PieceCluster(loc, Space.Black, testgame); int actual = simpleCluster.Liberties.Count; //assert Assert.AreEqual(expected, actual); }
public void basicClusterContainsSelf() { //arrange GoBoard testgame = new GoBoard(5); Coordinate loc = new Coordinate(3, 3); testgame.addPiece(loc, Space.Black); bool expected = true; //act PieceCluster simpleCluster = new PieceCluster(loc, Space.Black, testgame); bool actual = simpleCluster.Pieces.Contains(loc); //assert Assert.AreEqual(expected, actual); }
public void enemyNeighborHasLessLiberties() { //arrange GoBoard testgame = new GoBoard(5); Coordinate loc = new Coordinate(3, 3); testgame.addPiece(loc, Space.Black); Coordinate loc2 = new Coordinate(4,3); testgame.addPiece(loc2, Space.White); int expected = 3; //act PieceCluster simpleCluster = new PieceCluster(loc2, Space.White, testgame); int actual = simpleCluster.Liberties.Count; //assert Assert.AreEqual(expected, actual); }
public void libertyUpdatingWithLittleCluster() { //arrange GoBoard testgame = new GoBoard(5); Coordinate loc = new Coordinate(3, 3); testgame.addPiece(loc, Space.Black); PieceCluster black1 = new PieceCluster(loc, Space.Black, testgame); Coordinate loc2 = new Coordinate(4, 2); testgame.addPiece(loc2, Space.White); PieceCluster white1 = new PieceCluster(loc2, Space.White, testgame); Coordinate loc3 = new Coordinate(4, 3); testgame.addPiece(loc3, Space.Black); black1.piecesAdd(loc3); black1.removeLiberty(loc3); black1.addLibertiesOf(loc3); white1.removeLiberty(loc3); int expected = 3; //act int actual = white1.Liberties.Count; //assert Assert.AreEqual(expected, actual); }
public void libertyUpdatingForSimpleClustersWorks() { //arrange GoBoard testgame = new GoBoard(5); Coordinate loc = new Coordinate(3, 3); testgame.addPiece(loc, Space.Black); PieceCluster simpleCluster = new PieceCluster(loc, Space.Black, testgame); Coordinate loc2 = new Coordinate(4, 3); testgame.addPiece(loc2, Space.White); simpleCluster.removeLiberty(loc2); int expected = 3; //act int actual = simpleCluster.Liberties.Count; //assert Assert.AreEqual(expected, actual); }
private void CreateJigsawPuzzle() { #region Some validation if (_sourcePicture == null) { throw new Exception("Please provide source picture."); } if (GameSettings.NUM_ROWS <= 1 || GameSettings.NUM_COLUMNS <= 1) { throw new Exception("GameSettings.NUM_COLUMNS and GameSettings.NUM_ROWS must be at least 2."); } if (GameSettings.NUM_COLUMNS != GameSettings.NUM_ROWS) { throw new Exception("GameSettings.NUM_COLUMNS and GameSettings.NUM_ROWS must be the same."); } #endregion #region Make sure the piece size is not too small int pieceWidth = _sourcePicture.Width / GameSettings.NUM_COLUMNS; int pieceHeight = _sourcePicture.Height / GameSettings.NUM_ROWS; if (pieceWidth < GameSettings.MIN_PIECE_WIDTH || pieceHeight < GameSettings.MIN_PIECE_HEIGHT) { throw new Exception("The picture is too small. Please select a bigger picture."); } int lastColPieceWidth = pieceWidth + (_sourcePicture.Width % GameSettings.NUM_COLUMNS); int lastRowPieceHeight = pieceHeight + (_sourcePicture.Height % GameSettings.NUM_ROWS); #endregion #region Construct jigsaw pieces int lastRow = (GameSettings.NUM_ROWS - 1); int lastCol = (GameSettings.NUM_COLUMNS - 1); _currentCluster = null; _clusters = new List <PieceCluster>(); Matrix matrix = new Matrix(); Pen outlinePen = new Pen(Color.Black, 1) { Width = GameSettings.PIECE_OUTLINE_WIDTH, Alignment = PenAlignment.Inset }; int pieceID = 0; for (int row = 0; row < GameSettings.NUM_ROWS; row++) { // Make the top and bottom curves face in the same way or opposite direction. bool topCurveFlipVertical = (row % 2 == 0); bool bottomCurveFlipVertical = (row % 2 != 0); for (int col = 0; col < GameSettings.NUM_COLUMNS; col++) { // Make the left and right curves face in the same way or opposite direction. bool leftCurveFlipHorizontal = (col % 2 != 0); bool rightCurveFlipHorizontal = (col % 2 == 0); // Toggle the facing of left and right curves with each row. if (row % 2 == 0) { leftCurveFlipHorizontal = (col % 2 == 0); rightCurveFlipHorizontal = (col % 2 != 0); } // Toggle the facing of top and bottom curves with each row. topCurveFlipVertical = !topCurveFlipVertical; bottomCurveFlipVertical = !bottomCurveFlipVertical; GraphicsPath figure = new GraphicsPath(); int offsetX = (col * pieceWidth); int offsetY = (row * pieceHeight); int horizontalCurveLength = (col == lastCol ? lastColPieceWidth : pieceWidth); int verticalCurveLength = (row == lastRow ? lastRowPieceHeight : pieceHeight); #region Top if (row == 0) { int startX = offsetX; int startY = offsetY; int endX = offsetX + horizontalCurveLength; int endY = offsetY; figure.AddLine(startX, startY, endX, endY); } else { BezierCurve topCurve = BezierCurve.CreateHorizontal(horizontalCurveLength); if (topCurveFlipVertical) { topCurve.FlipVertical(); } topCurve.Translate(offsetX, offsetY); figure.AddBeziers(topCurve.Points); } #endregion #region Right if (col == lastCol) { int startX = offsetX + lastColPieceWidth; int startY = offsetY; int endX = offsetX + lastColPieceWidth; int endY = offsetY + verticalCurveLength; figure.AddLine(startX, startY, endX, endY); } else { BezierCurve verticalCurve = BezierCurve.CreateVertical(verticalCurveLength); if (rightCurveFlipHorizontal) { verticalCurve.FlipHorizontal(); } verticalCurve.Translate(offsetX + pieceWidth, offsetY); figure.AddBeziers(verticalCurve.Points); } #endregion #region Bottom if (row == lastRow) { int startX = offsetX; int startY = offsetY + lastRowPieceHeight; int endX = offsetX + horizontalCurveLength; int endY = offsetY + lastRowPieceHeight; figure.AddLine(endX, endY, startX, startY); } else { BezierCurve bottomCurve = BezierCurve.CreateHorizontal(horizontalCurveLength); bottomCurve.FlipHorizontal(); if (bottomCurveFlipVertical) { bottomCurve.FlipVertical(); } bottomCurve.Translate(offsetX + horizontalCurveLength, offsetY + pieceHeight); figure.AddBeziers(bottomCurve.Points); } #endregion #region Left if (col == 0) { int startX = offsetX; int startY = offsetY; int endX = offsetX; int endY = offsetY + verticalCurveLength; figure.AddLine(endX, endY, startX, startY); } else { BezierCurve verticalCurve = BezierCurve.CreateVertical(verticalCurveLength); verticalCurve.FlipVertical(); if (leftCurveFlipHorizontal) { verticalCurve.FlipHorizontal(); } verticalCurve.Translate(offsetX, offsetY + verticalCurveLength); figure.AddBeziers(verticalCurve.Points); } #endregion #region Jigsaw information #region Determine adjacent piece IDs for the current piece List <Coordinate> adjacentCoords = new List <Coordinate> { new Coordinate(col, row - 1), new Coordinate(col + 1, row), new Coordinate(col, row + 1), new Coordinate(col - 1, row) }; List <int> adjacentPieceIDs = DetermineAdjacentPieceIDs(adjacentCoords, GameSettings.NUM_COLUMNS); #endregion #region Construct piece picture Rectangle figureLocation = Rectangle.Truncate(figure.GetBounds()); // Translate the figure to the origin to draw the picture for individual piece matrix.Reset(); matrix.Translate(0 - figureLocation.X, 0 - figureLocation.Y); GraphicsPath translatedFigure = (GraphicsPath)figure.Clone(); translatedFigure.Transform(matrix); Rectangle translatedFigureLocation = Rectangle.Truncate(translatedFigure.GetBounds()); Bitmap piecePicture = new Bitmap(figureLocation.Width, figureLocation.Height); using (Graphics gfx = Graphics.FromImage(piecePicture)) { gfx.FillRectangle(Brushes.White, 0, 0, piecePicture.Width, piecePicture.Height); gfx.ResetClip(); gfx.SetClip(translatedFigure); gfx.DrawImage(_sourcePicture, new Rectangle(0, 0, piecePicture.Width, piecePicture.Height), figureLocation, GraphicsUnit.Pixel); if (GameSettings.DRAW_PIECE_OUTLINE) { gfx.SmoothingMode = SmoothingMode.AntiAlias; gfx.DrawPath(outlinePen, translatedFigure); } } // Wanted to do the "bevel edge" effect but too complicated for me. Bitmap modifiedPiecePicture = (Bitmap)piecePicture.Clone(); ImageUtilities.EdgeDetectHorizontal(modifiedPiecePicture); ImageUtilities.EdgeDetectVertical(modifiedPiecePicture); piecePicture = ImageUtilities.AlphaBlendMatrix(modifiedPiecePicture, piecePicture, 200); #endregion #region Piece and cluster information Piece piece = new Piece { ID = pieceID, ClusterID = pieceID, Width = figureLocation.Width, Height = figureLocation.Height, BoardLocation = translatedFigureLocation, SourcePictureLocation = figureLocation, MovableFigure = (GraphicsPath)translatedFigure.Clone(), StaticFigure = (GraphicsPath)figure.Clone(), Picture = (Bitmap)piecePicture.Clone(), AdjacentPieceIDs = adjacentPieceIDs }; PieceCluster cluster = new PieceCluster { ID = pieceID, Width = figureLocation.Width, Height = figureLocation.Height, BoardLocation = translatedFigureLocation, SourcePictureLocation = figureLocation, MovableFigure = (GraphicsPath)translatedFigure.Clone(), StaticFigure = (GraphicsPath)figure.Clone(), Picture = (Bitmap)piecePicture.Clone(), Pieces = new List <Piece> { piece } }; #endregion _clusters.Add(cluster); #endregion pieceID++; } } #endregion #region Scramble jigsaw pieces Random random = new Random(); int boardWidth = this.ClientSize.Width - grbButtons.Width; int boardHeight = this.ClientSize.Height - menuStrip1.Height; foreach (PieceCluster cluster in _clusters) { int locationX = random.Next(1, boardWidth); int locationY = random.Next((menuStrip1.Height + 1), boardHeight); #region Make sure the piece is within client rectangle bounds if ((locationX + cluster.Width) > boardWidth) { locationX = locationX - ((locationX + cluster.Width) - boardWidth); } if ((locationY + cluster.Height) > boardHeight) { locationY = locationY - ((locationY + cluster.Height) - boardHeight); } #endregion for (int index = 0; index < cluster.Pieces.Count; index++) { Piece piece = cluster.Pieces[index]; piece.BoardLocation = new Rectangle(locationX, locationY, piece.Width, piece.Height); matrix.Reset(); matrix.Translate(locationX, locationY); piece.MovableFigure.Transform(matrix); } // Move the figure for cluster piece cluster.BoardLocation = new Rectangle(locationX, locationY, cluster.Width, cluster.Height); matrix.Reset(); matrix.Translate(locationX, locationY); cluster.MovableFigure.Transform(matrix); } #endregion }
private void frmJigsawPuzzle_MouseUp(object sender, MouseEventArgs e) { if (_canMovePiece) { _previousMouseX = e.X; _previousMouseY = e.Y; #region Draw the "dropped" moving cluster at its final position into back buffer using (Graphics gfx = Graphics.FromImage(_backBuffer)) { gfx.ResetClip(); gfx.SetClip(_currentCluster.MovableFigure); gfx.DrawImageUnscaled(_currentCluster.Picture, _currentCluster.BoardLocation); } #endregion #region Sync the board, the back buffer, and the display using (Graphics gfx = Graphics.FromImage(_board)) { gfx.DrawImageUnscaled(_backBuffer, 0, 0); } using (Graphics gfx = this.CreateGraphics()) { gfx.DrawImageUnscaled(_backBuffer, 0, 0); } #endregion #region Snapping and combining adjacent pieces Matrix matrix = new Matrix(); // Adjacent clusters to be combined with the current cluster List <int> adjacentClusterIDs = new List <int>(); // For each piece in the current cluster, check if there is any adjacent piece to snap for (int i = 0; i < _currentCluster.Pieces.Count; i++) { Piece currentPiece = _currentCluster.Pieces[i]; foreach (int pieceID in currentPiece.AdjacentPieceIDs) { Piece adjacentPiece = GetPieceByID(pieceID); if (adjacentPiece != null && (adjacentPiece.ClusterID != currentPiece.ClusterID)) { #region Make sure the adjacent piece is located at the correct "side" of the current piece Rectangle adjacentPieceMovableFigureBoardLocation = Rectangle.Truncate(adjacentPiece.MovableFigure.GetBounds()); Rectangle currentPieceMovableFigureBoardLocation = Rectangle.Truncate(currentPiece.MovableFigure.GetBounds()); // Math.Sign(.) returns a number indicating the sign of value. // -1 value is less than zero. 0 value is equal to zero. 1 value is greater than zero. // Tolerance value is set to 2 pixels. if (Math.Abs(currentPiece.SourcePictureLocation.X - adjacentPiece.SourcePictureLocation.X) <= 2) { int figureYDifferenceSign = Math.Sign(currentPieceMovableFigureBoardLocation.Y - adjacentPieceMovableFigureBoardLocation.Y); int sourcePictureYDifferenceSign = Math.Sign(currentPiece.SourcePictureLocation.Y - adjacentPiece.SourcePictureLocation.Y); // Adjacent piece is on the wrong side of the current piece. Do not snap to the current piece. // For example, adjacent piece should be located below the current piece instead of being // located above it. if (figureYDifferenceSign != sourcePictureYDifferenceSign) { continue; } } else if (Math.Abs(currentPiece.SourcePictureLocation.Y - adjacentPiece.SourcePictureLocation.Y) <= 2) { int figureXDifferenceSign = Math.Sign(currentPieceMovableFigureBoardLocation.X - adjacentPieceMovableFigureBoardLocation.X); int sourceImageXDifferenceSign = Math.Sign(currentPiece.SourcePictureLocation.X - adjacentPiece.SourcePictureLocation.X); // Adjacent piece is on the wrong side of the current piece. Do not snap to the current piece. // For example, adjacent piece should be located at the right side of the current piece instead // of being located at the left side. if (figureXDifferenceSign != sourceImageXDifferenceSign) { continue; } } #endregion #region Determine if the adjacent piece should be snapped to the current cluster // ================================================= // If the dimensions of the rectangle bounds of the merged path // almost equals the "unioned" rectangles of the two pieces' source image // dimensions, they can be snapped together. // ================================================= GraphicsPath combinedMovableFigure = new GraphicsPath(); combinedMovableFigure.AddPath(adjacentPiece.MovableFigure, false); combinedMovableFigure.AddPath(currentPiece.MovableFigure, false); Rectangle combinedMovableFigureBoardLocation = Rectangle.Truncate(combinedMovableFigure.GetBounds()); // The combined rectangle based on the source picture dimensions of the two pieces Rectangle combinedSourcePictureLocation = Rectangle.Union(adjacentPiece.SourcePictureLocation, currentPiece.SourcePictureLocation); if (Math.Abs(combinedMovableFigureBoardLocation.Width - combinedSourcePictureLocation.Width) <= GameSettings.SNAP_TOLERANCE && Math.Abs(combinedMovableFigureBoardLocation.Height - combinedSourcePictureLocation.Height) <= GameSettings.SNAP_TOLERANCE) { PieceCluster adjacentPieceCluster = GetPieceClusterByID(adjacentPiece.ClusterID); adjacentClusterIDs.Add(adjacentPieceCluster.ID); // Update the ClusterID for the pieces in adjacent cluster foreach (Piece piece in adjacentPieceCluster.Pieces) { piece.ClusterID = currentPiece.ClusterID; } } #endregion } } } if (adjacentClusterIDs.Count > 0) { #region Remove the adjacent cluster from the list after combining with the current cluster foreach (int clusterID in adjacentClusterIDs) { PieceCluster adjacentCluster = GetPieceClusterByID(clusterID); foreach (Piece piece in adjacentCluster.Pieces) { _currentCluster.Pieces.Add(piece); } RemovePieceGroupByID(clusterID); } #endregion GraphicsPath combinedStaticFigure = new GraphicsPath(); Rectangle combinedBoardLocation = _currentCluster.BoardLocation; Rectangle combinedSourcePictureLocation = _currentCluster.SourcePictureLocation; foreach (Piece piece in _currentCluster.Pieces) { combinedStaticFigure.AddPath(piece.StaticFigure, false); combinedBoardLocation = Rectangle.Union(combinedBoardLocation, piece.BoardLocation); combinedSourcePictureLocation = Rectangle.Union(combinedSourcePictureLocation, piece.SourcePictureLocation); } _currentCluster.BoardLocation = new Rectangle(combinedBoardLocation.X, combinedBoardLocation.Y, combinedSourcePictureLocation.Width, combinedSourcePictureLocation.Height); _currentCluster.SourcePictureLocation = combinedSourcePictureLocation; _currentCluster.Width = combinedSourcePictureLocation.Width; _currentCluster.Height = combinedSourcePictureLocation.Height; _currentCluster.StaticFigure = (GraphicsPath)combinedStaticFigure.Clone(); _currentCluster.MovableFigure = (GraphicsPath)combinedStaticFigure.Clone(); Rectangle combinedStaticFigureLocation = Rectangle.Truncate(combinedStaticFigure.GetBounds()); // Translate the movable figure to the origin first and... matrix.Reset(); matrix.Translate(0 - combinedStaticFigureLocation.X, 0 - combinedStaticFigureLocation.Y); _currentCluster.MovableFigure.Transform(matrix); // ...then translate to the new board location matrix.Reset(); matrix.Translate(combinedBoardLocation.X, combinedBoardLocation.Y); _currentCluster.MovableFigure.Transform(matrix); #region Construct cluster picture // Translate the figure to the origin to draw the picture matrix.Reset(); matrix.Translate(0 - combinedStaticFigureLocation.X, 0 - combinedStaticFigureLocation.Y); GraphicsPath translatedCombinedStaticFigure = (GraphicsPath)combinedStaticFigure.Clone(); translatedCombinedStaticFigure.Transform(matrix); Bitmap clusterPicture = new Bitmap(combinedSourcePictureLocation.Width, combinedSourcePictureLocation.Height); using (Graphics gfx = Graphics.FromImage(clusterPicture)) { gfx.FillRectangle(Brushes.White, 0, 0, clusterPicture.Width, clusterPicture.Height); gfx.ResetClip(); gfx.SetClip(translatedCombinedStaticFigure); gfx.DrawImage(_sourcePicture, new Rectangle(0, 0, clusterPicture.Width, clusterPicture.Height), combinedStaticFigureLocation, GraphicsUnit.Pixel); if (GameSettings.DRAW_PIECE_OUTLINE) { Pen outlinePen = new Pen(Color.Black) { Width = GameSettings.PIECE_OUTLINE_WIDTH, Alignment = PenAlignment.Inset }; gfx.SmoothingMode = SmoothingMode.AntiAlias; gfx.DrawPath(outlinePen, translatedCombinedStaticFigure); } } Bitmap modifiedClusterPicture = (Bitmap)clusterPicture.Clone(); ImageUtilities.EdgeDetectHorizontal(modifiedClusterPicture); ImageUtilities.EdgeDetectVertical(modifiedClusterPicture); clusterPicture = ImageUtilities.AlphaBlendMatrix(modifiedClusterPicture, clusterPicture, 200); #endregion _currentCluster.Picture = (Bitmap)clusterPicture.Clone(); // Update the piece's movable figure and board location foreach (Piece piece in _currentCluster.Pieces) { int offsetX = piece.SourcePictureLocation.X - combinedSourcePictureLocation.X; int offsetY = piece.SourcePictureLocation.Y - combinedSourcePictureLocation.Y; int newLocationX = combinedBoardLocation.X + offsetX; int newLocationY = combinedBoardLocation.Y + offsetY; piece.BoardLocation = new Rectangle(newLocationX, newLocationY, piece.Width, piece.Height); Rectangle movableFigureBoardLocation = Rectangle.Truncate(piece.MovableFigure.GetBounds()); // Translate the movable figure to the origin first and... matrix.Reset(); matrix.Translate(0 - movableFigureBoardLocation.X, 0 - movableFigureBoardLocation.Y); piece.MovableFigure.Transform(matrix); // ...then translate to the new board location matrix.Reset(); matrix.Translate(newLocationX, newLocationY); piece.MovableFigure.Transform(matrix); } #region Redraw #region Back buffer Rectangle areaToClear = new Rectangle(combinedBoardLocation.X, combinedBoardLocation.Y, combinedBoardLocation.Width + GameSettings.DROP_SHADOW_DEPTH, combinedBoardLocation.Height + GameSettings.DROP_SHADOW_DEPTH); using (Graphics gfx = Graphics.FromImage(_backBuffer)) { // Clear the area with the background picture first gfx.DrawImage(_background, areaToClear, areaToClear, GraphicsUnit.Pixel); #region Redraw the pieces Region regionToRedraw = new Region(areaToClear); foreach (PieceCluster cluster in _clusters) { Region clusterRegion = new Region(cluster.MovableFigure); clusterRegion.Intersect(regionToRedraw); if (!clusterRegion.IsEmpty(gfx)) { gfx.SetClip(clusterRegion, CombineMode.Replace); gfx.DrawImageUnscaled(cluster.Picture, cluster.BoardLocation); } } #endregion } #endregion #region Board using (Graphics gfx = Graphics.FromImage(_board)) { gfx.DrawImageUnscaled(_backBuffer, 0, 0); } #endregion #region Form using (Graphics gfx = this.CreateGraphics()) { gfx.DrawImageUnscaled(_backBuffer, 0, 0); } #endregion #endregion } #endregion _canMovePiece = false; _currentCluster = null; #region Victory announcement if (_clusters.Count == 1) { if (_victoryAnnounced == false) { _victoryAnnounced = true; MessageBox.Show("¡Has resuelto el rompecabezas!", "¡Felicitaciones!", MessageBoxButtons.OK); Cronometro.Enabled = false; } } #endregion } }
private void frmJigsawPuzzle_MouseDown(object sender, MouseEventArgs e) { #region Determine which cluster is selected (mouse down) int selectedIndex = -1; for (int index = (_clusters.Count - 1); index >= 0; index--) { if (_clusters[index].MovableFigure.IsVisible(e.X, e.Y)) { selectedIndex = index; break; } } #endregion #region Bring up the selected cluster if (selectedIndex >= 0) { _currentCluster = _clusters[selectedIndex]; // Make the current cluster top-most and modify the list to reflect it _clusters.RemoveAt(selectedIndex); _clusters.Add(_currentCluster); #region Back buffer // ======================================================== // Clear the current moving piece's area with the background image and redraw the // pieces whose region intersect with the area. // ======================================================== using (Graphics gfx = Graphics.FromImage(_backBuffer)) { Rectangle currentClusterBoardLocation = _currentCluster.BoardLocation; // Clear the area with the background picture first gfx.DrawImage(_background, currentClusterBoardLocation, currentClusterBoardLocation, GraphicsUnit.Pixel); #region Redraw the pieces Region currentClusterBoardLocationRegion = new Region(_currentCluster.BoardLocation); foreach (PieceCluster cluster in _clusters) { if (cluster != _currentCluster) { Region clusterRegion = new Region(cluster.MovableFigure); clusterRegion.Intersect(currentClusterBoardLocationRegion); if (!clusterRegion.IsEmpty(gfx)) { gfx.SetClip(clusterRegion, CombineMode.Replace); gfx.DrawImageUnscaled(cluster.Picture, cluster.BoardLocation); } } } #endregion } #endregion #region Board Matrix matrix = new Matrix(); SolidBrush shadowBrush = new SolidBrush(GameSettings.DROP_SHADOW_COLOR); using (Graphics gfx = Graphics.FromImage(_board)) { #region Drop shadow // Simple drop shadow only for now. Alpha-blended drop shadow is too slow and jerky. matrix.Reset(); matrix.Translate(GameSettings.DROP_SHADOW_DEPTH, GameSettings.DROP_SHADOW_DEPTH); GraphicsPath shadowFigure = (GraphicsPath)_currentCluster.MovableFigure.Clone(); shadowFigure.Transform(matrix); gfx.ResetClip(); gfx.SetClip(shadowFigure); gfx.FillPath(shadowBrush, shadowFigure); #endregion #region Cluster picture gfx.ResetClip(); gfx.SetClip(_currentCluster.MovableFigure); gfx.DrawImageUnscaled(_currentCluster.Picture, _currentCluster.BoardLocation); #endregion } #endregion #region Form using (Graphics gfx = this.CreateGraphics()) { gfx.DrawImageUnscaled(_board, 0, 0); } #endregion _previousMouseX = e.X; _previousMouseY = e.Y; _canMovePiece = true; } #endregion }