Format code to tabs
This commit is contained in:
parent
4b7fe1fc5f
commit
14a0336886
1 changed files with 238 additions and 236 deletions
470
recursive.cpp
470
recursive.cpp
|
@ -26,286 +26,288 @@ tile pas(int t) { return (t % 2) ? p1 : p2; }
|
||||||
#define IMG_COUNT 2
|
#define IMG_COUNT 2
|
||||||
array<Texture2D, IMG_COUNT> textures;
|
array<Texture2D, IMG_COUNT> textures;
|
||||||
void prepareTextures() {
|
void prepareTextures() {
|
||||||
const char* paths[] = {"img/circle.png", "img/cross.png"};
|
const char* paths[] = {"img/circle.png", "img/cross.png"};
|
||||||
for(int i = 0; i < IMG_COUNT; i++) {
|
for(int i = 0; i < IMG_COUNT; i++) {
|
||||||
Image img;
|
Image img;
|
||||||
img = LoadImage(paths[i]);
|
img = LoadImage(paths[i]);
|
||||||
textures[i] = LoadTextureFromImage(img);
|
textures[i] = LoadTextureFromImage(img);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void renderImage(tile t, Rectangle dst, Color color = WHITE) {
|
void renderImage(tile t, Rectangle dst, Color color = WHITE) {
|
||||||
if(t == fr || t == tie) return;
|
if(t == fr || t == tie) return;
|
||||||
Texture tex = textures[t-1];
|
Texture tex = textures[t-1];
|
||||||
Rectangle src = {0, 0, (float)tex.width, (float)tex.height};
|
Rectangle src = {0, 0, (float)tex.width, (float)tex.height};
|
||||||
DrawTexturePro(textures[t-1], src, dst, {0,0}, 0, color);
|
DrawTexturePro(textures[t-1], src, dst, {0,0}, 0, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pos {
|
struct pos {
|
||||||
int x, y;
|
int x, y;
|
||||||
pos() : x(-1), y(-1) {}
|
pos() : x(-1), y(-1) {}
|
||||||
pos(int px, int py) : x(px), y(py) {}
|
pos(int px, int py) : x(px), y(py) {}
|
||||||
pos(Vector2 v) : x(v.x), y(v.y) {}
|
pos(Vector2 v) : x(v.x), y(v.y) {}
|
||||||
pos normalize() {
|
|
||||||
if(x >= 3) x = 2;
|
pos operator/(int a) {return {x/a, y/a};};
|
||||||
else if(x < 0) x = 0;
|
pos operator%(int a) {return {x%a, y%a};};
|
||||||
if(y >= 3) y = 2;
|
|
||||||
else if(y < 0) y = 0;
|
pos normalize() {
|
||||||
return *this;
|
if(x >= 3) x = 2;
|
||||||
}
|
else if(x < 0) x = 0;
|
||||||
pos operator/(int a) {return {x/a, y/a};};
|
if(y >= 3) y = 2;
|
||||||
pos operator%(int a) {return {x%a, y%a};};
|
else if(y < 0) y = 0;
|
||||||
int to_int() { return 3*y + x; }
|
return *this;
|
||||||
deque<int> to_deque(int depth, int screenSize) {
|
}
|
||||||
deque<int> r = {};
|
int to_int() { return 3*y + x; }
|
||||||
pos pp = pos(x,y);
|
deque<int> to_deque(int depth, int screenSize) {
|
||||||
int pwr = 1;
|
deque<int> r = {};
|
||||||
for(int i = 1; i <= depth; i++) {
|
pos pp = pos(x,y);
|
||||||
pwr *= 3;
|
int pwr = 1;
|
||||||
pos ppos = (pp/(screenSize/pwr));
|
for(int i = 1; i <= depth; i++) {
|
||||||
if(ppos.x > 2 || ppos.y > 2) return {};
|
pwr *= 3;
|
||||||
r.push_back(ppos.to_int());
|
pos ppos = (pp/(screenSize/pwr));
|
||||||
pp = pp%(screenSize/pwr);
|
if(ppos.x > 2 || ppos.y > 2) return {};
|
||||||
}
|
r.push_back(ppos.to_int());
|
||||||
return r;
|
pp = pp%(screenSize/pwr);
|
||||||
}
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OKAY -1
|
#define OKAY -1
|
||||||
#define CHANGE -2
|
#define CHANGE -2
|
||||||
struct Block {
|
struct Block {
|
||||||
tile t = fr;
|
tile t = fr;
|
||||||
bool leaf = false;
|
bool leaf = false;
|
||||||
Rectangle target;
|
Rectangle target;
|
||||||
array<Block*, 9> sons;
|
array<Block*, 9> sons;
|
||||||
|
|
||||||
Block() {}
|
Block() {}
|
||||||
Block(int depth, Rectangle trg) {
|
Block(int depth, Rectangle trg) {
|
||||||
target = trg;
|
target = trg;
|
||||||
int x = trg.x, y = trg.y, w = trg.width, h = trg.height;
|
int x = trg.x, y = trg.y, w = trg.width, h = trg.height;
|
||||||
if(depth == 0) leaf = true;
|
if(depth == 0) leaf = true;
|
||||||
else
|
else
|
||||||
for(int i = 0; i < 9; i++)
|
for(int i = 0; i < 9; i++)
|
||||||
sons[i] = new Block(depth-1,
|
sons[i] = new Block(depth-1,
|
||||||
{float(int(x + w/3 * (i%3))), float(int(y + h/3 * (i/3))), float(int(w/3)), float(int(h/3))});
|
{float(int(x + w/3 * (i%3))), float(int(y + h/3 * (i/3))), float(int(w/3)), float(int(h/3))});
|
||||||
}
|
}
|
||||||
int change(tile pl) {
|
int change(tile pl) {
|
||||||
t = pl;
|
t = pl;
|
||||||
if(pl == fr)
|
if(pl == fr)
|
||||||
return OKAY;
|
return OKAY;
|
||||||
return CHANGE;
|
return CHANGE;
|
||||||
}
|
}
|
||||||
bool playable(deque<int> v) {
|
bool playable(deque<int> v) {
|
||||||
if(leaf && t == fr) return true;
|
if(leaf && t == fr) return true;
|
||||||
if(t != fr || v.size() == 0) return false;
|
if(t != fr || v.size() == 0) return false;
|
||||||
int son = v.front();
|
int son = v.front();
|
||||||
v.pop_front();
|
v.pop_front();
|
||||||
return sons[son]->playable(v);
|
return sons[son]->playable(v);
|
||||||
}
|
}
|
||||||
int play(deque<int> v, tile pl) {
|
int play(deque<int> v, tile pl) {
|
||||||
if(t != fr) return v.size();
|
if(t != fr) return v.size();
|
||||||
if(leaf) return change(pl);
|
if(leaf) return change(pl);
|
||||||
if(v.size() == 0) return OKAY;
|
if(v.size() == 0) return OKAY;
|
||||||
|
|
||||||
int son = v.front();
|
int son = v.front();
|
||||||
v.erase(v.begin());
|
v.erase(v.begin());
|
||||||
int rv = sons[son]->play(v, pl);
|
int rv = sons[son]->play(v, pl);
|
||||||
|
|
||||||
if(rv == CHANGE) return change(check_win());
|
if(rv == CHANGE) return change(check_win());
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
tile check_win() {
|
tile check_win() {
|
||||||
tile d1 = sons[0]->t, d2 = sons[2]->t;
|
tile d1 = sons[0]->t, d2 = sons[2]->t;
|
||||||
for(int k = 0; k < 3; k++) {
|
for(int k = 0; k < 3; k++) {
|
||||||
tile row = sons[k*3]->t, col = sons[k%3]->t;
|
tile row = sons[k*3]->t, col = sons[k%3]->t;
|
||||||
for(int i = 0; i < 3; i++) {
|
for(int i = 0; i < 3; i++) {
|
||||||
if(sons[k*3 + i]->t != row) row = fr;
|
if(sons[k*3 + i]->t != row) row = fr;
|
||||||
if(sons[k%3 + i*3]->t != col) col = fr;
|
if(sons[k%3 + i*3]->t != col) col = fr;
|
||||||
}
|
}
|
||||||
if(row != fr) return row;
|
if(row != fr) return row;
|
||||||
if(col != fr) return col;
|
if(col != fr) return col;
|
||||||
if(sons[k*4]->t != sons[0]->t) d1 = fr;
|
if(sons[k*4]->t != sons[0]->t) d1 = fr;
|
||||||
if(sons[(k+1)*2]->t != sons[2]->t) d2 = fr;
|
if(sons[(k+1)*2]->t != sons[2]->t) d2 = fr;
|
||||||
}
|
}
|
||||||
if(d1 != fr) return d1;
|
if(d1 != fr) return d1;
|
||||||
if(d2 != fr) return d2;
|
if(d2 != fr) return d2;
|
||||||
|
|
||||||
bool is_tie = true;
|
bool is_tie = true;
|
||||||
for(Block* s : sons)
|
for(Block* s : sons)
|
||||||
if(s->t == fr) is_tie = false;
|
if(s->t == fr) is_tie = false;
|
||||||
if(is_tie) return tie;
|
if(is_tie) return tie;
|
||||||
|
|
||||||
return fr;
|
return fr;
|
||||||
}
|
}
|
||||||
void render(int depth) {
|
void render(int depth) {
|
||||||
if(!leaf) DrawRectangleLinesEx(target, depth, BLACK);
|
if(!leaf) DrawRectangleLinesEx(target, depth, BLACK);
|
||||||
renderImage(t, target);
|
renderImage(t, target);
|
||||||
if(leaf || (t != fr && t != tie)) return;
|
if(leaf || (t != fr && t != tie)) return;
|
||||||
|
|
||||||
for(int i = 0; i < 9; i++)
|
for(int i = 0; i < 9; i++)
|
||||||
sons[i]->render(depth-1);
|
sons[i]->render(depth-1);
|
||||||
}
|
}
|
||||||
Rectangle getRect(deque<int> v) {
|
Rectangle getRect(deque<int> v) {
|
||||||
if(v.size() == 0) return target;
|
if(v.size() == 0) return target;
|
||||||
else {
|
else {
|
||||||
int index = v.front();
|
int index = v.front();
|
||||||
v.pop_front();
|
v.pop_front();
|
||||||
return sons[index]->getRect(v);
|
return sons[index]->getRect(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void updateRect(Rectangle trg) {
|
void updateRect(Rectangle trg) {
|
||||||
target = trg;
|
target = trg;
|
||||||
int x = trg.x, y = trg.y, w = trg.width, h = trg.height;
|
int x = trg.x, y = trg.y, w = trg.width, h = trg.height;
|
||||||
if(leaf) return;
|
if(leaf) return;
|
||||||
for(int i = 0; i < 9; i++)
|
for(int i = 0; i < 9; i++)
|
||||||
sons[i]->updateRect({
|
sons[i]->updateRect({
|
||||||
float(int(x + w/3 * (i%3))),
|
float(int(x + w/3 * (i%3))),
|
||||||
float(int(y + h/3 * (i/3))),
|
float(int(y + h/3 * (i/3))),
|
||||||
float(int(w/3)),
|
float(int(w/3)),
|
||||||
float(int(h/3))
|
float(int(h/3))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void save(vector<tile> *r) {
|
void save(vector<tile> *r) {
|
||||||
if(leaf) r->push_back(t);
|
if(leaf) r->push_back(t);
|
||||||
else
|
else
|
||||||
for(Block* son : sons)
|
for(Block* son : sons)
|
||||||
son->save(r);
|
son->save(r);
|
||||||
}
|
}
|
||||||
void load_state(vector<tile> state, int pos) {
|
void load_state(vector<tile> state, int pos) {
|
||||||
if(leaf) t = state[pos];
|
if(leaf) t = state[pos];
|
||||||
else {
|
else {
|
||||||
for(int i = 0; i < 9; i++)
|
for(int i = 0; i < 9; i++)
|
||||||
sons[i]->load_state(state, pos*9+i);
|
sons[i]->load_state(state, pos*9+i);
|
||||||
t = check_win();
|
t = check_win();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void undo(deque<int> &prev) {
|
void undo(deque<int> &prev) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void save_state(Block* root, int depth, int time, deque<int> &turn) {
|
void save_state(Block* root, int depth, int time, deque<int> &turn) {
|
||||||
vector<tile> state = {};
|
vector<tile> state = {};
|
||||||
root->save(&state);
|
root->save(&state);
|
||||||
string filename; std::cin >> filename;
|
string filename; std::cin >> filename;
|
||||||
std::ofstream outfile("saves/" + filename);
|
std::ofstream outfile("saves/" + filename);
|
||||||
outfile << depth << "\n" << time << "\n" << turn.size() << "\n";
|
outfile << depth << "\n" << time << "\n" << turn.size() << "\n";
|
||||||
for(int play : turn)
|
for(int play : turn)
|
||||||
outfile << play << std::endl;
|
outfile << play << std::endl;
|
||||||
for(tile t : state)
|
for(tile t : state)
|
||||||
outfile << int(t) << std::endl;
|
outfile << int(t) << std::endl;
|
||||||
}
|
}
|
||||||
void load_state(Block** root, deque<int> &turn, int &depth, int &time, char* argv) {
|
void load_state(Block** root, deque<int> &turn, int &depth, int &time, char* argv) {
|
||||||
depth = atoi(argv);
|
depth = atoi(argv);
|
||||||
if(depth)
|
if(depth)
|
||||||
*root = new Block(depth, {0, 0, SCREEN, SCREEN});
|
*root = new Block(depth, {0, 0, SCREEN, SCREEN});
|
||||||
else {
|
else {
|
||||||
string path = "saves/" + string(argv);
|
string path = "saves/" + string(argv);
|
||||||
std::ifstream infile(path);
|
std::ifstream infile(path);
|
||||||
infile >> depth >> time;
|
infile >> depth >> time;
|
||||||
int K; infile >> K;
|
int K; infile >> K;
|
||||||
for(int k = 0; k < K; k++) {
|
for(int k = 0; k < K; k++) {
|
||||||
int play; infile >> play;
|
int play; infile >> play;
|
||||||
turn.push_back(play);
|
turn.push_back(play);
|
||||||
cout << play;
|
cout << play;
|
||||||
}
|
}
|
||||||
vector<tile> state = {};
|
vector<tile> state = {};
|
||||||
long long pw = 1;
|
long long pw = 1;
|
||||||
for(int i = 0; i < depth; i++) pw *= 9;
|
for(int i = 0; i < depth; i++) pw *= 9;
|
||||||
for(int i = 0; i < pw; i++) {
|
for(int i = 0; i < pw; i++) {
|
||||||
int next; infile >> next;
|
int next; infile >> next;
|
||||||
state.push_back((tile)next);
|
state.push_back((tile)next);
|
||||||
}
|
}
|
||||||
*root = new Block(depth, {0, 0, SCREEN, SCREEN});
|
*root = new Block(depth, {0, 0, SCREEN, SCREEN});
|
||||||
(*root)->load_state(state, 0);
|
(*root)->load_state(state, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(int &time, deque<int> &turn, Block* root, Rectangle &dst) {
|
void update(int &time, deque<int> &turn, Block* root, Rectangle &dst) {
|
||||||
time++;
|
time++;
|
||||||
turn.erase(turn.begin());
|
turn.erase(turn.begin());
|
||||||
int rval_2 = root->play(turn, pas(time));
|
int rval_2 = root->play(turn, pas(time));
|
||||||
for(int i = 0; i <= rval_2; i++)
|
for(int i = 0; i <= rval_2; i++)
|
||||||
turn.pop_back();
|
turn.pop_back();
|
||||||
dst = root->getRect(turn);
|
dst = root->getRect(turn);
|
||||||
}
|
}
|
||||||
void undo(Block *root, deque<int> &prev, Rectangle &dst, int &time) {
|
void undo(Block *root, deque<int> &prev, Rectangle &dst, int &time) {
|
||||||
if(prev.size() == 0) return;
|
if(prev.size() == 0) return;
|
||||||
time--;
|
time--;
|
||||||
root->undo(prev);
|
root->undo(prev);
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
bool valid(Block* root, Rectangle &dst, deque<int> &turn) {
|
bool valid(Block* root, Rectangle &dst, deque<int> &turn) {
|
||||||
return CheckCollisionRecs(root->getRect(turn), dst) && root->playable(turn);
|
return CheckCollisionRecs(root->getRect(turn), dst) && root->playable(turn);
|
||||||
}
|
}
|
||||||
void render_all(Block* root, int time, Rectangle dst, int depth, deque<int> highlight = {}) {
|
void render_all(Block* root, int time, Rectangle dst, int depth, deque<int> highlight = {}) {
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
root->render(depth);
|
root->render(depth);
|
||||||
if(valid(root, dst, highlight))
|
if(valid(root, dst, highlight))
|
||||||
renderImage(act(time), root->getRect(highlight), BLACK);
|
renderImage(act(time), root->getRect(highlight), BLACK);
|
||||||
DrawRectangleLinesEx(dst, 3*LINE_W, act(time+1) == p2 ? BLUE : RED);
|
DrawRectangleLinesEx(dst, 3*LINE_W, act(time+1) == p2 ? BLUE : RED);
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
void prepareScreen(Block* root, int time, Rectangle dst, int depth) {
|
void prepareScreen(Block* root, int time, Rectangle dst, int depth) {
|
||||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
||||||
InitWindow(SCREEN, SCREEN, "Rekurze");
|
InitWindow(SCREEN, SCREEN, "Rekurze");
|
||||||
SetTargetFPS(FPS);
|
SetTargetFPS(FPS);
|
||||||
prepareTextures();
|
prepareTextures();
|
||||||
render_all(root, time, dst, depth);
|
render_all(root, time, dst, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
deque<int> turn = {};
|
deque<int> turn = {};
|
||||||
int time = 0, depth;
|
int time = 0, depth;
|
||||||
Block* root = nullptr;
|
Block* root = nullptr;
|
||||||
|
|
||||||
int screenSize = SCREEN;
|
int screenSize = SCREEN;
|
||||||
|
|
||||||
if(argc <= 1) {
|
if(argc <= 1) {
|
||||||
cin >> depth;
|
cin >> depth;
|
||||||
root = new Block(depth, {0, 0, SCREEN, SCREEN});
|
root = new Block(depth, {0, 0, SCREEN, SCREEN});
|
||||||
}
|
}
|
||||||
else load_state(&root, turn, depth, time, argv[1]);
|
else load_state(&root, turn, depth, time, argv[1]);
|
||||||
|
|
||||||
Rectangle dst = root->getRect(turn);
|
Rectangle dst = root->getRect(turn);
|
||||||
|
|
||||||
prepareScreen(root, time, dst, depth);
|
prepareScreen(root, time, dst, depth);
|
||||||
|
|
||||||
|
|
||||||
bool end = false;
|
bool end = false;
|
||||||
deque<int> pturn = {};
|
deque<int> pturn = {};
|
||||||
while(!WindowShouldClose()) {
|
while(!WindowShouldClose()) {
|
||||||
// Update screen size
|
// Update screen size
|
||||||
screenSize = min(GetScreenWidth(), GetScreenHeight());
|
screenSize = min(GetScreenWidth(), GetScreenHeight());
|
||||||
root->updateRect({0, 0, (float)screenSize, (float)screenSize});
|
root->updateRect({0, 0, (float)screenSize, (float)screenSize});
|
||||||
dst = root->getRect(pturn);
|
dst = root->getRect(pturn);
|
||||||
|
|
||||||
// Move
|
// Move
|
||||||
Vector2 touch = GetMousePosition();
|
Vector2 touch = GetMousePosition();
|
||||||
turn = pos(touch).to_deque(depth, screenSize);
|
turn = pos(touch).to_deque(depth, screenSize);
|
||||||
if(IsMouseButtonPressed(0) && CheckCollisionPointRec(touch, dst) && valid(root, dst, turn)) {
|
if(IsMouseButtonPressed(0) && CheckCollisionPointRec(touch, dst) && valid(root, dst, turn)) {
|
||||||
int rval = root->play(turn, act(time));
|
int rval = root->play(turn, act(time));
|
||||||
if(rval == CHANGE) end = true;
|
if(rval == CHANGE) end = true;
|
||||||
else if(rval == OKAY) {
|
else if(rval == OKAY) {
|
||||||
update(time, turn, root, dst);
|
update(time, turn, root, dst);
|
||||||
pturn = turn;
|
pturn = turn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key presses
|
// Key presses
|
||||||
if(IsKeyPressed(KEY_X)) save_state(root, depth, time, turn), end = true;
|
if(IsKeyPressed(KEY_X)) save_state(root, depth, time, turn), end = true;
|
||||||
else if(IsKeyPressed(KEY_Z)); //TODO undo
|
else if(IsKeyPressed(KEY_Z)); //TODO undo
|
||||||
else if(IsKeyPressed(KEY_P)) TakeScreenshot("screenshot.png");
|
else if(IsKeyPressed(KEY_P)) TakeScreenshot("screenshot.png");
|
||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
render_all(root, time, dst, depth, turn);
|
render_all(root, time, dst, depth, turn);
|
||||||
|
|
||||||
if(end) break;
|
if(end) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTime(10);
|
WaitTime(10);
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue