annotate src/random.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
rev   line source
paulo@0 1 /* Piece randomizers for LOCKJAW, an implementation of the Soviet Mind Game
paulo@0 2
paulo@0 3 Copyright (C) 2006-2007 Damian Yerrick <tepples+lj@spamcop.net>
paulo@0 4
paulo@0 5 This work is free software; you can redistribute it and/or modify
paulo@0 6 it under the terms of the GNU General Public License as published by
paulo@0 7 the Free Software Foundation; either version 2 of the License, or
paulo@0 8 (at your option) any later version.
paulo@0 9
paulo@0 10 This program is distributed in the hope that it will be useful,
paulo@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
paulo@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
paulo@0 13 GNU General Public License for more details.
paulo@0 14
paulo@0 15 You should have received a copy of the GNU General Public License
paulo@0 16 along with this program; if not, write to the Free Software
paulo@0 17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
paulo@0 18
paulo@0 19 Original game concept and design by Alexey Pajitnov.
paulo@0 20 The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg,
paulo@0 21 or The Tetris Company LLC.
paulo@0 22
paulo@0 23 */
paulo@0 24
paulo@0 25 #include "lj.h"
paulo@0 26
paulo@0 27 // Order matters. The history randomizers prefer to give out the
paulo@0 28 // front half early in the game. You don't want to give an S or Z
paulo@0 29 // first, or you force a slide. You also don't want to give an O
paulo@0 30 // first, or you force a slide with OS or OZ.
paulo@0 31
paulo@0 32 static const signed char piecesNoI[] = {
paulo@0 33 1, 2, 5, // front half: J L T
paulo@0 34 3, 4, 6 // back half: O S Z
paulo@0 35 };
paulo@0 36
paulo@0 37 static const signed char piecesTetrominoes[] = {
paulo@0 38 0, 1, 2, 5, // front half: I J L T
paulo@0 39 3, 4, 6 // back half: O S Z
paulo@0 40 };
paulo@0 41
paulo@0 42 static const signed char piecesWithSmall[] = {
paulo@0 43 0, 1, 2, 5, 9, // front half: I J L T L3
paulo@0 44 3, 7, 8, 4, 6 // back half: O I2 I3 S Z
paulo@0 45 // make sure that the S and Z are in the back half
paulo@0 46 };
paulo@0 47
paulo@0 48 static const signed char piecesSZ[] = {
paulo@0 49 4, 6
paulo@0 50 };
paulo@0 51
paulo@0 52 static const signed char piecesI[] = {
paulo@0 53 0
paulo@0 54 };
paulo@0 55
paulo@0 56 static const signed char piecesT[] = {
paulo@0 57 5
paulo@0 58 };
paulo@0 59
paulo@0 60 static const signed char *const pieceSets[] = {
paulo@0 61 piecesTetrominoes,
paulo@0 62 piecesNoI,
paulo@0 63 piecesSZ,
paulo@0 64 piecesI,
paulo@0 65 piecesWithSmall,
paulo@0 66 piecesT
paulo@0 67 };
paulo@0 68
paulo@0 69 static const unsigned char pieceSetSizes[] = {
paulo@0 70 sizeof(piecesTetrominoes),
paulo@0 71 sizeof(piecesNoI),
paulo@0 72 sizeof(piecesSZ),
paulo@0 73 sizeof(piecesI),
paulo@0 74 sizeof(piecesWithSmall),
paulo@0 75 sizeof(piecesT)
paulo@0 76 };
paulo@0 77
paulo@0 78 static void bagInitRandomize(LJField *p) {
paulo@0 79 p->permuPhase = 0;
paulo@0 80 }
paulo@0 81
paulo@0 82 static unsigned int bagRandomize(LJField *p) {
paulo@0 83 unsigned int setNo = p->pieceSet;
paulo@0 84 unsigned int len = pieceSetSizes[setNo];
paulo@0 85 const signed char *set = pieceSets[setNo];
paulo@0 86
paulo@0 87 int piece;
paulo@0 88
paulo@0 89 // If we're out of permutation pieces, make new ones by copying
paulo@0 90 // from one of the rand#Bag arrays until we hit the -1 sentinel.
paulo@0 91 if (p->permuPhase == 0) {
paulo@0 92 int pos;
paulo@0 93
paulo@0 94 for (pos = 0; pos < len; ++pos) {
paulo@0 95 p->permuPiece[pos] = set[pos];
paulo@0 96 p->permuPiece[pos + len] = set[pos];
paulo@0 97 }
paulo@0 98
paulo@0 99 // Double bag: Add one randomly chosen piece to the bag
paulo@0 100 if (p->randomizer == LJRAND_2BAG) {
paulo@0 101 pos *= 2;
paulo@0 102 }
paulo@0 103 // 7+1 Bag (TOJ style): Add one randomly chosen piece to the bag
paulo@0 104 else if (p->randomizer == LJRAND_BAGPLUS1) {
paulo@0 105 p->permuPiece[pos++] = set[ljRand(p) % len];
paulo@0 106 }
paulo@0 107 p->permuPhase = pos;
paulo@0 108 }
paulo@0 109
paulo@0 110 // Choose a position in the remainder of the deck
paulo@0 111 int r = (p->permuPhase > 1) ? ljRand(p) % p->permuPhase : 0;
paulo@0 112
paulo@0 113 // Swap the top card with the card at this position
paulo@0 114 piece = p->permuPiece[r];
paulo@0 115 p->permuPiece[r] = p->permuPiece[--p->permuPhase];
paulo@0 116 return piece;
paulo@0 117 }
paulo@0 118
paulo@0 119 static void mtbInitRandomize(LJField *p) {
paulo@0 120 unsigned int setNo = p->pieceSet;
paulo@0 121 unsigned int len = pieceSetSizes[setNo];
paulo@0 122 const signed char *set = pieceSets[setNo];
paulo@0 123
paulo@0 124 // At game start, front three are I, J, L
paulo@0 125 // Back four (never dealt as first tetromino) are O, S, T, Z
paulo@0 126 for (int i = 0; i < len; ++i) {
paulo@0 127 p->permuPiece[i] = set[i];
paulo@0 128 }
paulo@0 129 }
paulo@0 130
paulo@0 131 static unsigned int mtbRandomize(LJField *p) {
paulo@0 132 unsigned int setNo = p->pieceSet;
paulo@0 133 unsigned int len = pieceSetSizes[setNo];
paulo@0 134
paulo@0 135 // Choose a piece from the three in front
paulo@0 136 int r = ljRand(p) % (len / 2);
paulo@0 137 int piece = p->permuPiece[r];
paulo@0 138
paulo@0 139 // Move it to the back
paulo@0 140 for (; r < len - 1; ++r) {
paulo@0 141 p->permuPiece[r] = p->permuPiece[r + 1];
paulo@0 142 }
paulo@0 143 p->permuPiece[len - 1] = piece;
paulo@0 144 return piece;
paulo@0 145 }
paulo@0 146
paulo@0 147 static void tgmInitRandomize(LJField *p) {
paulo@0 148 unsigned int setNo = p->pieceSet;
paulo@0 149 unsigned int len = pieceSetSizes[setNo];
paulo@0 150
paulo@0 151 p->permuPiece[0] = 0;
paulo@0 152 for (int i = len / 2; i < len; ++i) {
paulo@0 153 p->permuPiece[i] = i & 1 ? LJP_Z : LJP_S;
paulo@0 154 }
paulo@0 155 }
paulo@0 156
paulo@0 157 /* State of TGM randomizer:
paulo@0 158 * permuPiece[3..6]: history, [3] most recent
paulo@0 159 * permuPiece[2]: 0 for first piece (use equal probability I, J, L, T)
paulo@0 160 * or 1 for subsequent pieces
paulo@0 161 */
paulo@0 162 static unsigned int tgmRandomize(LJField *p) {
paulo@0 163 unsigned int setNo = p->pieceSet;
paulo@0 164 unsigned int len = pieceSetSizes[setNo];
paulo@0 165 const signed char *set = pieceSets[setNo];
paulo@0 166
paulo@0 167 int r = ljRand(p) ^ (ljRand(p) << 15);
paulo@0 168 int piece;
paulo@0 169
paulo@0 170 if (p->permuPiece[0]) {
paulo@0 171
paulo@0 172 // Roll up to 6 times for pieces
paulo@0 173 for (int rolls = 6;
paulo@0 174 rolls > 0;
paulo@0 175 --rolls, r /= len) {
paulo@0 176 piece = set[r % len];
paulo@0 177 int found = 0;
paulo@0 178
paulo@0 179 // If the piece is not in the history, use it now
paulo@0 180 for (int histoPos = len / 2;
paulo@0 181 !found && histoPos < len;
paulo@0 182 ++histoPos) {
paulo@0 183 if (piece == p->permuPiece[histoPos]) {
paulo@0 184 found = 1;
paulo@0 185 }
paulo@0 186 }
paulo@0 187 if (!found) {
paulo@0 188 break;
paulo@0 189 }
paulo@0 190 }
paulo@0 191 } else {
paulo@0 192 p->permuPiece[0] = 1;
paulo@0 193 // Generate only pieces in the first half of the list
paulo@0 194 piece = set[r % ((len + 1) / 2)];
paulo@0 195 if (piece == LJP_O) {
paulo@0 196 piece = LJP_T;
paulo@0 197 }
paulo@0 198 }
paulo@0 199
paulo@0 200 // Move it to the back
paulo@0 201 for (r = len / 2; r < len - 1; ++r) {
paulo@0 202 p->permuPiece[r] = p->permuPiece[r + 1];
paulo@0 203 }
paulo@0 204 p->permuPiece[len - 1] = piece;
paulo@0 205 return piece;
paulo@0 206 }
paulo@0 207
paulo@0 208 void initRandomize(LJField *p) {
paulo@0 209 unsigned int setNo = p->pieceSet;
paulo@0 210 unsigned int len = pieceSetSizes[setNo];
paulo@0 211
paulo@0 212 if (len < 2) {
paulo@0 213 p->randomizer = LJRAND_PURE;
paulo@0 214 }
paulo@0 215
paulo@0 216 switch (p->randomizer) {
paulo@0 217 case LJRAND_PURE:
paulo@0 218 break;
paulo@0 219 case LJRAND_BAG:
paulo@0 220 case LJRAND_BAGPLUS1:
paulo@0 221 case LJRAND_2BAG:
paulo@0 222 bagInitRandomize(p);
paulo@0 223 break;
paulo@0 224 case LJRAND_HIST_INF:
paulo@0 225 mtbInitRandomize(p);
paulo@0 226 break;
paulo@0 227 case LJRAND_HIST_6:
paulo@0 228 tgmInitRandomize(p);
paulo@0 229 break;
paulo@0 230 }
paulo@0 231 }
paulo@0 232
paulo@0 233 unsigned int randomize(LJField *p) {
paulo@0 234 switch (p->randomizer) {
paulo@0 235
paulo@0 236 case LJRAND_BAG:
paulo@0 237 case LJRAND_BAGPLUS1:
paulo@0 238 case LJRAND_2BAG:
paulo@0 239 return bagRandomize(p);
paulo@0 240 case LJRAND_HIST_INF:
paulo@0 241 return mtbRandomize(p);
paulo@0 242 case LJRAND_HIST_6:
paulo@0 243 return tgmRandomize(p);
paulo@0 244 case LJRAND_PURE:
paulo@0 245 default:
paulo@0 246 {
paulo@0 247 unsigned int setNo = p->pieceSet;
paulo@0 248 unsigned int len = pieceSetSizes[setNo];
paulo@0 249 const signed char *set = pieceSets[setNo];
paulo@0 250 return set[ljRand(p) % len];
paulo@0 251 }
paulo@0 252 }
paulo@0 253 }