Advertisement
Guest User

[Java] Tetris Randomizer

a guest
Aug 17th, 2017
294
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 11.51 KB | None | 0 0
  1. import java.util.Random;
  2.  
  3. public class Randomizer
  4. {
  5.  
  6.     public static final int RAND_DORY = 0, // memoryless randomizer
  7.             RAND_OLAF = 1, // dementia randomizer, reduces chances of floods and droughts
  8.             RAND_RECURSIVE = 2, // recursive update of probabilities
  9.             RAND_BAG14 = 3, // 14-bag randomizer AKA double-bag randomizer
  10.             RAND_BAG = 4, // 7-bag randomizer
  11.             RAND_LENGTH = 5;
  12.  
  13.     public int numpieces; // how many pieces exist, should be 7 for Tetris pieces
  14.  
  15.     public Random r; // random number generator
  16.     public int type; // randomizer-type ,e.g. memoryless, bag randomizer
  17.     int[] bag; // pieces that will be handed out in near future
  18.     int left; // how many pieces are currently left in the bag
  19.     int[] history; // pieces you got in recent past; history[0] is most recent piece
  20.     int[] drought; // how long you didn't get a certain piece kind
  21.     double[] chance; // weights resp. probabilities for recursively updated randomizer
  22.  
  23.     public Randomizer()
  24.     {
  25.         type = RAND_BAG;
  26.         reset();
  27.     }
  28.  
  29.     public Randomizer( long seed )
  30.     {
  31.         type = RAND_BAG;
  32.         reset( seed );
  33.     }
  34.  
  35.     public void reset()
  36.     {
  37.         r = new Random();
  38.         initme();
  39.     }
  40.  
  41.     public void reset( long seed )
  42.     {
  43.         r = new Random( seed );
  44.         initme();
  45.     }
  46.  
  47.     public void initme()
  48.     {
  49.         numpieces = 7;
  50.         // needed for 7-bag and 14-bag randomizer
  51.         bag = new int[14];
  52.         for ( int j = 0; j < bag.length; j++ )
  53.             bag[j] = -1;
  54.         left = 0;
  55.         // needed for dementia/olaf randomizer
  56.         history = new int[4];
  57.         for ( int j = 0; j < history.length; j++ )
  58.             history[j] = r.nextInt( numpieces );
  59.         drought = new int[numpieces];
  60.         for ( int i = 0; i < numpieces; i++ )
  61.             drought[i] = history.length;
  62.         for ( int j = history.length - 1; j >= 0; j-- )
  63.             drought[history[j]] = j;
  64.         // needed for recursively updated randomizer
  65.         chance = new double[numpieces];
  66.         for ( int i = 0; i < numpieces; i++ )
  67.             chance[i] = 1f / numpieces;
  68.     }
  69.  
  70.     // hands out the next piece, returns a number between 0 and numpieces-1
  71.     public int next()
  72.     {
  73.         int piece = -1;
  74.         if ( type == RAND_DORY )
  75.             piece = r.nextInt( numpieces );
  76.         else if ( type == RAND_OLAF )
  77.             piece = nextolaf();
  78.         else if ( type == RAND_RECURSIVE )
  79.             piece = nextrecursive();
  80.         else if ( type == RAND_BAG )
  81.             piece = nextbag();
  82.         else if ( type == RAND_BAG14 )
  83.             piece = nextbag14();
  84.         else
  85.             System.out.println( "unknown Randomizer" );
  86.  
  87.         return piece;
  88.     }
  89.  
  90.     // pretty close to memoyless randomizer, uses weights to reduce chances of droughts and floods
  91.     public int nextolaf()
  92.     {
  93.         // uses global arrays history[] and drought[]
  94.         // history tells which piece kinds you got most recently, history[0] is the most recent piece
  95.         // drought tells you when you got each piece kind for the last time,
  96.         // drought[0] is how long you have to wait for the piece shape with the ID 0
  97.        
  98.         // flood reduction constants
  99.         final int base = 160; // the weight for each piece kind before floods and droughts are considered
  100.         final int[] reduction = { 70, 30, 14, 6 }; // subtracted from base for the 4 most recent pieces
  101.         // drought reduction constants
  102.         final int threshold = 7; // increase probability of a shape if drought is at least this long
  103.         final float factor = 1.4f;
  104.         final float potence = 1.5f;
  105.  
  106.         int[] weight = new int[numpieces];
  107.         for ( int i = 0; i < numpieces; i++ )
  108.             weight[i] = base;
  109.  
  110.         // flood reduction
  111.         for ( int j = 0; j < reduction.length; j++ )
  112.             weight[history[j]] -= reduction[j];
  113.  
  114.         // drought reduction
  115.         for ( int i = 0; i < numpieces; i++ )
  116.             if ( drought[i] > threshold )
  117.                 weight[i] += (int) ( factor * Math.pow( drought[i] - threshold, potence ) );
  118.  
  119.         // dealing a piece shape
  120.         int total = 0;
  121.         for ( int i = 0; i < numpieces; i++ )
  122.             total += weight[i];
  123.         int rand = r.nextInt( total );
  124.         int piece; // piece shape IDs are numerated from 0 to numpieces-1
  125.         for ( piece = 0; piece < numpieces; piece++ )
  126.             if ( rand < weight[piece] )
  127.                 break; // choose the current shape as next piece
  128.             else
  129.                 rand -= weight[piece];
  130.  
  131.         // update history and drought
  132.         for ( int j = history.length - 1; j > 0; j-- )
  133.             history[j] = history[j - 1];
  134.         history[0] = piece;
  135.         for ( int i = 0; i < numpieces; i++ )
  136.             drought[i] += 1;
  137.         drought[piece] = 0;
  138.  
  139.         return piece;
  140.     }
  141.  
  142.     // recursively updated randomizer, sum of chances are 1
  143.     public int nextrecursive()
  144.     {
  145.         final double multiplier = 0.5f; // must be between 0 and 1, memoryless = 1
  146.  
  147.         // dealing a piece shape
  148.         double rand = r.nextDouble();
  149.         int piece; // piece shape IDs are numerated from 0 to numpieces-1
  150.         for ( piece = 0; piece < numpieces; piece++ )
  151.             if ( rand < chance[piece] )
  152.                 break; // choose the current shape as next piece
  153.             else
  154.                 rand -= chance[piece];
  155.  
  156.         // recursively update piece chances
  157.         double increasement = chance[piece] * ( 1 - multiplier ) / ( numpieces - 1 );
  158.         for ( int i = 0; i < numpieces; i++ )
  159.             if ( i == piece )
  160.                 chance[i] *= multiplier;
  161.             else
  162.                 chance[i] += increasement;
  163.  
  164.         return piece;
  165.     }
  166.  
  167.     public void insertbag()
  168.     {
  169.         for ( int i = 0; i < numpieces; i++ )
  170.         {
  171.             bag[left] = i;
  172.             left += 1;
  173.         }
  174.     }
  175.  
  176.     public int takefrombag()
  177.     {
  178.         int rand = r.nextInt( left );
  179.         int piece = bag[rand];
  180.         for ( int j = rand; j < left - 1; j++ )
  181.         {
  182.             bag[j] = bag[j + 1];
  183.         }
  184.         left -= 1;
  185.         bag[left] = -1;
  186.         return piece;
  187.     }
  188.  
  189.     public int nextbag14()
  190.     {
  191.         if ( left == 0 )
  192.         {
  193.             insertbag();
  194.             insertbag(); // fill in 14 pieces
  195.         }
  196.         return takefrombag();
  197.     }
  198.  
  199.     public int nextbag()
  200.     {
  201.         if ( left == 0 )
  202.             insertbag(); // fill in 7 pieces
  203.         return takefrombag();
  204.     }
  205.  
  206.     // just to make sure that all piece kinds are handed out equally
  207.     public static void amountpershape()
  208.     {
  209.         Randomizer randomizer = new Randomizer();
  210.         int tries = 1000000;
  211.         int numpieces = randomizer.numpieces;
  212.         for ( int type = 0; type < RAND_LENGTH; type++ )
  213.         {
  214.             int[] sum = new int[numpieces];
  215.             randomizer.type = type;
  216.             randomizer.reset();
  217.             int piece;
  218.             for ( int j = 0; j < tries; j++ )
  219.             {
  220.                 piece = randomizer.next();
  221.                 sum[piece] += 1;
  222. //              if ( type == RAND_RECURSIVE && j <= 100 )
  223. //              {
  224. //                  String str = "";
  225. //                  for ( int i = 0; i < numpieces; i++ )
  226. //                      str += String.format( "%5.2f", 100 * randomizer.chance[i] ) + " ";
  227. //                  System.out.println( str );
  228. //              }
  229.             }
  230.             String str = "Randomizer Nr. " + type + ":";
  231.             for ( int i = 0; i < numpieces; i++ )
  232.                 str += " " + sum[i];
  233.             System.out.println( str );
  234.         }
  235.     }
  236.  
  237.     // The following function takes a look at the following scenario:
  238.     // A certain piece shape is handed out. How long do you have to wait
  239.     // until the next piece of that same shape shows up?
  240.     // More explicitely the function calculates the variance and the
  241.     // standard derivation of that probability distribution.
  242.     // In average, a piece shape is handed out every 7 pieces. But what's
  243.     // the deviations from this mean?
  244.     // The output looks as follows (numbers can vary a little):
  245.     //
  246.     //        Memoryless: derivation = 6,48 , variance = 41,994 , flood = 11,065 , drought = 30,930
  247.     //  Dementia weights: derivation = 5,43 , variance = 29,438 , flood =  8,990 , drought = 20,448
  248.     // Recursive chances: derivation = 4,62 , variance = 21,335 , flood =  7,958 , drought = 13,376
  249.     //        Double bag: derivation = 4,36 , variance = 19,004 , flood =  7,647 , drought = 11,357
  250.     //       7-piece Bag: derivation = 2,83 , variance =  8,001 , flood =  4,000 , drought =  4,000
  251.     //
  252.     // dist Memoryl Dementi Recursi Double  7-piece
  253.     //   1  14,28%   8,23%   8,38%   8,17%   2,04%
  254.     //   2  12,25%  11,39%   8,90%   8,49%   4,09%
  255.     //   3  10,48%  11,31%   9,12%   8,63%   6,12%
  256.     //   4   9,00%  10,30%   9,12%   8,67%   8,17%
  257.     //   5   7,71%   9,14%   8,84%   8,52%  10,20%
  258.     //   6   6,62%   7,72%   8,37%   8,28%  12,24%
  259.     //   7   5,66%   6,52%   7,71%   7,91%  14,28%
  260.     //   8   4,86%   5,51%   6,98%   7,40%  12,24%
  261.     //   9   4,17%   4,69%   6,16%   6,78%  10,22%
  262.     //  10   3,58%   4,00%   5,32%   6,08%   8,16%
  263.     //  11   3,06%   3,42%   4,51%   5,23%   6,12%
  264.     //  12   2,61%   2,95%   3,75%   4,31%   4,08%
  265.     //  13   2,24%   2,50%   3,05%   3,30%   2,05%
  266.     //  14   1,93%   2,14%   2,44%   2,19%   0,00%
  267.     //  15   1,65%   1,80%   1,92%   1,73%   0,00%
  268.     //  16   1,42%   1,53%   1,48%   1,33%   0,00%
  269.     //  17   1,22%   1,28%   1,12%   1,00%   0,00%
  270.     //  18   1,04%   1,07%   0,84%   0,72%   0,00%
  271.     //  19   0,89%   0,89%   0,61%   0,51%   0,00%
  272.     //  20   0,76%   0,73%   0,44%   0,34%   0,00%
  273.     //  21   0,66%   0,60%   0,31%   0,21%   0,00%
  274.     //  22   0,56%   0,49%   0,21%   0,12%   0,00%
  275.     //  23   0,48%   0,39%   0,15%   0,06%   0,00%
  276.     //  24   0,41%   0,31%   0,10%   0,02%   0,00%
  277.     //  25   0,35%   0,25%   0,06%   0,01%   0,00%
  278.     //  26   0,31%   0,20%   0,04%   0,00%   0,00%
  279.     //  27   0,26%   0,15%   0,03%   0,00%   0,00%
  280.     //  28   0,22%   0,12%   0,02%   0,00%   0,00%
  281.     //  29   0,19%   0,09%   0,01%   0,00%   0,00%
  282.     // 30+   1,14%   0,27%   0,02%   0,00%   0,00%
  283.     public static void variance()
  284.     {
  285.         Randomizer randomizer = new Randomizer();
  286.         String str = "Unknown";
  287.         String str2 = "dist";
  288.  
  289.         float[][] percentages = new float[30][RAND_LENGTH];
  290.         int tries = 1000000;
  291.  
  292.         for ( int type = 0; type < RAND_LENGTH; type++ )
  293.         {
  294.             int[] queue = new int[100];
  295.             int[] distances = new int[30];
  296.  
  297.             if ( type == RAND_DORY )
  298.                 str = "Memoryless";
  299.             else if ( type == RAND_OLAF )
  300.                 str = "Dementia weights";
  301.             else if ( type == RAND_RECURSIVE )
  302.                 str = "Recursive chances";
  303.             else if ( type == RAND_BAG14 )
  304.                 str = "Double bag";
  305.             else if ( type == RAND_BAG )
  306.                 str = "7-piece Bag";
  307.  
  308.             str2 += " " + String.format( "%7s", str ).substring( 0, 7 );
  309.             str = String.format( "%21s", str );
  310.             randomizer.type = type;
  311.             randomizer.reset();
  312.  
  313.             // initialize queue
  314.             for ( int i = queue.length - 1; i >= 0; i-- )
  315.                 queue[i] = randomizer.next();
  316.             // now log a very long sequence and sum up the local variances
  317.             long sum = 0, sum2 = 0, sum3 = 0;
  318.             for ( int j = 0; j < tries; j++ )
  319.             {
  320.                 // deal out new piece, update queue
  321.                 for ( int i = queue.length - 2; i >= 0; i-- )
  322.                 {
  323.                     queue[i + 1] = queue[i];
  324.                 }
  325.                 queue[0] = randomizer.next();
  326.                 // did the new piece shape appear recently?
  327.                 int dist;
  328.                 for ( dist = 1; dist < queue.length; dist++ )
  329.                 {
  330.                     if ( queue[dist] == queue[0] )
  331.                         break;
  332.                 }
  333.                 sum += ( dist - 7 ) * ( dist - 7 );
  334.                 if ( dist < 7 )
  335.                     sum2 += ( dist - 7 ) * ( dist - 7 );
  336.                 if ( dist > 7 )
  337.                     sum3 += ( dist - 7 ) * ( dist - 7 );
  338.                 distances[Math.min( dist - 1, distances.length - 1 )] += 1;
  339.             }
  340.             float variance = sum * 1f / tries;
  341.             float flood = sum2 * 1f / tries;
  342.             float drought = sum3 * 1f / tries;
  343.             System.out.println( str + ": derivation = " + String.format( "%4.2f", Math.sqrt( variance ) )
  344.                     + " , variance = " + String.format( "%6.3f", variance ) + " , flood = "
  345.                     + String.format( "%6.3f", flood ) + " , drought = " + String.format( "%6.3f", drought ) );
  346.             for ( int i = 0; i < percentages.length; i++ )
  347.             {
  348.                 percentages[i][type] = distances[i] * 100f / tries;
  349.             }
  350.         }
  351.         // log distance probabilities
  352.         System.out.println();
  353.         System.out.println( str2 );
  354.         for ( int i = 0; i < percentages.length; i++ )
  355.         {
  356.             str = String.format( "%4s", i + 1 );
  357.             if ( i == percentages.length - 1 )
  358.                 str = String.format( "%3s", i + 1 ) + "+";
  359.             for ( int j = 0; j < RAND_LENGTH; j++ )
  360.             {
  361.                 str += "  " + String.format( "%5.2f", percentages[i][j] ) + "%";
  362.             }
  363.             System.out.println( str );
  364.         }
  365.     }
  366.  
  367.     public static void main( String[] args )
  368.     {
  369.         variance();
  370.         // amountpershape();
  371.     }
  372. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement