home · contact · privacy
Server/py: Optimize polling in read_command().
[plomrogue] / libplomrogue.c
1 #include <stddef.h> /* NULL */
2 #include <stdint.h> /* uint8_t, uint16_t, uint32_t, INT8_MIN, INT8_MAX */
3
4
5
6 /* Coordinate for maps of max. 256x256 cells. */
7 struct yx_uint8
8 {
9     uint8_t y;
10     uint8_t x;
11 };
12
13 /* Storage for map_length, set by set_maplength(). */
14 static uint16_t maplength = 0;
15 extern void set_maplength(uint16_t maplength_input)
16 {
17     maplength = maplength_input;
18 }
19
20
21
22 /* Pseudo-randomness seed for rrand(), set by seed_rrand(). */
23 static uint32_t seed = 0;
24
25
26
27 /* Helper to mv_yx_in_dir_legal(). Move "yx" into hex direction "d". */
28 static void mv_yx_in_dir(char d, struct yx_uint8 * yx)
29 {
30     if      (d == 'e')
31     {
32         yx->x = yx->x + (yx->y % 2);
33         yx->y--;
34     }
35     else if (d == 'd')
36     {
37         yx->x++;
38     }
39     else if (d == 'c')
40     {
41         yx->x = yx->x + (yx->y % 2);
42         yx->y++;
43     }
44     else if (d == 'x')
45     {
46         yx->x = yx->x - !(yx->y % 2);
47         yx->y++;
48     }
49     else if (d == 's')
50     {
51         yx->x--;
52     }
53     else if (d == 'w')
54     {
55         yx->x = yx->x - !(yx->y % 2);
56         yx->y--;
57     }
58 }
59
60
61
62 /* Move "yx" into hex direction "dir". Available hex directions are: 'e'
63  * (north-east), 'd' (east), 'c' (south-east), 'x' (south-west), 's' (west), 'w'
64  * (north-west). Returns 1 if the move was legal, 0 if not, and -1 when internal
65  * wrapping limits were exceeded.
66  *
67  * A move is legal if "yx" ends up within the the map and the original wrap
68  * space. The latter is left to a neighbor wrap space if "yx" moves beyond the
69  * minimal (0) or maximal (UINT8_MAX) column or row of possible map space – in
70  * which case "yx".y or "yx".x will snap to the respective opposite side. The
71  * current wrapping state is kept between successive calls until a "yx" of NULL
72  * is passed, in which case the function does nothing but zero the wrap state.
73  * Successive wrapping may move "yx" several wrap spaces into either direction,
74  * or return it into the original wrap space.
75  */
76 static int8_t mv_yx_in_dir_legal(char dir, struct yx_uint8 * yx)
77 {
78     static int8_t wrap_west_east   = 0;
79     static int8_t wrap_north_south = 0;
80     if (!yx)
81     {
82         wrap_west_east = wrap_north_south = 0;
83         return 0;
84     }
85     if (   INT8_MIN == wrap_west_east || INT8_MIN == wrap_north_south
86         || INT8_MAX == wrap_west_east || INT8_MAX == wrap_north_south)
87     {
88         return -1;
89     }
90     struct yx_uint8 original = *yx;
91     mv_yx_in_dir(dir, yx);
92     if      (('e' == dir || 'd' == dir || 'c' == dir) && yx->x < original.x)
93     {
94         wrap_west_east++;
95     }
96     else if (('x' == dir || 's' == dir || 'w' == dir) && yx->x > original.x)
97     {
98         wrap_west_east--;
99     }
100     if      (('w' == dir || 'e' == dir)               && yx->y > original.y)
101     {
102         wrap_north_south--;
103     }
104     else if (('x' == dir || 'c' == dir)               && yx->y < original.y)
105     {
106         wrap_north_south++;
107     }
108     if (   !wrap_west_east && !wrap_north_south
109         && yx->x < maplength && yx->y < maplength)
110     {
111         return 1;
112     }
113     return 0;
114 }
115
116
117
118 /* Wrapper around mv_yx_in_dir_legal() that stores new coordinate in res_y/x,
119  * (return with result_y/x()), and immediately resets the wrapping.
120  */
121 static uint8_t res_y = 0;
122 static uint8_t res_x = 0;
123 extern uint8_t mv_yx_in_dir_legal_wrap(char dir, uint8_t y, uint8_t x)
124 {
125     struct yx_uint8 yx;
126     yx.y = y;
127     yx.x = x;
128     uint8_t result = mv_yx_in_dir_legal(dir, &yx);
129     mv_yx_in_dir_legal(0, NULL);
130     res_y = yx.y;
131     res_x = yx.x;
132     return result;
133 }
134 extern uint8_t result_y()
135 {
136     return res_y;
137 }
138 extern uint8_t result_x()
139 {
140     return res_x;
141 }
142
143
144
145 /* With set_seed set, set seed global to seed_input. In any case, return it. */
146 extern uint32_t seed_rrand(uint8_t set_seed, uint32_t seed_input)
147 {
148     if (set_seed)
149     {
150         seed = seed_input;
151     }
152     return seed;
153 }
154
155
156
157 /* Return 16-bit number pseudo-randomly generated via Linear Congruential
158  * Generator algorithm with some proven constants. Use instead of any rand() to
159   * ensure portability of the same pseudo-randomness across systems.
160  */
161 extern uint16_t rrand()
162 {   /* Constants as recommended by POSIX.1-2001 (see man page rand(3)). */
163     seed = ((seed * 1103515245) + 12345) % 4294967296;
164     return (seed >> 16); /* Ignore less random least significant bits. */
165 }