/* 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 score for the current grid after clearing full rows. */ private double CalculateGridScore(Grid grid, bool prioritizeTetrisses, int fieldHeight = 0) { /* Do calculations after clearing full rows in the grid. * This gives row clearing moves a better score. */ grid.ClearFullRows(); if (prioritizeTetrisses) { return(BotHelperFunctions.AggregateHeightScore(grid, AggregateHeightPenalty) + BotHelperFunctions.HeightDifferenceScore(grid, HeightDifferencePenalty) + BotHelperFunctions.HoleScore(grid, HolePenalty, HoleWeightPenalty) + BotHelperFunctions.UnevennessScore(grid, UnevennessPenalty) + BotHelperFunctions.WellScore(grid, WellPenalty)); } else { return(BotHelperFunctions.AggregateHeightScore(grid, AggregateHeightPenalty) + BotHelperFunctions.HoleScore(grid, HolePenalty, HoleWeightPenalty) + BotHelperFunctions.UnevennessScore(grid, UnevennessPenalty)); } }
/* Moves a tetromino from the default position to the desired position. */ private void PerformTetrisMove(TetrisMove move) { /* Rotate the tetromino. */ switch (move.Rotation) { case 1: Processor.RotatePreviewPiece(1); break; case 2: Processor.RotatePreviewPiece(1); goto case 1; case 3: Processor.RotatePreviewPiece(-1); break; } /* Calculate how for the tetromino must be moved. */ int relativeDistance = move.Column - Processor.CurrentPieceColumn; if (relativeDistance != 0) { /* Calculate movment direction. */ int direction = relativeDistance / BotHelperFunctions.AbsoluteValue(relativeDistance); while (relativeDistance != 0) { /* Move the piece across the grid. */ Processor.MovePreviewPiece(direction); /* Decrease movement amount. */ relativeDistance -= direction; Thread.Sleep(GridMoveDelay); } } Processor.PlacePreviewPiece(); }
/* 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); }