/* Adds a tetromino to the given tetris grid. */ public Grid PlaceTetromino(Grid grid, Tetromino piece, int col) { /* The offset determines how far from the top the piece must be placed. */ int offset = BotHelperFunctions.DistanceToField(grid, piece, col); /* Insert the piece grid into the playing grid. */ grid.InsertGrid(piece, offset, col); return(grid); }
/* Calculates the best move for the current grid and performs that move. */ private void CalculateBestMoveAsync() { /* Copy of the processor grid, used for score calculations. */ Grid currentGrid = Processor.Grid.Clone(); /* The current workable tetromino. */ Tetromino currentPiece = Processor.CurrentPiece.Clone(); /* The look ahead tetromino, used for next level calculations. */ Tetromino lookAheadPiece = Processor.LookAheadPiece.Clone(); /* Remove the current piece from the top of the grid. */ currentGrid.DeleteGrid(currentPiece, Processor.CurrentPieceRow, Processor.CurrentPieceColumn); PerformTetrisMove(CalculateBestMove(currentGrid, currentPiece, lookAheadPiece)); }
/* Calculates the smallest distance from the tetromino to the playing field. */ public static int DistanceToField(Grid grid, Tetromino piece, int col) { /* Get the first distance from piece to field. */ int minDistance = grid.DistanceToFirstBlock(piece.LowestBlockRow(0), col); /* Compare remaining distances. */ for (int i = 1; i < piece.Width; i++) { /* Get distance. */ int distance = grid.DistanceToFirstBlock(piece.LowestBlockRow(i), col + i); /* Select smallest distance.*/ if (minDistance > distance) { minDistance = distance; } } return(minDistance); }
/* Fills the queue with 7 new pieces. */ private void GeneratePieces() { Random r = new Random(); /* Get a list of all pieces. */ List <Tetromino> Pieces = new List <Tetromino>(Tetromino.All()); /* The first item in the queue has to be an I, J, L or T piece. * These are the first four in the array, thus we can generate a random * number up to four to get one of those pieces. */ int i = r.Next(4); PieceQueue.Enqueue(Pieces[i]); Pieces.RemoveAt(i); /* Generate the remaining pieces. */ while (Pieces.Count > 0) { i = r.Next(Pieces.Count); PieceQueue.Enqueue(Pieces[i]); Pieces.RemoveAt(i); } }
/* Determines whether a tetromino is an I piece. */ private bool IsIPiece(Tetromino piece) { /* Only tetrominoes with width 4 can be I pieces. */ return(piece.Width == 4); }
/* Calculates the move with the highest grid score, * taking the current and look ahead pieces into consideration. */ private TetrisMove CalculateBestMove(Grid grid, Tetromino piece, Tetromino lookAheadPiece) { /* Create a variable to hold the best move. */ TetrisMove bestMove = new TetrisMove(); /* Grids used for calculations. */ Grid tempGrid = null; Grid lookAheadGrid = null; /* Reset the bot move in the tetris processor. */ Processor.BotPiece = null; Processor.BotLookAheadPiece = null; Processor.BotMove = true; bool prioritizeTetrisses = false; int rightBoundaryOffset = 1; /* Highest point in the current field. */ int fieldHeight = 0; if (PrioritizeTetrisses) { int tetrisReady = BotHelperFunctions.TetrisReady(grid); if (tetrisReady == 0 && IsIPiece(piece)) { /* Rotate the I piece upright. */ piece.Rotate90Deg(); /* Move it over to the right of the grid to make a tetris. */ return(new TetrisMove(grid.Width - piece.LeftMostBlockColumn() - 1, 1)); } fieldHeight = BotHelperFunctions.FieldHeight(grid); if (fieldHeight < ForceNormalPlayFieldHeight && tetrisReady != 2) { /* If it is still safe to do so, play without the last column. */ rightBoundaryOffset = 2; prioritizeTetrisses = true; } } /* Calculate best permutation*/ for (int rotation = 0; rotation < piece.UniqueRotations; rotation++) { /* Calculate boundaries. */ int leftMostColumn = piece.LeftMostBlockColumn(); int rightMostColumn = grid.Width - piece.RightMostBlockColumn() - rightBoundaryOffset; for (int column = -leftMostColumn; column <= rightMostColumn; column++) { /* Calculate best permutation for look ahead piece. */ for (int lookAheadRotation = 0; lookAheadRotation < lookAheadPiece.UniqueRotations; lookAheadRotation++) { /* Calculate look ahead boundaries. */ int lookAheadLeftMostColumn = lookAheadPiece.LeftMostBlockColumn(); int lookAheadRightMostColumn = grid.Width - lookAheadPiece.RightMostBlockColumn() - rightBoundaryOffset; for (int lookAheadColumn = -lookAheadLeftMostColumn; lookAheadColumn <= lookAheadRightMostColumn; lookAheadColumn++) { /* Create a grid with current pieces. */ tempGrid = PlaceTetromino(grid.Clone(), piece, column); lookAheadGrid = PlaceTetromino(tempGrid.Clone(), lookAheadPiece, lookAheadColumn); double score = CalculateGridScore(lookAheadGrid, prioritizeTetrisses); if (score > bestMove.Score) { /* Update best move. */ bestMove.Column = column; bestMove.Rotation = rotation; bestMove.Score = score; /* Update bot move in tetris processor. */ Processor.BotPiece = piece; Processor.BotMoveRow = BotHelperFunctions.DistanceToField(grid, piece, column); Processor.BotMoveColumn = column; Processor.BotLookAheadPiece = lookAheadPiece; Processor.BotLookAheadMoveRow = BotHelperFunctions.DistanceToField(tempGrid, lookAheadPiece, lookAheadColumn); Processor.BotLookAheadMoveColumn = lookAheadColumn; /* Update view. */ Processor.RaiseUpdateEvent(); Thread.Sleep(BestMoveDelay); } } /* Rotate look ahead piece for the next permutation. */ lookAheadPiece.Rotate90Deg(); } } /* Rotate piece for the next permutation. */ piece.Rotate90Deg(); } /* Remove the preview of the bots move. */ Processor.BotMove = false; return(bestMove); }