diff --git a/recursive.cpp b/recursive.cpp index a68dcb5..937efc3 100644 --- a/recursive.cpp +++ b/recursive.cpp @@ -10,19 +10,20 @@ using std::deque; using std::string; using std::array; using std::vector; -using std::min; + using std::cin; using std::cout; -enum tile {fr = 0, p1 = 1, p2 = 2, tie = 3}; +enum tile {empty = 0, p1 = 1, p2 = 2, tie = 3}; tile act(int t) { return (t % 2) ? p2 : p1; } tile pas(int t) { return (t % 2) ? p1 : p2; } -#define point(pos) {(float)pos.x, (float)pos.y} +Color col(int t) { return act(t) == p2 ? BLUE : RED; } #define FPS 15 #define SCREEN 800 #define LINE_W 2 +// Images #define IMG_COUNT 2 array textures; void prepareTextures() { @@ -34,7 +35,8 @@ void prepareTextures() { } } void renderImage(tile t, Rectangle dst, Color color = WHITE) { - if(t == fr || t == tie) return; + if(t == empty || t == tie) + return; Texture tex = textures[t-1]; Rectangle src = {0, 0, (float)tex.width, (float)tex.height}; DrawTexturePro(textures[t-1], src, dst, {0,0}, 0, color); @@ -49,105 +51,145 @@ struct pos { pos operator/(int a) {return {x/a, y/a};}; pos operator%(int a) {return {x%a, y%a};}; - pos normalize() { - if(x >= 3) x = 2; - else if(x < 0) x = 0; - if(y >= 3) y = 2; - else if(y < 0) y = 0; - return *this; - } int to_int() { return 3*y + x; } deque to_deque(int depth, int screenSize) { deque r = {}; pos pp = pos(x,y); - int pwr = 1; - for(int i = 1; i <= depth; i++) { - pwr *= 3; - pos ppos = (pp/(screenSize/pwr)); - if(ppos.x > 2 || ppos.y > 2) return {}; + if(pp.x > screenSize || pp.y > screenSize) + return {}; + + for(int i = 0; i < depth; ++i) { + screenSize /= 3; + pos ppos = pp/screenSize; r.push_back(ppos.to_int()); - pp = pp%(screenSize/pwr); + pp = pp%screenSize; } return r; } }; +deque to_deque(Vector2 v, int depth, int size) { + deque r = {}; + int x = v.x, y = v.y; + + if(x >= size || y >= size || x < 0 || y < 0) + return {}; + + for(int i = 0; i < depth; ++i) { + size /= 3; + r.push_back(3*(y/size) + x/size); + x %= size; + y %= size; + } + return r; +} + #define OKAY -1 #define CHANGE -2 -struct Block { - tile t = fr; - bool leaf = false; - Rectangle target; +class Block { + tile t = empty; + Rectangle place; + int depth; array sons; +public: Block() {} - Block(int depth, Rectangle trg) { - target = trg; + Block(int _depth, Rectangle trg) { + place = trg; int x = trg.x, y = trg.y, w = trg.width, h = trg.height; - if(depth == 0) leaf = true; - else + depth = _depth; + if(depth > 0) for(int i = 0; i < 9; i++) - 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))}); + sons[i] = new Block( depth-1, get_son_rectangle(i) ); + } + Rectangle get_son_rectangle(int son) { + return { + float(int(place.x + place.width/3 * (son%3))), + float(int(place.y + place.height/3 * int(son/3))), + float(int(place.width/3)), + float(int(place.height/3)) + }; } int change(tile pl) { t = pl; - if(pl == fr) + if(pl == empty) return OKAY; return CHANGE; } bool playable(deque v) { - if(leaf && t == fr) return true; - if(t != fr || v.size() == 0) return false; + if(depth == 0 && t == empty) + return true; + if(t != empty || v.size() == 0) + return false; int son = v.front(); v.pop_front(); return sons[son]->playable(v); } int play(deque v, tile pl) { - if(t != fr) return v.size(); - if(leaf) return change(pl); - if(v.size() == 0) return OKAY; + if(t != empty) + return v.size(); + if(depth == 0) + return change(pl); + if(v.size() == 0) + return OKAY; int son = v.front(); v.erase(v.begin()); int rv = sons[son]->play(v, pl); - if(rv == CHANGE) return change(check_win()); + if(rv == CHANGE) + return change(check_win()); return rv; } + bool check_tie() { + bool is_tie = true; + for(Block* s : sons) + if(s->t == empty) + is_tie = false; + return is_tie; + } tile check_win() { tile d1 = sons[0]->t, d2 = sons[2]->t; for(int k = 0; k < 3; k++) { tile row = sons[k*3]->t, col = sons[k%3]->t; for(int i = 0; i < 3; i++) { - if(sons[k*3 + i]->t != row) row = fr; - if(sons[k%3 + i*3]->t != col) col = fr; + if(sons[k*3 + i]->t != row) + row = empty; + if(sons[k%3 + i*3]->t != col) + col = empty; } - if(row != fr) return row; - if(col != fr) return col; - if(sons[k*4]->t != sons[0]->t) d1 = fr; - if(sons[(k+1)*2]->t != sons[2]->t) d2 = fr; + if(row != empty) + return row; + if(col != empty) + return col; + if(sons[k*4]->t != sons[0]->t) + d1 = empty; + if(sons[(k+1)*2]->t != sons[2]->t) + d2 = empty; } - if(d1 != fr) return d1; - if(d2 != fr) return d2; + if(d1 != empty) + return d1; + if(d2 != empty) + return d2; - bool is_tie = true; - for(Block* s : sons) - if(s->t == fr) is_tie = false; - if(is_tie) return tie; + if(check_tie()) + return tie; - return fr; + return empty; } - void render(int depth) { - if(!leaf) DrawRectangleLinesEx(target, depth, BLACK); - renderImage(t, target); - if(leaf || (t != fr && t != tie)) return; + void render() { + if(depth > 0) + DrawRectangleLinesEx(place, depth, BLACK); + renderImage(t, place); + if(depth == 0 || (t != empty && t != tie)) + return; for(int i = 0; i < 9; i++) - sons[i]->render(depth-1); + sons[i]->render(); } Rectangle getRect(deque v) { - if(v.size() == 0) return target; + if(v.size() == 0) + return place; else { int index = v.front(); v.pop_front(); @@ -155,26 +197,25 @@ struct Block { } } void updateRect(Rectangle trg) { - target = trg; - int x = trg.x, y = trg.y, w = trg.width, h = trg.height; - if(leaf) return; + place = trg; + int x = trg.x, y = trg.y, + w = trg.width, h = trg.height; + if(depth == 0) + return; for(int i = 0; i < 9; i++) - sons[i]->updateRect({ - float(int(x + w/3 * (i%3))), - float(int(y + h/3 * (i/3))), - float(int(w/3)), - float(int(h/3)) - }); + sons[i]->updateRect(get_son_rectangle(i)); } void save(vector *r) { - if(leaf) r->push_back(t); - else + if(depth == 0) + r->push_back(t); + else // TODO save? for(Block* son : sons) son->save(r); } void load_state(vector state, int pos) { - if(leaf) t = state[pos]; + if(depth == 0) + t = state[pos]; else { for(int i = 0; i < 9; i++) sons[i]->load_state(state, pos*9+i); @@ -182,18 +223,22 @@ struct Block { } } void undo(deque &prev) { - // TODO + // TODall: $(PAGES) ...O } }; void save_state(Block* root, int depth, int time, deque &turn) { vector state = {}; root->save(&state); + string filename; std::cin >> filename; std::ofstream outfile("saves/" + filename); + outfile << depth << "\n" << time << "\n" << turn.size() << "\n"; + for(int play : turn) outfile << play << std::endl; + for(tile t : state) outfile << int(t) << std::endl; } @@ -240,13 +285,15 @@ void undo(Block *root, deque &prev, Rectangle &dst, int &time) { bool valid(Block* root, Rectangle &dst, deque &turn) { return CheckCollisionRecs(root->getRect(turn), dst) && root->playable(turn); } -void render_all(Block* root, int time, Rectangle dst, int depth, deque highlight = {}) { +void render_all(Block* root, int time, Rectangle dst, deque highlight = {}) { BeginDrawing(); ClearBackground(RAYWHITE); - root->render(depth); + + root->render(); if(valid(root, dst, highlight)) renderImage(act(time), root->getRect(highlight), BLACK); - DrawRectangleLinesEx(dst, 3*LINE_W, act(time+1) == p2 ? BLUE : RED); + DrawRectangleLinesEx(dst, 3*LINE_W, col(time+1)); + EndDrawing(); } void prepareScreen(Block* root, int time, Rectangle dst, int depth) { @@ -254,7 +301,7 @@ void prepareScreen(Block* root, int time, Rectangle dst, int depth) { InitWindow(SCREEN, SCREEN, "Rekurze"); SetTargetFPS(FPS); prepareTextures(); - render_all(root, time, dst, depth); + render_all(root, time, dst); } @@ -267,44 +314,55 @@ int main(int argc, char** argv) { if(argc <= 1) { cin >> depth; - root = new Block(depth, {0, 0, SCREEN, SCREEN}); + root = new Block(depth, {0, 0, (float)screenSize, (float)screenSize}); } - else load_state(&root, turn, depth, time, argv[1]); + else + load_state(&root, turn, depth, time, argv[1]); Rectangle dst = root->getRect(turn); prepareScreen(root, time, dst, depth); - bool end = false; deque pturn = {}; while(!WindowShouldClose()) { // Update screen size - screenSize = min(GetScreenWidth(), GetScreenHeight()); - root->updateRect({0, 0, (float)screenSize, (float)screenSize}); + screenSize = std::min(GetScreenWidth(), GetScreenHeight()); + int size = 1; + while(size <= screenSize) + size *= 3; + screenSize = size/3; + float start_x = ((float)GetScreenWidth()-screenSize)/2; + float start_y = ((float)GetScreenHeight()-screenSize)/2; + + root->updateRect({start_x, start_y, (float)screenSize, (float)screenSize}); dst = root->getRect(pturn); // Move Vector2 touch = GetMousePosition(); - turn = pos(touch).to_deque(depth, screenSize); + turn = to_deque({touch.x - start_x, touch.y - start_y}, depth, screenSize); if(IsMouseButtonPressed(0) && CheckCollisionPointRec(touch, dst) && valid(root, dst, turn)) { - int rval = root->play(turn, act(time)); - if(rval == CHANGE) end = true; - else if(rval == OKAY) { - update(time, turn, root, dst); - pturn = turn; + switch(root->play(turn, act(time))) { + case CHANGE: + end = true; + break; + case OKAY: + update(time, turn, root, dst); + pturn = turn; + break; } } // Key presses - if(IsKeyPressed(KEY_X)) save_state(root, depth, time, turn), end = true; - else if(IsKeyPressed(KEY_Z)); //TODO undo - else if(IsKeyPressed(KEY_P)) TakeScreenshot("screenshot.png"); + if(IsKeyPressed(KEY_X)) + save_state(root, depth, time, turn), end = true; + else if(IsKeyPressed(KEY_Z)) {} //TODO undo // Rendering - render_all(root, time, dst, depth, turn); + render_all(root, time, dst, turn); - if(end) break; + if(end) + break; } WaitTime(10);