1 /* flatdice --- the dice that remember their last value
2 * by Oohara Yuuma <oohara@libra.interq.or.jp>
3 * $Id: flatdice.c,v 1.20 2005/07/06 13:26:10 oohara Exp $
4 */
5
6 #include <stdio.h>
7 /* malloc, rand */
8 #include <stdlib.h>
9
10 #include "flatdice.h"
11
12 /* return a random integer in [0, side - 1]
13 * the return value is adjusted so that
14 * * it is likely to differ from the last value
15 * (this adjustment is strong if "repeat" is large)
16 * * all possible values appear almost same times
17 * (this adjustment is weak if "randomness" is large)
18 */
19 flatdice *
flatdice_new(int side,int randomness,int repeat)20 flatdice_new(int side, int randomness, int repeat)
21 {
22 int i;
23 flatdice *new = NULL;
24
25 /* sanity check */
26 if (side <= 0)
27 {
28 fprintf(stderr, "flatdice_new: side is non-positive (%d)\n", side);
29 return NULL;
30 }
31 if (randomness <= 0)
32 {
33 fprintf(stderr, "flatdice_new: randomness is non-positive (%d)\n",
34 randomness);
35 return NULL;
36 }
37 if (repeat <= 0)
38 {
39 fprintf(stderr, "flatdice_new: repeat is non-positive (%d)\n", repeat);
40 return NULL;
41 }
42
43 new = (flatdice *) malloc(sizeof(flatdice));
44 if (new == NULL)
45 {
46 fprintf(stderr, "flatdice_new: malloc(new) failed\n");
47 return NULL;
48 }
49
50 new->side = side;
51 new->randomness = randomness;
52 new->repeat = repeat;
53 new->stock = NULL;
54 new->last = -1;
55
56 new->stock = (int *) malloc(sizeof(int) * side);
57 if (new == NULL)
58 {
59 fprintf(stderr, "flatdice_new: malloc(new->stock) failed\n");
60 flatdice_delete(new);
61 return NULL;
62 }
63 for (i = 0; i < side; i++)
64 new->stock[i] = randomness;
65
66 return new;
67 }
68
69 void
flatdice_delete(flatdice * p)70 flatdice_delete(flatdice *p)
71 {
72 if (p != NULL)
73 {
74 if (p->stock != NULL)
75 {
76 free(p->stock);
77 p->stock = NULL;
78 }
79 free(p);
80 }
81 }
82
83 /* return 1 (true) or 0 (false) */
84 int
flatdice_valid(flatdice * p,int quiet)85 flatdice_valid(flatdice *p, int quiet)
86 {
87 int i;
88 int total;
89
90 /* sanity check */
91 if (p == NULL)
92 {
93 if (!quiet)
94 fprintf(stderr, "flatdice_valid: p is NULL\n");
95 return 0;
96 }
97 if (p->side <= 0)
98 {
99 if (!quiet)
100 fprintf(stderr, "flatdice_valid: p->side is non-positive (%d)\n",
101 p->side);
102 return 0;
103 }
104 if (p->randomness <= 0)
105 {
106 if (!quiet)
107 fprintf(stderr, "flatdice_valid: p->randomness is non-positive (%d)\n",
108 p->randomness);
109 return 0;
110 }
111 if (p->repeat <= 0)
112 {
113 if (!quiet)
114 fprintf(stderr, "flatdice_valid: p->repeat is non-positive (%d)\n",
115 p->repeat);
116 return 0;
117 }
118 if (p->stock == NULL)
119 {
120 if (!quiet)
121 fprintf(stderr, "flatdice_valid: p->stock is NULL\n");
122 return 0;
123 }
124
125 total = 0;
126 for (i = 0; i < p->side; i++)
127 {
128 if (p->stock[i] < 0)
129 {
130 if (!quiet)
131 fprintf(stderr, "flatdice_valid: p->stock[%d] is negative (%d)\n",
132 i, p->stock[i]);
133 return 0;
134 }
135 if (i == p->last)
136 total += p->stock[i];
137 else
138 total += p->stock[i] * p->repeat;
139 }
140 if (total <= 0)
141 {
142 if (!quiet)
143 fprintf(stderr, "flatdice_valid: total is non-positive (%d)\n", total);
144 return 0;
145 }
146
147 return 1;
148 }
149
150 /* return [0, p->side - 1] on success, -1 on error */
151 int
flatdice_next(flatdice * p)152 flatdice_next(flatdice *p)
153 {
154 int i;
155 int total;
156 int n1;
157 int n2;
158 int needed;
159 int result = -1;
160
161 /* sanity check */
162 if (p == NULL)
163 {
164 fprintf(stderr, "flatdice_next: p is NULL\n");
165 return -1;
166 }
167 if (!flatdice_valid(p, 0))
168 {
169 fprintf(stderr, "flatdice_next: p is invalid\n");
170 return -1;
171 }
172
173 total = 0;
174 for (i = 0; i < p->side; i++)
175 {
176 if (i == p->last)
177 total += p->stock[i];
178 else
179 total += p->stock[i] * p->repeat;
180 }
181
182 n1 = rand() % total + 1;
183 n2 = 0;
184 for (i = 0; i < p->side; i++)
185 {
186 if (((i == p->last) && (n2 + p->stock[i] >= n1))
187 || ((i != p->last) && (n2 + p->stock[i] * p->repeat >= n1)))
188 {
189 result = i;
190 p->last = i;
191 (p->stock[i])--;
192 if (p->stock[i] < 0)
193 p->stock[i] = 0;
194 break;
195 }
196 if (i == p->last)
197 n2 += p->stock[i];
198 else
199 n2 += p->stock[i] * p->repeat;
200 }
201
202 needed = p->randomness;
203 for (i = 0; i < p->side; i++)
204 {
205 if (needed > p->randomness - p->stock[i])
206 needed = p->randomness - p->stock[i];
207 }
208 if (needed < 0)
209 needed = 0;
210 for (i = 0; i < p->side; i++)
211 p->stock[i] += needed;
212
213 return result;
214 }
215
216 /* return 0 on success, 1 on error */
217 int
flatdice_reset(flatdice * p)218 flatdice_reset(flatdice *p)
219 {
220 int i;
221
222 /* sanity check */
223 if (p == NULL)
224 {
225 fprintf(stderr, "flatdice_reset: p is NULL\n");
226 return 1;
227 }
228 if (!flatdice_valid(p, 0))
229 {
230 fprintf(stderr, "flatdice_reset: p is invalid\n");
231 return 1;
232 }
233
234 for (i = 0; i < p->side; i++)
235 p->stock[i] = p->randomness;
236 p->last = -1;
237
238 return 0;
239 }
240