Mercurial > hg > index.fcgi > lj > lj046
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 } |