Esempio n. 1
0
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            var parameters = (TetrisInput)e.Parameter;

            generateGrid(TetrisSettings.Width, TetrisSettings.Height);
            this.boardOccupation = new bool[width, height];
            this.boardFills      = new Rectangle[width, height];
            this.game            = new TetrisGame(width, height);

            this.ann     = new ANN(ANNSettings.Weights, ANNSettings.Input, ANNSettings.Hidden);
            this.package = new PlacementPackage()
            {
                RemovedRows = 0
            };

            SolidColorBrush blackBrush = new SolidColorBrush(Colors.Black);

            for (int x = 0; x < this.width; x++)
            {
                for (int y = 0; y < this.height; y++)
                {
                    var block = new Rectangle();
                    block.Fill   = transparentBrush;
                    block.Stroke = blackBrush;
                    Grid.SetColumn(block, x);
                    Grid.SetRow(block, y);
                    board.Children.Add(block);
                    boardFills[x, y] = block;
                }
            }
        }
 public void ApplyPackage(PlacementPackage package)
 {
     this.board  = package.ResultantBoard;
     this.peaks  = package.Peaks;
     this.Score += package.GetScore();
     this.PlacedPieces++;
 }
Esempio n. 3
0
        public Tuple <double, double> Evaluate(bool full = false)
        {
            int evalGames = full ? TetrisSettings.EvalutaionGames : TetrisSettings.TrainEvaluationGames;

            double[] _clearedRows  = new double[evalGames];
            double[] _placedPieces = new double[evalGames];
            for (int i = 0; i < evalGames; i++)
            {
                if (full)
                {
                    this.tetrisGame.ResetGame(TetrisSettings.Width, TetrisSettings.Height);
                }
                else
                {
                    this.tetrisGame.ResetGame(TetrisSettings.TrainWidth, TetrisSettings.TrainHeight);
                }
                PlacementPackage[] packages = tetrisGame.GetPackages();
                while (packages.Length > 0)
                {
                    PlacementPackage bestPackage = packages[0];
                    bestPackage.PackageScore = ann.Evaluate(bestPackage);
                    for (int iPackage = 1; iPackage < packages.Length; iPackage++)
                    {
                        PlacementPackage package = packages[iPackage];
                        package.PackageScore = ann.Evaluate(package);
                        if (package.PackageScore > bestPackage.PackageScore)
                        {
                            bestPackage = package;
                        }
                    }
                    tetrisGame.ApplyPackage(bestPackage);
                    packages = tetrisGame.GetPackages();
                }
                _clearedRows[i]  = tetrisGame.Score;
                _placedPieces[i] = tetrisGame.PlacedPieces;
            }
            double totCleared = 0, totPlaced = 0;

            for (int i = 0; i < evalGames; i++)
            {
                totCleared += _clearedRows[i];
                totPlaced  += _placedPieces[i];
            }
            this.cleared = totCleared / evalGames;
            this.placed  = placed / evalGames;
            return(new Tuple <double, double>(cleared, placed));
        }
Esempio n. 4
0
        public double Evaluate(PlacementPackage placement)
        {
            placement.Normalize();
            double[] intermediateScores = new double[Hidden + 1];
            //for (int iIntermediateScore = 0; iIntermediateScore < intermediateScores.Length - 1; iIntermediateScore++) {
            //	intermediateScores[iIntermediateScore] = 0;
            //}
            intermediateScores[intermediateScores.Length - 1] = 1;
            for (int iInput = 0; iInput <= Input; iInput++)                // the last gotten feature is the input bias
            {
                double feature = placement.GetFeature(iInput);
                int    index   = iInput * Hidden;
                for (int iHidden = 0; iHidden < Hidden; iHidden++)
                {
                    intermediateScores[iHidden] += feature * Weights[index + iHidden];
                }
            }
            for (int inter = 0; inter < intermediateScores.Length - 1; inter++)
            {
                if (intermediateScores[inter] < 0)
                {
                    intermediateScores[inter] = 0;
                }
            }
            double result      = 0;
            int    outputIndex = (this.Input + 1) * this.Hidden;

            for (int inter = 0; inter < intermediateScores.Length; inter++)
            {
                double temp = intermediateScores[inter] * Weights[outputIndex + inter];
                result += temp;
            }
            result = 1 / (1 + Math.Pow(Math.E, -result));
            return(result);

            //double result = 0;
            //for (int i = 0; i < ANNSettings.Input; i++) {
            //	result += placement.GetFeature(i) * Weights[i];
            //}
            //return result;
        }
Esempio n. 5
0
        private void NNPlace(object sender, RoutedEventArgs e)
        {
            PlacementPackage[] packages = game.GetPackages(currentPiece);
            if (packages.Length == 0)
            {
                ClearBoard();
            }
            else
            {
                PlacementPackage bestPackage = packages[0];
                bestPackage.PackageScore = ann.Evaluate(bestPackage);
                for (int iPackage = 1; iPackage < packages.Length; iPackage++)
                {
                    PlacementPackage package = packages[iPackage];
                    package.PackageScore = ann.Evaluate(package);
                    if (package.PackageScore > bestPackage.PackageScore)
                    {
                        bestPackage = package;
                    }
                }

                int[,] toOccupy = bestPackage.OccupiedCells;
                this.package    = bestPackage;

                List <int> occupiedRows = new List <int>();
                for (int i = 0; i < bestPackage.OccupiedCells.GetLength(0); i++)
                {
                    if (!occupiedRows.Contains(toOccupy[i, 1]))
                    {
                        occupiedRows.Add(bestPackage.OccupiedCells[i, 1]);
                    }
                }

                game.ApplyPackage(bestPackage);

                for (int i = 0; i < toOccupy.GetLength(0); i++)
                {
                    if (this.boardOccupation[toOccupy[i, 0], toOccupy[i, 1]])
                    {
                        //Console.WriteLine("thing");
                        throw new Exception("Something about a thing");
                    }
                    this.boardOccupation[toOccupy[i, 0], toOccupy[i, 1]] = true;
                    boardFills[toOccupy[i, 0], toOccupy[i, 1]].Fill      = currentPiece.Brush;
                }

                //Clear the board as necessary, not optimized.
                List <int> rowsToOccupy = new List <int>();
                for (int i = 0; i < toOccupy.GetLength(0); i++)
                {
                    if (!rowsToOccupy.Contains(toOccupy[i, 1]))
                    {
                        rowsToOccupy.Add(toOccupy[i, 1]);
                    }
                }

                /*
                 * The logic is pretty simple, we don't care about efficiency, so start at the bottom row, if it's full, remove it and bring down all the rows above.
                 * Repeat for that row, once done, test the row up, until every row is tested.
                 */
                for (int i = this.height - 1; i >= 0; i--)
                {
                    bool rowFull = true;
                    for (int j = 0; j < this.width; j++)
                    {
                        if (!this.boardOccupation[j, i])
                        {
                            rowFull = false;
                            break;
                        }
                    }
                    if (rowFull)
                    {
                        for (int j = i - 1; j >= 0; j--)                           // Start at the row above to send it down
                        {
                            for (int x = 0; x < width; x++)                        // Move horizontally along the board
                            {
                                boardFills[x, j + 1].Fill = boardFills[x, j].Fill;
                                //Grid.SetColumn(boardFills[x, j + 1], j + 1);

                                this.boardOccupation[x, j + 1] = this.boardOccupation[x, j];                                 // set the board occupation for later verification.
                            }
                        }
                        i++;
                        for (int x = 0; x < width; x++)
                        {
                            boardFills[x, 0].Fill      = transparentBrush;
                            this.boardOccupation[x, 0] = false;
                        }
                    }
                }

                // Verify the two different calculations match
                if (!this.boardOccupation.ToString().Equals(this.game.Board.ToString()))
                {
                    Console.WriteLine(this.boardOccupation.ToString());
                    Console.WriteLine(this.game.Board.ToString());
                    throw new Exception("TetrisGame and Tetris boards do not match");
                }
                display_score.Text = this.game.Score.ToString();
            }
            newPiece();
        }
        public PlacementPackage[] GetPackages(Piece piece = null)
        {
            /* Features:
             * Removed Rows - Number of rows cleared as result of placement
             * Smoothness - Sum of difference in height between adjacent columns
             * Landing Height - The height where the piece is being placed
             * Number of Holes - Number of surrounded cells (other pieces or edge)
             * Number of Wells - Cell is closed at bottom, left, and right; but open on the top
             * Altitude Difference - Highest peak minus lowest peak
             * Pile Height - Row of highest occupied cell
             * Maximum Well Depth - The depth of the deepest well
             * Sum of Well Depths - The sum of all well depths
             * Covered - The number of empty cells below an occupied cell
             * Weighted Block Count - The sum of all occupied cells, weighted by the row in which it occurs
             * Connected Hole Count - Several vertically connected gaps make one connected hole
             * Block Count - The total number of blocks in the grid.
             * Eroded Piece Count - cells from current placement removed, multiplied by removed rows.
             * Row Transitions - The number of transitions between occupied and unoccupied cells in a row, edges are occupied.
             * Column Transitions - Same as row, but for column.
             */

            List <PlacementPackage> packages = new List <PlacementPackage>();

            piece = piece ?? new Piece();
            for (int testX = 0; testX < Width; testX++)
            {
                List <int[, ]> placements = new List <int[, ]>();
                for (int y = this.peaks[testX]; y < Height; y++)
                {
                    if (y >= 0)
                    {
                        if (!board[y][testX])
                        {
                            placements.AddRange(piece.GetPlacements(testX, y));
                        }
                    }
                }

                foreach (int[,] placement in placements)
                {
                    bool       valid = false;
                    List <int> rowsWithPlacements = new List <int>();
                    List <int> cells = new List <int>();
                    for (int iCell = 0; iCell < placement.GetLength(0); iCell++)
                    {
                        int y = placement[iCell, 1], x = placement[iCell, 0];
                        if (x < 0 || x >= Width || y < 0 || y >= Height)
                        {
                            valid = false;
                            break;
                        }
                        if (board[y][x])
                        {
                            valid = false;
                            break;
                        }

                        if (y == Height - 1)
                        {
                            valid = true;
                        }
                        else if (board[y + 1][x])
                        {
                            valid = true;
                        }

                        if (!rowsWithPlacements.Contains(y))
                        {
                            rowsWithPlacements.Add(y);
                            cells.Add(1);
                        }
                        else
                        {
                            cells[rowsWithPlacements.IndexOf(y)]++;
                        }
                    }
                    if (valid)
                    {
                        bool[][] result = CopyArray(this.board);
                        for (int iCell = 0; iCell < placement.GetLength(0); iCell++)
                        {
                            result[placement[iCell, 1]][placement[iCell, 0]] = true;
                        }
                        Tuple <int, int> clearResult = ClearRows(rowsWithPlacements.ToArray(), cells.ToArray(), result);
                        PlacementPackage package     = new PlacementPackage(result)
                        {
                            // Removed Rows
                            RemovedRows = clearResult.Item1,
                            // Eroded Piece Count
                            ErodedPieceCount = clearResult.Item1 * clearResult.Item2,
                            OccupiedCells    = placement
                        };
                        int[] peaks = Enumerable.Repeat(Height - 1, Width).ToArray();
                        int   lowPeak = 0;
                        int   highPeak = TetrisSettings.Height;
                        bool  rPrev = true, cPrev = true;
                        for (int y = 0; y < Height; y++)
                        {
                            for (int x = 0; x < Width; x++)
                            {
                                if (this.board[y][x] != rPrev)
                                {
                                    rPrev = !rPrev;
                                    // Row Transitions
                                    package.RowTransitions++;
                                }
                            }
                            if (this.board[y][Width - 1] == false)
                            {
                                // Row Transitions
                                package.RowTransitions++;
                            }
                        }
                        for (int x = 0; x < Width; x++)
                        {
                            for (int y = 0; y < Height; y++)
                            {
                                if (this.board[y][x] != cPrev)
                                {
                                    // Column Transitions
                                    package.ColumnTransitions++;
                                    cPrev = !cPrev;
                                }
                                if (peaks[x] == Height - 1 && result[y][x])
                                {
                                    peaks[x] = y - 1;
                                    highPeak = peaks[x] < highPeak ? peaks[x] : highPeak;
                                    lowPeak  = peaks[x] > lowPeak ? peaks[x] : lowPeak;
                                    int depth = 0;
                                    for (int i = y - 1; i >= 0; i--)
                                    {
                                        bool[] res = result[i];
                                        int    l = x - 1, r = x + 1;
                                        if ((l < 0 || res[l]) && (r == Width || res[r]))
                                        {
                                            depth++;
                                        }
                                        else
                                        {
                                            break;
                                        }
                                    }
                                    if (depth > 0)
                                    {
                                        // Number of Wells
                                        package.NumberOfWells++;
                                        // Sum of all Well depths
                                        package.TotalWellDepth += depth;

                                        // Max Well Depth
                                        if (depth > package.MaxWellDepth)
                                        {
                                            package.MaxWellDepth = depth;
                                        }
                                    }
                                }
                                if (peaks[x] != Height - 1)
                                {
                                    if (!result[y][x])
                                    {
                                        int    r = x + 1, l = x - 1, u = y - 1, d = y + 1;
                                        bool[] res = result[y];
                                        // Covered
                                        package.Covered++;
                                        if ((r == Width || res[r]) && (l < 0 || res[l]) && (u < 0 || result[u][x]))
                                        {
                                            if (d == Height || result[d][x])
                                            {
                                                // Number of Holes
                                                package.NumberOfHoles++;
                                            }
                                            else
                                            {
                                                // Connected Hole Count
                                                package.ConnectedHoleCount++;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        // Weighted Block Count
                                        package.WeightedBlockCount += y;
                                        // Block Count
                                        package.BlockCount++;
                                    }
                                }
                                else
                                {
                                    lowPeak = Height - 1;
                                }
                            }
                            if (this.board[Height - 1][x] == false)
                            {
                                package.ColumnTransitions++;
                            }
                        }

                        for (int x = 0; x < Width - 1; x++)
                        {
                            // Smoothness
                            package.Smoothness += Math.Abs(peaks[x] - peaks[x + 1]);
                        }

                        // Landing Height
                        package.LandingHeight = Height - LowestPoint(placement);

                        //Altitude Difference
                        package.AltitudeDifference = Math.Abs(highPeak - lowPeak);

                        // Pile Height
                        package.PileHeight = TetrisSettings.Height - highPeak;

                        package.Peaks = peaks;
                        packages.Add(package);
                    }
                }
            }
            return(packages.ToArray());
        }