-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
287 lines (221 loc) · 7.56 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#include <tuple>
#include "Font.hpp"
#include "Graphic.hpp"
#include "Keypad.hpp"
#include "Square.hpp"
#include "arm7type.h"
#include "slider.h"
/******************** Unit test *************************/
#ifndef SQLIST
#define SQLIST \
"123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-0"
#endif
template <typename T, usize_t N>
static constexpr usize_t square(const T (&a)[N], usize_t n = 2)
{
return n * n >= N ? n : square(a, n + 1);
}
template <typename T, usize_t N>
static constexpr usize_t slen(const T (&)[N])
{
return N;
}
static const u8arm_t sqlist[] = SQLIST;
static constexpr const u32arm_t WxH = square(sqlist) - 1;
static_assert(WxH * WxH == slen(sqlist) - 1,
"WxH*WxH !=slen(sqlist) => It's not square!!");
/********************** SEED ***********************/
#ifndef INITSEED
#define INITSEED (1)
#endif
/********************** Graphic ***********************/
#define FRGAP 4
#define RGAP 1
#define CGAP RGAP
#define WIDTH ((ROW - RGAP * (WxH - 1) - FRGAP * 2) / WxH)
#define FCGAP ((COL - CGAP * (WxH - 1) - WIDTH * WxH) / 2)
using Color = Color3;
using Color_t = Color::Color_t;
using Font = X11_clR8x8_Font<Color>;
static constexpr const GraphicDevice::Dispcnt_t regcontrol = 0x400 | Color::mode;
static constexpr const i32arm_t COL = Color::COL;
static constexpr const i32arm_t ROW = Color::ROW;
static constexpr const Color_t BOXCOLOR = RGB15(31, 0, 0);
static constexpr const Color_t NUMCOLOR = RGB15(0, 0, 31);
static constexpr const Color_t COMBOXCOLOR = RGB15(0, 31, 0);
static constexpr const Color_t COMNUMCOLOR = NUMCOLOR;
static constexpr const Color_t BGCOLOR = RGB15(0, 0, 0);
/********************** Game function ***********************/
template <class FONT, class COLORMODE, usize_t N, usize_t M>
static void drawboard(const Graphicx<COLORMODE>& g,
const Square<FONT, COLORMODE>& square,
const Square<FONT, COLORMODE>& comsquare,
const u32arm_t (&sq)[N], const u8arm_t (&sqlist)[M],
u32arm_t index)
{
for (usize_t i = 0, rgap = FRGAP, k = 0; i < WxH;
++i, rgap += (RGAP + square.width))
for (usize_t j = 0, cgap = FCGAP; j < WxH;
++j, cgap += (CGAP + square.width), ++k)
if (sq[k] != index)
(sq[k] == k ? comsquare : square)
.draw(g, Point(cgap, rgap), sqlist[sq[k]]);
else
g.rectangle(BGCOLOR, cgap, rgap, cgap + square.width,
rgap + square.width);
}
template <class FONT, class COLORMODE, usize_t N, usize_t M>
static void slidesquare(const Graphicx<COLORMODE>& g,
const Square<FONT, COLORMODE>& square,
const Square<FONT, COLORMODE>& comsquare,
const u32arm_t (&sq)[N], const u8arm_t (&sqlist)[M],
u32arm_t from, u32arm_t to)
{
const u32arm_t jfrom = from % WxH;
const u32arm_t ifrom = from / WxH;
const u32arm_t jto = to % WxH;
const u32arm_t ito = to / WxH;
const u32arm_t xto = FCGAP + jto * (square.width + CGAP);
const u32arm_t yto = FRGAP + ito * (square.width + RGAP);
(sq[to] == to ? comsquare : square).draw(g, Point(xto, yto), sqlist[sq[to]]);
const u32arm_t xfrom = FCGAP + jfrom * (square.width + CGAP);
const u32arm_t yfrom = FRGAP + ifrom * (square.width + RGAP);
g.rectangle(BGCOLOR, xfrom, yfrom, xfrom + square.width,
yfrom + square.width);
}
template <u32arm_t N>
struct SlidingPuzzle {
static constexpr const u32arm_t WxH = N;
static constexpr const u32arm_t index = WxH * WxH - 1;
static void initgame(u32arm_t* const sq, u32arm_t* seed, u32arm_t index)
{
initsq(sq, WxH);
randomsq(sq, index, WxH, seed);
}
u32arm_t seed, origseed;
u32arm_t sq[WxH * WxH];
inline SlidingPuzzle(u32arm_t seed)
: seed(seed)
, origseed(seed)
{
initgame(sq, &seed, index);
}
void initgame(u32arm_t seed)
{
origseed = seed;
this->seed = seed;
initgame(sq, &this->seed, index);
}
inline u32arm_t slide(u32arm_t kid) { return ::slide(sq, kid, index, WxH); }
};
template <u32arm_t N, typename KeypadDevice>
static std::tuple<u32arm_t, u32arm_t, u32arm_t, u32arm_t> keypadaction(
const SlidingPuzzle<N>& game, Keypad<KeypadDevice>& keypad)
{
u32arm_t indexfrom = 0, indexto = 0;
auto newseed = game.seed;
auto keydownfunc =
[&indexfrom, &indexto, &newseed, origseed = game.origseed, sq = game.sq,
index = game.index, WxH = game.WxH](
const typename Keypad<KeypadDevice>::Key& key) mutable -> i32arm_t {
u32arm_t kid = -1U;
struct point p;
getxy(indexto = getindex(sq, index, WxH), &p, WxH);
switch (key.key) {
case key.KEY_UP:
if (p.y > 0) {
indexfrom = indexto - WxH;
kid = cmd_up;
}
break;
case key.KEY_DOWN:
if (p.y < WxH - 1) {
indexfrom = indexto + WxH;
kid = cmd_down;
}
break;
case key.KEY_LEFT:
if (p.x > 0) {
indexfrom = indexto - 1;
kid = cmd_left;
}
break;
case key.KEY_RIGHT:
if (p.x < WxH - 1) {
indexfrom = indexto + 1;
kid = cmd_right;
}
break;
case key.KEY_A:
kid = cmd_right + 1;
newseed = origseed - 1;
break;
case key.KEY_B:
kid = cmd_right + 2;
newseed = origseed + 1;
break;
case key.KEY_START:
kid = cmd_right + 3;
newseed = origseed;
break;
case key.KEY_SELECT:
kid = cmd_right + 4;
break;
default:
break;
}
return kid;
};
auto keyupfunc =
[](const typename Keypad<KeypadDevice>::Key& key) -> i32arm_t {
return (key == key.KEY_SELECT) ? cmd_right + 5 : -1U;
};
return {
keypad.dispatch(keydownfunc, keypad.defaultkeyfunc(-1U), keyupfunc,
keypad.defaultkeyfunc(-1U)),
indexfrom, indexto, newseed
};
}
extern "C" [[noreturn]] void main()
{
constexpr const Square<Font, Color> square { WIDTH, BOXCOLOR, NUMCOLOR };
constexpr const Square<Font, Color> comsquare { WIDTH, COMBOXCOLOR,
COMNUMCOLOR };
SlidingPuzzle<WxH> game(INITSEED);
const auto& sq = game.sq;
constexpr const auto index = game.index;
GraphicDevice::refdispcnt() = regcontrol;
constexpr const Graphicx<Color> g;
g.bgcolor(BGCOLOR);
drawboard(g, square, comsquare, sq, sqlist, index);
Keypad<KeypadDevice> keypad;
while (true) {
g.waitVSync();
// (C++17) init variable in switch statement + struct binding
switch (const auto& [kid, indexfrom, indexto, newseed] = keypadaction(game, keypad); kid) {
case cmd_up:
case cmd_down:
case cmd_left:
case cmd_right:
if (game.slide(kid) != -1UL)
slidesquare(g, square, comsquare, sq, sqlist, indexfrom, indexto);
break;
case cmd_right + 1:
case cmd_right + 2:
case cmd_right + 3:
game.initgame(newseed);
drawboard(g, square, comsquare, sq, sqlist, index);
break;
case cmd_right + 4: {
u32arm_t sq[WxH * WxH];
initsq(sq, WxH);
drawboard(g, square, comsquare, sq, sqlist, index);
} break;
case cmd_right + 5:
drawboard(g, square, comsquare, sq, sqlist, index);
break;
default:
break;
}
}
}