2019-11-28 20:20:10 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "demo.h"
|
|
|
|
|
|
|
|
// FIXME do the bigger dimension on the screen's bigger dimension
|
2019-11-29 03:08:26 +00:00
|
|
|
#define CHUNKS_VERT 6
|
|
|
|
#define CHUNKS_HORZ 12
|
2019-12-04 15:00:23 +00:00
|
|
|
#define MOVES 20
|
2019-11-29 03:08:26 +00:00
|
|
|
|
2019-12-02 07:05:42 +00:00
|
|
|
static int
|
2019-12-03 23:40:41 +00:00
|
|
|
move_square(struct notcurses* nc, struct ncplane* chunk, int* holey, int* holex,
|
|
|
|
uint64_t movens){
|
2019-12-02 07:05:42 +00:00
|
|
|
int newholex, newholey;
|
|
|
|
ncplane_yx(chunk, &newholey, &newholex);
|
2019-12-02 07:18:05 +00:00
|
|
|
// we need to move from newhole to hole over the course of movetime
|
|
|
|
int deltay, deltax;
|
|
|
|
deltay = *holey - newholey;
|
|
|
|
deltax = *holex - newholex;
|
|
|
|
// divide movetime into abs(max(deltay, deltax)) units, and move delta
|
|
|
|
int units = abs(deltay) > abs(deltax) ? abs(deltay) : abs(deltax);
|
|
|
|
movens /= units;
|
2019-12-25 07:23:18 +00:00
|
|
|
struct timespec movetime;
|
|
|
|
ns_to_timespec(movens, &movetime);
|
2019-12-02 07:18:05 +00:00
|
|
|
int i;
|
|
|
|
int targy = newholey;
|
|
|
|
int targx = newholex;
|
|
|
|
deltay = deltay < 0 ? -1 : deltay == 0 ? 0 : 1;
|
|
|
|
deltax = deltax < 0 ? -1 : deltax == 0 ? 0 : 1;
|
2019-12-02 11:18:17 +00:00
|
|
|
// FIXME do an adaptive time, like our fades, so we whip along under load
|
2019-12-02 07:18:05 +00:00
|
|
|
for(i = 0 ; i < units ; ++i){
|
|
|
|
targy += deltay;
|
|
|
|
targx += deltax;
|
|
|
|
ncplane_move_yx(chunk, targy, targx);
|
2020-02-12 03:22:37 +00:00
|
|
|
DEMO_RENDER(nc);
|
2020-04-18 21:55:49 +00:00
|
|
|
demo_nanosleep(nc, &movetime);
|
2019-12-02 07:18:05 +00:00
|
|
|
}
|
2019-12-02 07:05:42 +00:00
|
|
|
*holey = newholey;
|
|
|
|
*holex = newholex;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-25 07:23:18 +00:00
|
|
|
// we take demodelay * 5 to play MOVES moves
|
2019-11-29 03:08:26 +00:00
|
|
|
static int
|
2021-11-28 10:07:15 +00:00
|
|
|
play(struct notcurses* nc, struct ncplane** chunks, uint64_t startns){
|
2019-12-25 07:23:18 +00:00
|
|
|
const uint64_t delayns = timespec_to_ns(&demodelay);
|
2019-11-29 03:08:26 +00:00
|
|
|
const int chunkcount = CHUNKS_VERT * CHUNKS_HORZ;
|
2019-12-03 23:40:41 +00:00
|
|
|
// we don't want to spend more than demodelay * 5
|
|
|
|
const uint64_t totalns = delayns * 5;
|
2021-11-28 10:07:15 +00:00
|
|
|
const uint64_t deadline_ns = startns + totalns;
|
2019-12-03 23:40:41 +00:00
|
|
|
const uint64_t movens = totalns / MOVES;
|
2021-07-24 19:18:02 +00:00
|
|
|
int hole = rand() % chunkcount;
|
2019-11-29 03:08:26 +00:00
|
|
|
int holex, holey;
|
|
|
|
ncplane_yx(chunks[hole], &holey, &holex);
|
|
|
|
ncplane_destroy(chunks[hole]);
|
|
|
|
chunks[hole] = NULL;
|
|
|
|
int m;
|
|
|
|
int lastdir = -1;
|
|
|
|
for(m = 0 ; m < MOVES ; ++m){
|
2021-11-28 10:07:15 +00:00
|
|
|
uint64_t now = clock_getns(CLOCK_MONOTONIC);
|
2019-12-03 23:40:41 +00:00
|
|
|
if(now >= deadline_ns){
|
|
|
|
break;
|
|
|
|
}
|
2019-11-29 03:08:26 +00:00
|
|
|
int mover = chunkcount;
|
|
|
|
int direction;
|
|
|
|
do{
|
2021-07-24 19:18:02 +00:00
|
|
|
direction = rand() % 4;
|
2019-11-29 03:08:26 +00:00
|
|
|
switch(direction){
|
|
|
|
case 3: // up
|
|
|
|
if(lastdir != 1 && hole >= CHUNKS_HORZ){ mover = hole - CHUNKS_HORZ; } break;
|
|
|
|
case 2: // right
|
|
|
|
if(lastdir != 0 && hole % CHUNKS_HORZ < CHUNKS_HORZ - 1){ mover = hole + 1; } break;
|
|
|
|
case 1: // down
|
|
|
|
if(lastdir != 3 && hole < chunkcount - CHUNKS_HORZ){ mover = hole + CHUNKS_HORZ; } break;
|
|
|
|
case 0: // left
|
|
|
|
if(lastdir != 2 && hole % CHUNKS_HORZ){ mover = hole - 1; } break;
|
|
|
|
}
|
|
|
|
}while(mover == chunkcount);
|
|
|
|
lastdir = direction;
|
2020-02-12 03:22:37 +00:00
|
|
|
int err = move_square(nc, chunks[mover], &holey, &holex, movens);
|
|
|
|
if(err){
|
|
|
|
return err;
|
|
|
|
}
|
2019-11-29 03:08:26 +00:00
|
|
|
chunks[hole] = chunks[mover];
|
|
|
|
chunks[mover] = NULL;
|
|
|
|
hole = mover;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2019-11-28 20:20:10 +00:00
|
|
|
|
2019-11-28 20:41:51 +00:00
|
|
|
static int
|
|
|
|
fill_chunk(struct ncplane* n, int idx){
|
2019-12-04 15:00:23 +00:00
|
|
|
const int hidx = idx % CHUNKS_HORZ;
|
|
|
|
const int vidx = idx / CHUNKS_HORZ;
|
2021-11-07 02:32:20 +00:00
|
|
|
unsigned maxy, maxx;
|
2019-11-29 03:08:26 +00:00
|
|
|
ncplane_dim_yx(n, &maxy, &maxx);
|
2019-12-03 23:40:41 +00:00
|
|
|
uint64_t channels = 0;
|
2019-12-04 15:00:23 +00:00
|
|
|
int r = 64 + hidx * 10;
|
|
|
|
int b = 64 + vidx * 30;
|
|
|
|
int g = 225 - ((hidx + vidx) * 12);
|
2021-04-29 05:18:37 +00:00
|
|
|
ncchannels_set_fg_rgb8(&channels, r, g, b);
|
2020-03-08 08:05:55 +00:00
|
|
|
uint32_t ul = 0, ur = 0, ll = 0, lr = 0;
|
2021-04-27 18:10:41 +00:00
|
|
|
ncchannel_set_rgb8(&ul, r, g, b);
|
|
|
|
ncchannel_set_rgb8(&lr, r, g, b);
|
|
|
|
ncchannel_set_rgb8(&ur, g, b, r);
|
|
|
|
ncchannel_set_rgb8(&ll, b, r, g);
|
2020-02-23 10:04:59 +00:00
|
|
|
int ret = 0;
|
2021-12-02 06:45:49 +00:00
|
|
|
if(notcurses_canutf8(ncplane_notcurses(n))){
|
|
|
|
if(ncplane_gradient2x1(n, -1, -1, 0, 0, ul, ur, ll, lr) <= 0){
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
ret |= ncplane_double_box(n, 0, channels, maxy - 1, maxx - 1, 0);
|
|
|
|
}else{
|
|
|
|
if(ncplane_gradient(n, -1, -1, 0, 0, " ", NCSTYLE_NONE, ul, ur, ll, lr) <= 0){
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
ret |= ncplane_ascii_box(n, 0, channels, maxy - 1, maxx - 1, 0);
|
2020-06-09 10:08:29 +00:00
|
|
|
}
|
2019-12-04 15:00:23 +00:00
|
|
|
if(maxx >= 4 && maxy >= 3){
|
2021-03-04 04:33:33 +00:00
|
|
|
// don't zero-index to viewer
|
|
|
|
ret |= (ncplane_printf_yx(n, (maxy - 1) / 2, (maxx - 1) / 2, "%02d", idx + 1) < 0);
|
2019-11-28 21:19:08 +00:00
|
|
|
}
|
2020-02-23 10:04:59 +00:00
|
|
|
return ret;
|
2019-11-28 20:41:51 +00:00
|
|
|
}
|
|
|
|
|
2019-11-29 03:08:26 +00:00
|
|
|
static int
|
|
|
|
draw_bounding_box(struct ncplane* n, int yoff, int xoff, int chunky, int chunkx){
|
2019-12-03 23:40:41 +00:00
|
|
|
int ret;
|
|
|
|
uint64_t channels = 0;
|
2021-04-29 05:18:37 +00:00
|
|
|
ncchannels_set_fg_rgb8(&channels, 180, 80, 180);
|
2020-09-17 19:34:28 +00:00
|
|
|
//channels_set_bg_rgb8(&channels, 0, 0, 0);
|
2019-11-29 03:08:26 +00:00
|
|
|
ncplane_cursor_move_yx(n, yoff, xoff);
|
2021-12-02 06:45:49 +00:00
|
|
|
if(notcurses_canutf8(ncplane_notcurses(n))){
|
|
|
|
ret = ncplane_rounded_box(n, 0, channels,
|
|
|
|
CHUNKS_VERT * chunky + yoff + 1,
|
|
|
|
CHUNKS_HORZ * chunkx + xoff + 1, 0);
|
|
|
|
}else{
|
|
|
|
ret = ncplane_ascii_box(n, 0, channels,
|
2019-12-03 23:40:41 +00:00
|
|
|
CHUNKS_VERT * chunky + yoff + 1,
|
2019-12-04 05:46:38 +00:00
|
|
|
CHUNKS_HORZ * chunkx + xoff + 1, 0);
|
2021-12-02 06:45:49 +00:00
|
|
|
}
|
2019-11-29 03:08:26 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-08-16 02:41:44 +00:00
|
|
|
// make a bunch of boxes with gradients and use them to play a sliding puzzle.
|
2021-11-28 10:07:15 +00:00
|
|
|
int sliders_demo(struct notcurses* nc, uint64_t startns){
|
2019-11-28 20:20:10 +00:00
|
|
|
int ret = -1, z;
|
2021-11-07 22:52:50 +00:00
|
|
|
unsigned maxx, maxy;
|
2020-02-21 05:13:03 +00:00
|
|
|
struct ncplane* n = notcurses_stddim_yx(nc, &maxy, &maxx);
|
2019-11-28 20:20:10 +00:00
|
|
|
int chunky, chunkx;
|
2019-11-28 21:19:08 +00:00
|
|
|
// want at least 2x2 for each sliding chunk
|
|
|
|
if(maxy < CHUNKS_VERT * 2 || maxx < CHUNKS_HORZ * 2){
|
2019-11-28 20:20:10 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2019-11-29 03:08:26 +00:00
|
|
|
// we want an 8x8 grid of chunks with a border. the leftover space will be unused
|
|
|
|
chunky = (maxy - 2) / CHUNKS_VERT;
|
|
|
|
chunkx = (maxx - 2) / CHUNKS_HORZ;
|
2020-02-23 12:16:07 +00:00
|
|
|
// want an even width so our 2-digit IDs are centered exactly
|
|
|
|
chunkx -= (chunkx % 2);
|
2019-12-05 05:43:09 +00:00
|
|
|
// don't allow them to be too rectangular, but keep aspect ratio in mind!
|
|
|
|
if(chunky > chunkx + 1){
|
|
|
|
chunky = chunkx + 1;
|
|
|
|
}else if(chunkx > chunky * 2){
|
|
|
|
chunkx = chunky * 2;
|
|
|
|
}
|
|
|
|
int wastey = ((maxy - 2) - (CHUNKS_VERT * chunky)) / 2;
|
|
|
|
int wastex = ((maxx - 2) - (CHUNKS_HORZ * chunkx)) / 2;
|
2019-11-29 03:08:26 +00:00
|
|
|
const int chunkcount = CHUNKS_VERT * CHUNKS_HORZ;
|
2019-11-28 20:20:10 +00:00
|
|
|
struct ncplane** chunks = malloc(sizeof(*chunks) * chunkcount);
|
|
|
|
if(chunks == NULL){
|
2020-05-07 05:24:03 +00:00
|
|
|
return -1;
|
2019-11-28 20:20:10 +00:00
|
|
|
}
|
|
|
|
memset(chunks, 0, sizeof(*chunks) * chunkcount);
|
2019-12-04 15:00:23 +00:00
|
|
|
// draw the 72 boxes in a nice color pattern, in order
|
2019-11-28 20:20:10 +00:00
|
|
|
int cy, cx;
|
|
|
|
for(cy = 0 ; cy < CHUNKS_VERT ; ++cy){
|
|
|
|
for(cx = 0 ; cx < CHUNKS_HORZ ; ++cx){
|
|
|
|
const int idx = cy * CHUNKS_HORZ + cx;
|
2020-11-15 06:03:50 +00:00
|
|
|
struct ncplane_options nopts = {
|
|
|
|
.y = cy * chunky + wastey + 1,
|
|
|
|
.x = cx * chunkx + wastex + 1,
|
|
|
|
.rows = chunky,
|
|
|
|
.cols = chunkx,
|
|
|
|
};
|
|
|
|
chunks[idx] = ncplane_create(n, &nopts);
|
2019-11-28 20:20:10 +00:00
|
|
|
if(chunks[idx] == NULL){
|
|
|
|
goto done;
|
|
|
|
}
|
2020-06-09 10:08:29 +00:00
|
|
|
if(fill_chunk(chunks[idx], idx)){
|
|
|
|
goto done;
|
|
|
|
}
|
2019-11-28 20:20:10 +00:00
|
|
|
}
|
|
|
|
}
|
2019-12-04 15:00:23 +00:00
|
|
|
// draw a box around the playing area
|
2019-11-29 03:08:26 +00:00
|
|
|
if(draw_bounding_box(n, wastey, wastex, chunky, chunkx)){
|
2020-01-03 10:48:59 +00:00
|
|
|
goto done;
|
2019-11-29 03:08:26 +00:00
|
|
|
}
|
2020-02-12 03:22:37 +00:00
|
|
|
DEMO_RENDER(nc);
|
2019-12-04 15:00:23 +00:00
|
|
|
// shuffle up the chunks
|
|
|
|
int i;
|
2021-01-13 10:49:57 +00:00
|
|
|
demo_nanosleep(nc, &demodelay);
|
2019-12-04 15:00:23 +00:00
|
|
|
for(i = 0 ; i < 200 ; ++i){
|
2021-07-24 19:18:02 +00:00
|
|
|
int i0 = rand() % chunkcount;
|
|
|
|
int i1 = rand() % chunkcount;
|
2019-12-04 15:00:23 +00:00
|
|
|
while(i1 == i0){
|
2021-07-24 19:18:02 +00:00
|
|
|
i1 = rand() % chunkcount;
|
2019-12-04 15:00:23 +00:00
|
|
|
}
|
|
|
|
int targy0, targx0;
|
|
|
|
int targy, targx;
|
|
|
|
ncplane_yx(chunks[i0], &targy0, &targx0);
|
|
|
|
ncplane_yx(chunks[i1], &targy, &targx);
|
|
|
|
struct ncplane* t = chunks[i0];
|
|
|
|
ncplane_move_yx(t, targy, targx);
|
|
|
|
chunks[i0] = chunks[i1];
|
|
|
|
ncplane_move_yx(chunks[i0], targy0, targx0);
|
|
|
|
chunks[i1] = t;
|
2020-02-12 03:22:37 +00:00
|
|
|
DEMO_RENDER(nc);
|
2019-11-29 03:08:26 +00:00
|
|
|
}
|
2021-11-28 10:07:15 +00:00
|
|
|
ret = play(nc, chunks, startns);
|
2019-11-28 20:20:10 +00:00
|
|
|
|
|
|
|
done:
|
|
|
|
for(z = 0 ; z < chunkcount ; ++z){
|
2019-11-29 03:08:26 +00:00
|
|
|
ncplane_destroy(chunks[z]);
|
2019-11-28 20:20:10 +00:00
|
|
|
}
|
|
|
|
free(chunks);
|
|
|
|
return ret;
|
|
|
|
}
|