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