Code Monkey home page Code Monkey logo

tetris-ai's Introduction

How to play

  1. Click here
  2. Clone this repo and open the Tetris.html file in your web browser.

This will start the algorithm at generation zero. To see its evolved form at generation 25, press SHIFT once it opens

25th Generation AI

AI running after 25 generations of evolution

How it works

This AI uses genetic programming / evolutionary techniques to improve over time. Through selection, crossover, and mutation, the AI will learn to get the highest score in as few moves as possible (we'll aim for 500 moves).

Genetic algorithms work by creating a population of "genomes" that have multiple "genes", representing parameters for the algorithm. Each of these individuals in the population is evaluated and a "fitness" score for each genome is produced. The fittest individuals would reproduce and pass favourable genes down to the next generation. Mutation also occurs where genes are randomly modified in hopes of creating more beneficial features.

Analysis

Rules: Each time a block moves down, the score is incremented by one. When a row is cleared, the score is increased by 400, 1000, 3000, or 12000, depending on how many rows are cleared at once.

The step-by-step algorithm is as follows:

  1. Initialize 50 genomes with random values. This is generation 0. A genome is a "moveset" or a Tetris game the AI plays until it loses / reaches 500 moves without losing. An example genome looks like this:
{
"id": 0.3633325448484497
"rowsCleared": -0.4579172890221702
"weightedHeight": -0.1247033950880867
"cumulativeHeight": -0.05487475723349933
"relativeHeight": 0.19087878312923057
"holes": 0.1516741306703968
"roughness": -0.11759213555846282
}

All the parameters in a genome refer to a weight value:

id: The unique identifier for the genome
rowsCleared: The number of rows cleared by the given move
weightedHeight: The absolute height of the highest column
cumulativeHeight: The sum of all the columns' heights
relativeHeight: The highest column minus the lowest column
holes: All the empty cells with a block above them
roughness: The sum of height differences between adjacent columns

  1. Depending on the genome values, the AI will exhaustively try every possible move given an upcoming shape to optimize for the highest rating, where a rating follows this linear combination:
move.getRowsCleared() * genome.rowsCleared +
move.getWeightedHeight() * genome.weightedHeight +
move.getCumulativeHeight() * genome.cumulativeHeight +
move.getRelativeHeight() * genome.relativeHeight +
move.getHoles() * genome.holes +
move.getRoughness() * genome.roughness

As you can see, a genome with small values for heights, holes, and roughness, and large values for rowsCleared will achieve the highest score.

  1. A genome's "fitness" is the game score reached before losing the game (hitting the ceiling). After the initial 50 genomes' fitness scores are evaluated, we sort the list of genomes by their fitness value in descending order.

  2. Remove the 2nd half of the genomes from the list - we'll only allow the top 50% of the individuals in the genome population to breed/pass on their genes.

  3. Create a new array of genomes called children. Put the fittest individual in the array - we sorted genomes previously by fitness, so this will just be genomes[0].

  4. Time to breed! We need to fill the children array with 50 individuals (we already have one - the fittest individual from generation 0). We randomly select two parent genomes, make a child, and push it into the children array. We create a child by randomly selecting one of the two gene values from the parents for each of the 6 parameters.

  5. Next, we randomly mutate the child's gene(s) to try and benefit from it. We set small values for the mutationStep and mutationRate hyperparamaters (0.2 and 0.05 respectively), so we only mutate occasionally. We repeat this for all the children we created using the breeding/crossover step in 6.

if (Math.random() < mutationRate) {
	child.rowsCleared = child.rowsCleared + Math.random() * mutationStep * 2 - mutationStep;
}
  1. We now have a new genome population called generation 1, with improved genes from generation 0. We repeat steps 2-7 indefinitely.

If you've tried running the AI already, you'll notice the first few individuals don't score too well. However, if you try loading the evolved population at generation 25 (by pressing SHIFT) you'll see how much better it scores.

It would make intuitive sense that in order to maximize score, we would want to maximize the number of rows cleared and minimize all the other parameters (heights, holes, roughness) when calculating move ratings. This seemed to be true in the first few generations, however, once the number of moves started approaching the limit (500) in a generation, the relativeHeight parameter started to increase. We would start seeing the AI stacking blocks up to clear multiple rows at once, getting bonuses of up to 10x as compared to clearing each line individually, which is a strategy used by high level players used to maximize score.

Multiple Clears

References

Coding a Tetris AI using a Genetic Algorithm

Tetris AI – The (Near) Perfect Bot

Evolutionary AI for Tetris

Playing Tetris with Genetic Algorithms

Credits go to Siraj Raval for his educational AI videos on YouTube.

tetris-ai's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

tetris-ai's Issues

License ?

Hello, under what license is this project released under ? I would like to study it to learn from it. Thank you.

Fix attribution

Unfortunately, Siraj Raval used my code for TetNet without permission or license when making his YouTube video and didn’t provide proper attribution at the time. I only realized this now four years later and am working on restoring the attribution wherever possible. The original source is here: https://github.com/IdreesInc/TetNet and my full write up is here: https://idreesinc.com/about-tetnet.html

I’d appreciate it if you linked back to the original source if possible as I am still trying to undo the damage that the video caused. Or even better, please fork the original repository instead (though I understand that would undo the current stars/forks).

For what it’s worth, I’m glad you enjoyed working with TetNet!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.