|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
#include "puzzle.h"
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
void puzzleAlloc(Puzzle *pz, int rows, int cols) {
|
|
Ivan Mahonin |
fdbd7d |
pz->rows = rows < 1 ? 1 : rows;
|
|
Ivan Mahonin |
fdbd7d |
pz->cols = cols < 1 ? 1 : cols;
|
|
Ivan Mahonin |
fdbd7d |
pz->cs = vone();
|
|
Ivan Mahonin |
fdbd7d |
pz->hlines = (Vertex**)alloc2d(pz->rows+1, (pz->cols*LN_SEGS+1)*ASIZEOF(**pz->hlines));
|
|
Ivan Mahonin |
fdbd7d |
pz->vlines = (Vertex**)alloc2d(pz->cols+1, (pz->rows*LN_SEGS+1)*ASIZEOF(**pz->vlines));
|
|
Ivan Mahonin |
fdbd7d |
pz->chunks = (Chunk**)alloc2d(pz->rows, pz->cols*ASIZEOF(**pz->chunks));
|
|
Ivan Mahonin |
fdbd7d |
pz->chunksOrder = (Chunk**)alloc(pz->rows*pz->cols*ASIZEOF(*pz->chunksOrder));
|
|
Ivan Mahonin |
fdbd7d |
physicsAlloc(&pz->ph, pz->rows*2, pz->cols*2, 1);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
void puzzleFree(Puzzle *pz) {
|
|
Ivan Mahonin |
fdbd7d |
free(pz->chunksOrder);
|
|
Ivan Mahonin |
fdbd7d |
free(pz->chunks);
|
|
Ivan Mahonin |
fdbd7d |
physicsFree(&pz->ph);
|
|
Ivan Mahonin |
fdbd7d |
tileFree(&pz->tm);
|
|
Ivan Mahonin |
fdbd7d |
free(pz->hlines);
|
|
Ivan Mahonin |
fdbd7d |
free(pz->vlines);
|
|
Ivan Mahonin |
fdbd7d |
memset(pz, 0, sizeof(*pz));
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
void puzzleClearImages(Puzzle *pz) {
|
|
Ivan Mahonin |
fdbd7d |
for(int r = 0; r < pz->rows; ++r)
|
|
Ivan Mahonin |
fdbd7d |
for(int c = 0; c < pz->cols; ++c)
|
|
Ivan Mahonin |
fdbd7d |
pz->chunks[r][c].t = (Tile){};
|
|
Ivan Mahonin |
fdbd7d |
tileClear(&pz->tm);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
void puzzleGenLines(Puzzle *pz, double cellw, double cellh, double jitter, double depth) {
|
|
Ivan Mahonin |
fdbd7d |
puzzleClearImages(pz);
|
|
Ivan Mahonin |
fdbd7d |
pz->cs.x = maxd(PRECISION, cellw);
|
|
Ivan Mahonin |
fdbd7d |
pz->cs.y = maxd(PRECISION, cellh);
|
|
Ivan Mahonin |
fdbd7d |
for(int r = 0; r <= pz->rows; ++r) {
|
|
Ivan Mahonin |
fdbd7d |
double j = r && r < pz->rows ? jitter : 0.0;
|
|
Ivan Mahonin |
fdbd7d |
double d = r && r < pz->rows ? depth : 0.0;
|
|
Ivan Mahonin |
fdbd7d |
lineGenH(pz->hlines[r], pz->cols, r*pz->cs.y, pz->cs.x, pz->cs.y, j, d);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
for(int c = 0; c <= pz->cols; ++c) {
|
|
Ivan Mahonin |
fdbd7d |
double j = c && c < pz->cols ? jitter : 0.0;
|
|
Ivan Mahonin |
fdbd7d |
double d = c && c < pz->cols ? depth : 0.0;
|
|
Ivan Mahonin |
fdbd7d |
lineGenV(pz->vlines[c], pz->rows, c*pz->cs.x, pz->cs.x, pz->cs.y, j, d);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
for(int r = 1; r < pz->rows; ++r)
|
|
Ivan Mahonin |
fdbd7d |
for(int c = 1; c < pz->cols; ++c)
|
|
Ivan Mahonin |
fdbd7d |
pz->vlines[c][r*LN_SEGS].p = pz->hlines[r][c*LN_SEGS].p;
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
void puzzleRecalcGroups(Puzzle *pz) {
|
|
Ivan Mahonin |
fdbd7d |
pz->groups = 0;
|
|
Ivan Mahonin |
fdbd7d |
for(PhGroup *g = pz->ph.first; g; g = g->next) ++pz->groups;
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
void puzzleGenChunks(Puzzle *pz) {
|
|
Ivan Mahonin |
fdbd7d |
pz->ph.fixangle = 1;
|
|
Ivan Mahonin |
fdbd7d |
double nr = mind(pz->cs.x, pz->cs.y)/4;
|
|
Ivan Mahonin |
fdbd7d |
Vec nd = { pz->cs.x/2 - nr, pz->cs.y/2 - nr };
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
Vec s = vmul( vmulv(vec(pz->cols, pz->rows), pz->cs), 1.5/2 );
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
physicsClear(&pz->ph);
|
|
Ivan Mahonin |
fdbd7d |
pz->ph.cs = maxd(pz->cs.x, pz->cs.y);
|
|
Ivan Mahonin |
fdbd7d |
Vec nds[] = { vneg(nd), vnegy(nd), vnegx(nd), nd, vzero() };
|
|
Ivan Mahonin |
fdbd7d |
double nrs[] = { nr, nr, nr, nr, 2*nr };
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
for(int r = 0; r < pz->rows; ++r)
|
|
Ivan Mahonin |
fdbd7d |
for(int c = 0; c < pz->cols; ++c) {
|
|
Ivan Mahonin |
fdbd7d |
Chunk *a = &pz->chunks[r][c];
|
|
Ivan Mahonin |
fdbd7d |
*a = (Chunk){ pz, r, c };
|
|
Ivan Mahonin |
fdbd7d |
a->parent = &a->group;
|
|
Ivan Mahonin |
fdbd7d |
a->flags |= PF_HANDLES;
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
Vec o = vmulv(s, vrandTwo());
|
|
Ivan Mahonin |
fdbd7d |
Vec go = chunkGroupPos(a);
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
for(int i = 0; i < 5; ++i) {
|
|
Ivan Mahonin |
fdbd7d |
PhNode *n = &a->nodes[i];
|
|
Ivan Mahonin |
fdbd7d |
n->gp = vadd(go, nds[i]);
|
|
Ivan Mahonin |
fdbd7d |
n->r = nrs[i];
|
|
Ivan Mahonin |
fdbd7d |
n->p = vadd(o, vrandTwo());
|
|
Ivan Mahonin |
fdbd7d |
phNodeReg(n, a->parent);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
phGroupReg(a->parent, &pz->ph);
|
|
Ivan Mahonin |
fdbd7d |
phGroupRecalc(a->parent);
|
|
Ivan Mahonin |
fdbd7d |
phGroupFix(a->parent, !pz->turn);
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
pz->chunksOrder[r*pz->cols + c] = a;
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
int cnt = pz->rows*pz->cols;
|
|
Ivan Mahonin |
fdbd7d |
for(int i = 0; i < cnt; ++i) {
|
|
Ivan Mahonin |
fdbd7d |
int j = rand()%(cnt-i) + i;
|
|
Ivan Mahonin |
fdbd7d |
Chunk *c = pz->chunksOrder[j];
|
|
Ivan Mahonin |
fdbd7d |
pz->chunksOrder[j] = pz->chunksOrder[i];
|
|
Ivan Mahonin |
fdbd7d |
pz->chunksOrder[i] = c;
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
puzzleRecalcGroups(pz);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
void puzzleRenderChunks(Puzzle *pz, int size, double m) {
|
|
Ivan Mahonin |
fdbd7d |
puzzleClearImages(pz);
|
|
Ivan Mahonin |
fdbd7d |
int cnt = pz->rows*pz->cols;
|
|
Ivan Mahonin |
fdbd7d |
double s = maxd(pz->cs.x, pz->cs.y) + 2*m;
|
|
Ivan Mahonin |
fdbd7d |
for(int i = 0; i < cnt; ++i) {
|
|
Ivan Mahonin |
fdbd7d |
Chunk *c = &pz->chunks[0][i];
|
|
Ivan Mahonin |
fdbd7d |
c->t = tileAdd(&pz->tm, size, s);
|
|
Ivan Mahonin |
fdbd7d |
chunkRender(c);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
int puzzleChooseChunks(Puzzle *pz, Vec mouse) {
|
|
Ivan Mahonin |
fdbd7d |
pz->activeChunks = 0;
|
|
Ivan Mahonin |
fdbd7d |
Chunk *choosen = NULL;
|
|
Ivan Mahonin |
fdbd7d |
Chunk *choosenE = NULL;
|
|
Ivan Mahonin |
fdbd7d |
int cnt = pz->rows*pz->cols;
|
|
Ivan Mahonin |
fdbd7d |
for(int i = cnt-1; i >= 0; --i) {
|
|
Ivan Mahonin |
fdbd7d |
Chunk *c = pz->chunksOrder[i];
|
|
Ivan Mahonin |
fdbd7d |
Flags f = chunkCheckPoint(c, mouse);
|
|
Ivan Mahonin |
fdbd7d |
if (f&PCP_BODY) { choosen = c; pz->mousefix = !pz->turn || !(f&PCP_EDGE); }
|
|
Ivan Mahonin |
fdbd7d |
if (f&PCP_EDGE) choosenE = c;
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
if (!choosen) { choosen = choosenE; pz->mousefix = !pz->turn; }
|
|
Ivan Mahonin |
fdbd7d |
if (!choosen) return 0;
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
pz->gmouse = phGroupUntrans(choosen->parent, mouse);
|
|
Ivan Mahonin |
fdbd7d |
for(int i = 0; i < cnt; ++i) {
|
|
Ivan Mahonin |
fdbd7d |
Chunk *c = pz->chunksOrder[i];
|
|
Ivan Mahonin |
fdbd7d |
if (c->parent != choosen->parent) continue;
|
|
Ivan Mahonin |
fdbd7d |
memmove(pz->chunksOrder + pz->activeChunks + 1, pz->chunksOrder + pz->activeChunks, (i - pz->activeChunks)*sizeof(*pz->chunksOrder));
|
|
Ivan Mahonin |
fdbd7d |
pz->chunksOrder[pz->activeChunks++] = c;
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
return pz->activeChunks;
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
void puzzleReleaseChunks(Puzzle *pz) {
|
|
Ivan Mahonin |
fdbd7d |
if (!pz->activeChunks) return;
|
|
Ivan Mahonin |
fdbd7d |
while(pz->activeChunks > 0) {
|
|
Ivan Mahonin |
fdbd7d |
Chunk *c = pz->chunksOrder[--pz->activeChunks];
|
|
Ivan Mahonin |
fdbd7d |
chunkTryMerge(c, -1, 0);
|
|
Ivan Mahonin |
fdbd7d |
chunkTryMerge(c, 1, 0);
|
|
Ivan Mahonin |
fdbd7d |
chunkTryMerge(c, 0, -1);
|
|
Ivan Mahonin |
fdbd7d |
chunkTryMerge(c, 0, 1);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
puzzleRecalcGroups(pz);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
void puzzleUpdate(Puzzle *pz, Vec hs, Vec mouse) {
|
|
Ivan Mahonin |
fdbd7d |
Vec mmin = vdiv(pz->cs, 2);
|
|
Ivan Mahonin |
fdbd7d |
Vec bmax = vmulv(vec(pz->ph.hw, pz->ph.hh), pz->cs);
|
|
Ivan Mahonin |
fdbd7d |
Vec b1 = vec( maxd(mmin.x, mind(hs.x, bmax.x)),
|
|
Ivan Mahonin |
fdbd7d |
maxd(mmin.y, mind(hs.y, bmax.y)) );
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
if ( (b1.x != pz->ph.b1.x || b1.y != pz->ph.b1.y)
|
|
Ivan Mahonin |
fdbd7d |
&& b1.x > PRECISION && pz->ph.b1.x > PRECISION
|
|
Ivan Mahonin |
fdbd7d |
&& b1.y > PRECISION && pz->ph.b1.y > PRECISION )
|
|
Ivan Mahonin |
fdbd7d |
{
|
|
Ivan Mahonin |
fdbd7d |
Vec k = vdivv(b1, pz->ph.b1);
|
|
Ivan Mahonin |
fdbd7d |
for(PhGroup *g = pz->ph.first; g; g = g->next) {
|
|
Ivan Mahonin |
fdbd7d |
g->o = vmulv(g->o, k);
|
|
Ivan Mahonin |
fdbd7d |
phGroupPlaceNodes(g);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
pz->ph.b1 = b1;
|
|
Ivan Mahonin |
fdbd7d |
pz->ph.b0 = vneg(b1);
|
|
Ivan Mahonin |
fdbd7d |
|
|
Ivan Mahonin |
fdbd7d |
physicsUpdate(&pz->ph);
|
|
Ivan Mahonin |
fdbd7d |
if (pz->activeChunks)
|
|
Ivan Mahonin |
fdbd7d |
phGroupMove(pz->chunksOrder[0]->parent, pz->gmouse, mouse, pz->mousefix);
|
|
Ivan Mahonin |
fdbd7d |
}
|
|
Ivan Mahonin |
fdbd7d |
|