comparison src/random.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:0456bddd67bd
1 /* Piece randomizers for LOCKJAW, an implementation of the Soviet Mind Game
2
3 Copyright (C) 2006-2007 Damian Yerrick <tepples+lj@spamcop.net>
4
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.
9
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.
14
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
18
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.
22
23 */
24
25 #include "lj.h"
26
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.
31
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 };
36
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 };
41
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 };
47
48 static const signed char piecesSZ[] = {
49 4, 6
50 };
51
52 static const signed char piecesI[] = {
53 0
54 };
55
56 static const signed char piecesT[] = {
57 5
58 };
59
60 static const signed char *const pieceSets[] = {
61 piecesTetrominoes,
62 piecesNoI,
63 piecesSZ,
64 piecesI,
65 piecesWithSmall,
66 piecesT
67 };
68
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 };
77
78 static void bagInitRandomize(LJField *p) {
79 p->permuPhase = 0;
80 }
81
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];
86
87 int piece;
88
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;
93
94 for (pos = 0; pos < len; ++pos) {
95 p->permuPiece[pos] = set[pos];
96 p->permuPiece[pos + len] = set[pos];
97 }
98
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 }
109
110 // Choose a position in the remainder of the deck
111 int r = (p->permuPhase > 1) ? ljRand(p) % p->permuPhase : 0;
112
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 }
118
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];
123
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 }
130
131 static unsigned int mtbRandomize(LJField *p) {
132 unsigned int setNo = p->pieceSet;
133 unsigned int len = pieceSetSizes[setNo];
134
135 // Choose a piece from the three in front
136 int r = ljRand(p) % (len / 2);
137 int piece = p->permuPiece[r];
138
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 }
146
147 static void tgmInitRandomize(LJField *p) {
148 unsigned int setNo = p->pieceSet;
149 unsigned int len = pieceSetSizes[setNo];
150
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 }
156
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];
166
167 int r = ljRand(p) ^ (ljRand(p) << 15);
168 int piece;
169
170 if (p->permuPiece[0]) {
171
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;
178
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 }
199
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 }
207
208 void initRandomize(LJField *p) {
209 unsigned int setNo = p->pieceSet;
210 unsigned int len = pieceSetSizes[setNo];
211
212 if (len < 2) {
213 p->randomizer = LJRAND_PURE;
214 }
215
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 }
232
233 unsigned int randomize(LJField *p) {
234 switch (p->randomizer) {
235
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 }