view src/random.c @ 0:c84446dfb3f5

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