ALMOST WORKING

AHH
This commit is contained in:
Julia 2024-05-15 17:10:47 -05:00
parent e3ed625feb
commit 1c4197e864
36 changed files with 366 additions and 307 deletions

View file

@ -60,7 +60,8 @@
"stdbool.h": "c", "stdbool.h": "c",
"fumoengine.h": "c", "fumoengine.h": "c",
"event.h": "c", "event.h": "c",
"fumocommon.h": "c" "fumocommon.h": "c",
"terminal.h": "c"
} }
} }
} }

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
["1d6bdf7e8de4ac751252b67027e5d57e", "9df90eabc8908cac60aa774d335a106c", "1420f33d62a8ed8429c8f1a96f1ab33e", "dc6df72158812bc9f6ed484a4cfb046b", "6669fc7fcffc77563f1315cb7710ec82", "333c7211bb2c72ad321495f53d11bff0", "088145536b04ef82517eb93630888dff", "f61af2abe56cd6881a830ae6222483e9", "e09059d1f20c982c6c42a61a0754c102", "fbccab3d5cd1838cbf8ad1d4e2a7c03b", "330b6f9493d091e7c340c1434b6f80b4", "e38bd5ea2b554a21849158242a2add8e"] ["f315479de287d3cccdfa665c1e8c58bd", "7d30e573f96a566ed9510833b95d5520", "0eaec40fe47b9cb31ff5a70f7bfee15a", "72e1b62b85eac654ed094a8ecf009416", "5ce28b2bf9d7c5750ea290f80fbd1264", "0d65896ce70d098bdf4cb3587ca74508", "f6611a0f07f78cc4fd52df267e0d3d25", "9f0597e7cacc7c918163affc5f3d9841", "cd22e396133a64303ecae95280f8ba1a", "7d7451ae7d88f4d1f84055180f9e84a7", "29f6d19bcc5a1897b220a192ef6fc3cc", "1d88301163b019760c3dc8396ce2aa4b", "ec4912a725a2bc606bd76ba34159435c"]

View file

@ -1 +1 @@
[] ["4aa55dfc1d038e75d0efbf277e6033a4"]

BIN
debug.exe

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -2,11 +2,16 @@
#include <time.h> #include <time.h>
usize min_usize(usize a, usize b) usize min(usize a, usize b)
{ {
return a < b ? a : b; return a < b ? a : b;
} }
usize max(usize a, usize b)
{
return a > b ? a : b;
}
nsec TimeNow() nsec TimeNow()
{ {
struct timespec ts; struct timespec ts;

View file

@ -40,7 +40,8 @@ typedef int_fast64_t i64f;
typedef u64 nsec; typedef u64 nsec;
size_t min_usize(usize a, usize b); size_t min(usize a, usize b);
size_t max(usize a, usize b);
nsec TimeNow(); nsec TimeNow();
double TimeNowD(); double TimeNowD();

View file

@ -2,16 +2,35 @@
#include "platform.h" #include "platform.h"
const VectorT FUMOCO_T = VECTOR_T(struct FumoCoroutine);
void Panic(char *message) void Panic(char *message)
{ {
printf(message); printf(message);
exit(1); exit(1);
} }
bool CreateFumoInstance(struct FumoInstance *instance) bool CoroutineAdd(struct Instance *inst, void *state, coroutine_handler callback)
{
return VectorAdd(&inst->coroutines, &(struct Coroutine) {
.callback = callback,
.state = state,
.next_scheduled = inst->time
});
}
void CoroutineTryInvoke(struct Instance *inst, struct Coroutine *co)
{
while (inst->time > co->next_scheduled) {
nsec wait = co->callback(inst, co->state);
if (wait == 0) {
co->next_scheduled = inst->time;
break;
} else {
co->next_scheduled += wait;
}
}
}
bool CreateFumoInstance(struct Instance *instance)
{ {
if (!PlatformInit()) if (!PlatformInit())
Panic("Platform failed to initialize"); Panic("Platform failed to initialize");
@ -22,27 +41,27 @@ bool CreateFumoInstance(struct FumoInstance *instance)
if (!CreateInputThread(&instance->input_hand)) if (!CreateInputThread(&instance->input_hand))
Panic("Input handle failed to initialize"); Panic("Input handle failed to initialize");
if (!CreateTerminal(&instance->term, 20, 10))
Panic("Out of memory");
if (!CreateEvent(&instance->on_start)) if (!CreateEvent(&instance->on_start))
Panic("Out of memory"); Panic("Out of memory");
if (!CreateEvent(&instance->on_update)) if (!CreateEvent(&instance->on_update))
Panic("Out of memory"); Panic("Out of memory");
if (!CreateEvent(&instance->on_draw))
Panic("Out of memory");
if (!CreateVector(&instance->coroutines, sizeof(struct Coroutine)))
Panic("Out of memory");
instance->time = TimeNow(); instance->time = TimeNow();
return true; return true;
} }
bool FumoInstanceRun(struct FumoInstance *inst) bool FumoInstanceRun(struct Instance *inst)
{ {
EventInvoke(&inst->on_start, inst); EventInvoke(&inst->on_start, inst);
usize buf_n = TerminalMaxOut(&inst->term);
char *buf = malloc(buf_n);
while (true) { while (true) {
// Time // Time
nsec now = TimeNow(); nsec now = TimeNow();
@ -60,25 +79,14 @@ bool FumoInstanceRun(struct FumoInstance *inst)
// Update // Update
EventInvoke(&inst->on_update, inst); EventInvoke(&inst->on_update, inst);
for (usize i = 0; i < inst->coroutines.len; i++) { for (usize i = 0; i < inst->coroutines.len; i++) {
struct FumoCoroutine *co = VectorGet(FUMOCO_T, &inst->coroutines, i); CoroutineTryInvoke(inst, VectorGet(&inst->coroutines, i));
co->callback();
} }
// Draw // Draw
EventInvoke(&inst->on_draw, inst); EventInvoke(&inst->on_draw, inst);
TerminalPrint(&inst->term, buf, buf_n);
puts(buf);
//_sleep(100); //_sleep(100);
} }
} }
bool CoroutineAdd(struct FumoInstance *inst, handler callback, nsec period)
{
return VectorAdd(FUMOCO_T, &inst->coroutines, &(struct FumoCoroutine) {
.callback = callback,
.timer = 0,
.period = period
});
}

View file

@ -3,20 +3,21 @@
#include "event.h" #include "event.h"
#include "fumocommon.h" #include "fumocommon.h"
#include "input.h" #include "input.h"
#include "terminal.h"
#include "vector.h" #include "vector.h"
struct FumoCoroutine { typedef nsec (*coroutine_handler)(void *state, void *instance);
handler callback;
nsec timer;
nsec period; struct Coroutine {
coroutine_handler callback;
void *state;
nsec next_scheduled;
}; };
struct FumoInstance { struct Instance {
struct Controller ctrl; struct Controller ctrl;
struct InputHandle input_hand; struct InputHandle input_hand;
struct Terminal term;
struct Event on_start; struct Event on_start;
struct Event on_update; struct Event on_update;
@ -31,6 +32,10 @@ struct FumoInstance {
void Panic(char *message); void Panic(char *message);
bool CreateFumoInstance(struct FumoInstance *game); bool CoroutineAdd(struct Instance *inst, void *state, coroutine_handler callback);
bool FumoInstanceRun(struct FumoInstance *game); void CoroutineTryInvoke(struct Instance *inst, struct Coroutine *co);
bool CreateFumoInstance(struct Instance *game);
bool FumoInstanceRun(struct Instance *game);

View file

@ -1,21 +1,24 @@
#include "dictionary.h" #include "dictionary.h"
#include <stdalign.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
bool CreateDictionary(DictT T, struct Dictionary *dict) bool CreateDictionary(struct Dictionary *dict, usize value_size)
{ {
void *bkts = calloc(16, T->BKT_SIZE); void *bkts = calloc(16, value_size);
if (bkts == nullptr) if (bkts == nullptr)
return false; return false;
*dict = (struct Dictionary) { dict->value_size = value_size;
.filled = 0, dict->value_offset = max(alignof(u32), alignof(u8[dict->value_size]));
.capacity = 16, dict->bkt_size = dict->value_offset + value_size;
.bkts = bkts
}; dict->filled = 0;
dict->capacity = 16;
dict->bkts = bkts;
return true; return true;
} }
@ -25,45 +28,45 @@ void FreeDictionary(struct Dictionary *dict)
free(dict->bkts); free(dict->bkts);
} }
void *index_bkt(DictT T, struct Dictionary *dict, usize i) void *index_bkt(struct Dictionary *dict, usize i)
{ {
return (u8 *)dict->bkts + i * T->BKT_SIZE; return (u8 *)dict->bkts + i * dict->bkt_size;
} }
u32 *get_key(DictT T, void *bkt) u32 *get_key(struct Dictionary *dict, void *bkt)
{ {
return (u32 *)bkt; return (u32 *)bkt;
} }
void *get_val(DictT T, void *bkt) void *get_value_ptr(struct Dictionary *dict, void *bkt)
{ {
return (u8 *)bkt + T->VAL_OFS; return (u8 *)bkt + dict->value_offset;
} }
void set_bkt(DictT T, void *bkt, u32 key, void *val) void set_bkt(struct Dictionary *dict, void *bkt, u32 key, void *value_ptr)
{ {
*get_key(T, bkt) = key; *get_key(dict, bkt) = key;
memcpy(get_val(T, bkt), val, T->VAL_SIZE); memcpy(get_value_ptr(dict, bkt), value_ptr, dict->value_size);
} }
void *probe_bkt(DictT T, struct Dictionary *dict, usize index, u32 key) void *probe_bkt(struct Dictionary *dict, usize index, u32 key)
{ {
for (usize i = 0; i < dict->capacity; i++) { for (usize i = 0; i < dict->capacity; i++) {
void *bkt = index_bkt(T, dict, (index + i) % dict->capacity); void *bkt = index_bkt(dict, (index + i) % dict->capacity);
if (*get_key(T, bkt) == key) if (*get_key(dict, bkt) == key)
return bkt; return bkt;
} }
return nullptr; return nullptr;
} }
void *probe_empty_bkt(DictT T, struct Dictionary *dict, usize index, u32 key) void *probe_empty_bkt(struct Dictionary *dict, usize index, u32 key)
{ {
for (usize i = 0; i < dict->capacity; i++) { for (usize i = 0; i < dict->capacity; i++) {
void *bkt = index_bkt(T, dict, (index + i) % dict->capacity); void *bkt = index_bkt(dict, (index + i) % dict->capacity);
u32 k = *get_key(T, bkt); u32 k = *get_key(dict, bkt);
if (k == 0 or k == key) if (k == 0 or k == key)
return bkt; return bkt;
} }
@ -71,25 +74,25 @@ void *probe_empty_bkt(DictT T, struct Dictionary *dict, usize index, u32 key)
return nullptr; return nullptr;
} }
void *DictionaryFind(DictT T, struct Dictionary *dict, u32 key) void *DictionaryFind(struct Dictionary *dict, u32 key)
{ {
usize index = key % dict->capacity; usize index = key % dict->capacity;
void *bkt = probe_bkt(T, dict, index, key); void *bkt = probe_bkt(dict, index, key);
if (bkt == nullptr) if (bkt == nullptr)
return false; return false;
return get_val(T, bkt); return get_value_ptr(dict, bkt);
} }
void *DictionarySet(DictT T, struct Dictionary *dict, u32 key, void *val) void *DictionarySet(struct Dictionary *dict, u32 key, void *value_ptr)
{ {
usize index = key % dict->capacity; usize index = key % dict->capacity;
void *bkt = probe_empty_bkt(T, dict, index, key); void *bkt = probe_empty_bkt(dict, index, key);
if (*get_key(T, bkt) == 0) if (*get_key(dict, bkt) == 0)
set_bkt(T, bkt, key, val); set_bkt(dict, bkt, key, value_ptr);
return bkt; return bkt;
} }

View file

@ -1,31 +1,21 @@
#pragma once #pragma once
#include "fumocommon.h" #include "fumocommon.h"
#define DICT_T(DICT_VAL_T) \
(&(struct DictT) { \
.VAL_SIZE = sizeof(DICT_VAL_T), \
.VAL_OFS = offsetof(struct { u32 k; DICT_VAL_T v; }, v), \
.BKT_SIZE = sizeof(struct { u32 k; DICT_VAL_T v; }) \
}) \
typedef const struct DictT {
usize VAL_SIZE;
usize VAL_OFS;
usize BKT_SIZE;
} *const DictT;
struct Dictionary { struct Dictionary {
usize value_size;
usize value_offset;
usize bkt_size;
usize filled; usize filled;
usize capacity; usize capacity;
void *bkts; void *bkts;
}; };
bool CreateDictionary(struct Dictionary *dict, usize value_size);
bool CreateDictionary(DictT T, struct Dictionary *dict);
void FreeDictionary(struct Dictionary *dict); void FreeDictionary(struct Dictionary *dict);
void *DictionaryFind(DictT T, struct Dictionary *dict, u32 key); void *DictionaryFind(struct Dictionary *dict, u32 key);
void *DictionarySet(DictT T, struct Dictionary *dict, u32 key, void *val); void *DictionarySet(struct Dictionary *dict, u32 key, void *value_ptr);

View file

@ -22,7 +22,7 @@ void FreeEvent(struct Event *event)
free(event->methods); free(event->methods);
} }
bool EventAdd(struct Event *event, handler callback, void *instance) bool EventAdd(struct Event *event, void *instance, handler callback)
{ {
if (event->len == event->capacity) { if (event->len == event->capacity) {
usize new_size = event->capacity * 2 * sizeof(struct Method); usize new_size = event->capacity * 2 * sizeof(struct Method);

View file

@ -21,6 +21,6 @@ struct Event {
bool CreateEvent(struct Event *event); bool CreateEvent(struct Event *event);
bool EventAdd(struct Event *event, handler callback, void *instance); bool EventAdd(struct Event *event, void *instance, handler callback);
void EventInvoke(struct Event *event, void *state); void EventInvoke(struct Event *event, void *state);

View file

@ -37,7 +37,7 @@ void RingBufferTransfer(
struct RingBufferHead *dest, struct RingBufferHead *dest,
struct RingBufferHead *tmp struct RingBufferHead *tmp
) { ) {
usize copy_max = min_usize(T->LEN - dest->len, tmp->len); usize copy_max = min(T->LEN - dest->len, tmp->len);
for (usize i = 0; i < copy_max; i++) { for (usize i = 0; i < copy_max; i++) {
void *to = RingBufferGet(T, dest, dest->len + i); void *to = RingBufferGet(T, dest, dest->len + i);
@ -55,7 +55,7 @@ usize RingBufferOut(
void *dest, void *dest,
struct RingBufferHead *src struct RingBufferHead *src
) { ) {
usize copy_max = min_usize(n, src->len); usize copy_max = min(n, src->len);
for (usize i = 0; i < copy_max; i++) { for (usize i = 0; i < copy_max; i++) {
void *to = (u8 *)dest + i * T->SIZE; void *to = (u8 *)dest + i * T->SIZE;

View file

@ -3,13 +3,15 @@
#include <string.h> #include <string.h>
bool CreateVector(VectorT T, struct Vector *vec) bool CreateVector(struct Vector *vec, usize value_size)
{ {
void *array = malloc(16 * T->SIZE); void *array = malloc(16 * value_size);
if (array == nullptr) if (array == nullptr)
return false; return false;
vec->value_size = value_size;
vec->len = 0; vec->len = 0;
vec->capacity = 16; vec->capacity = 16;
vec->array = array; vec->array = array;
@ -22,16 +24,16 @@ void FreeVector(struct Vector *vec)
free(vec->array); free(vec->array);
} }
void *VectorGet(VectorT T, struct Vector *vec, usize i) void *VectorGet(struct Vector *vec, usize i)
{ {
return (u8 *)vec->array + i * T->SIZE; return (u8 *)vec->array + i * vec->value_size;
} }
bool VectorAdd(VectorT T, struct Vector *vec, void *item) bool VectorAdd(struct Vector *vec, void *item)
{ {
if (vec->len == vec->capacity) { if (vec->len == vec->capacity) {
usize new_capacity = vec->capacity * 2; usize new_capacity = vec->capacity * 2;
void *new_array = realloc(vec->array, new_capacity * T->SIZE); void *new_array = realloc(vec->array, new_capacity * vec->value_size);
if (new_array == nullptr) if (new_array == nullptr)
return false; return false;
@ -39,7 +41,7 @@ bool VectorAdd(VectorT T, struct Vector *vec, void *item)
vec->capacity = new_capacity; vec->capacity = new_capacity;
} }
memcpy(VectorGet(T, vec, vec->len++), item, T->SIZE); memcpy(VectorGet(vec, vec->len++), item, vec->value_size);
return true; return true;
} }

View file

@ -1,26 +1,19 @@
#include "fumocommon.h" #include "fumocommon.h"
#define VECTOR_T(VEC_ITEM_T) \
(&(struct VectorT) { \
.SIZE = sizeof(VEC_ITEM_T) \
}) \
typedef const struct VectorT {
usize SIZE;
} *const VectorT;
struct Vector { struct Vector {
usize value_size;
usize len; usize len;
usize capacity; usize capacity;
void *array; void *array;
}; };
bool CreateVector(VectorT T, struct Vector *vec); bool CreateVector(struct Vector *vec, usize value_size);
void FreeVector(struct Vector *vec); void FreeVector(struct Vector *vec);
void *VectorGet(VectorT T, struct Vector *vec, usize i); void *VectorGet(struct Vector *vec, usize i);
bool VectorAdd(VectorT T, struct Vector *vec, void *item); bool VectorAdd(struct Vector *vec, void *item);

View file

@ -4,16 +4,13 @@
#define INIT_SIZE 16 #define INIT_SIZE 16
DictT BIND_T = DICT_T(struct InputAxis *);
bool CreateController(struct Controller *ctrl) bool CreateController(struct Controller *ctrl)
{ {
struct InputAxis *axes = calloc(16, sizeof(struct InputAxis)); struct InputAxis *axes = calloc(16, sizeof(struct InputAxis));
if (axes == nullptr) if (axes == nullptr)
return false; return false;
if (!CreateDictionary(BIND_T, &ctrl->binds)) if (!CreateDictionary(&ctrl->binds, sizeof(struct InputAxis*)))
return false; return false;
ctrl->pending_len = 0; ctrl->pending_len = 0;
@ -39,7 +36,7 @@ bool ControllerBind(struct Controller *ctrl, u16 control, u16 code, u16 type)
u32 hash = hash_bind(code, type); u32 hash = hash_bind(code, type);
struct InputAxis *axis = &ctrl->axes[control]; struct InputAxis *axis = &ctrl->axes[control];
struct InputAxis **bind = DictionarySet(BIND_T, &ctrl->binds, hash, &axis); struct InputAxis **bind = DictionarySet(&ctrl->binds, hash, &axis);
if (bind == nullptr) if (bind == nullptr)
return false; return false;
@ -92,7 +89,7 @@ void ControllerPoll(struct Controller *ctrl, struct RecordBuffer *recs)
struct InputRecord *rec = recs->buf + i; struct InputRecord *rec = recs->buf + i;
u32 hash = hash_bind(rec->code, rec->type); u32 hash = hash_bind(rec->code, rec->type);
struct InputAxis **axis = DictionaryFind(BIND_T, &ctrl->binds, hash); struct InputAxis **axis = DictionaryFind(&ctrl->binds, hash);
if (axis == nullptr) if (axis == nullptr)
continue; continue;
@ -103,43 +100,3 @@ void ControllerPoll(struct Controller *ctrl, struct RecordBuffer *recs)
recs->head.len = 0; recs->head.len = 0;
} }
/*int main()
{
struct Controller ctrl;
if (!CreateController(&ctrl))
return 1;
ControllerMap(&ctrl, 123, 111, BUTTON);
ControllerMap(&ctrl, 0, 8, BUTTON);
struct RecordBuffer recs = { .head.len = 0, .head.start = 0 };
recs.buf[recs.head.len++] = (struct InputRecord) {
.but.value = 69,
.is_down = true,
.id.bind = 111,
.id.type = BUTTON
};
recs.buf[recs.head.len++] = (struct InputRecord) {
.but.value = 1000,
.is_down = true,
.id.bind = 8,
.id.type = BUTTON
};
ControllerPoll(&ctrl, &recs);
struct InputAxis *a = ControllerGet(&ctrl, 123, BUTTON);
printf("%u\n", a->but.value);
struct InputAxis *b = ControllerGet(&ctrl, 0, BUTTON);
printf("%u\n", b->but.value);
printf("success");
return 0;
}*/

View file

@ -5,26 +5,30 @@
#define MAX_CH4_LEN 11 #define MAX_CH4_LEN 11
usize TerminalMaxOut(struct Terminal *term) usize TerminalMaxOut(usize wid, usize hgt)
{ {
return RESET_STR_LEN return RESET_STR_LEN
+ MAX_CH4_LEN * term->wid * term->hgt + MAX_CH4_LEN * wid * hgt
+ term->hgt + hgt
+ 1; + 1;
} }
bool CreateTerminal(struct Terminal *term, usize wid, usize hgt) bool CreateTerminal(struct Terminal *term, usize wid, usize hgt)
{ {
struct Char4 *ch4s = calloc(wid * hgt, sizeof(struct Char4)); struct Char4 *ch4s = calloc(wid * hgt, sizeof(struct Char4));
if (ch4s == nullptr) if (ch4s == nullptr)
return false; return false;
*term = (struct Terminal) { char *str = malloc(TerminalMaxOut(wid, hgt));
.wid = wid, if (str == nullptr)
.hgt = hgt, return false;
.buf = ch4s *term = (struct Terminal) {
.buf = ch4s,
.str = str,
.wid = wid,
.hgt = hgt
}; };
return true; return true;
@ -107,12 +111,12 @@ usize ch4_dif_to_str(char *out, struct Color4 *dif, struct Char4 *ch4)
return len; return len;
} }
usize TerminalPrint(struct Terminal *term, char *out, usize n) usize TerminalPrint(struct Terminal *term)
{ {
struct Color4 dif = { 0, 0 }; struct Color4 dif = { 0, 0 };
usize len = 7; usize len = 7;
memcpy(out, "\x1b[H\x1b[0m", 7); memcpy(term->str, "\x1b[H\x1b[0m", 7);
usize i = 0; usize i = 0;
for (usize y = 0; y < term->hgt; y++) { for (usize y = 0; y < term->hgt; y++) {
@ -124,11 +128,11 @@ usize TerminalPrint(struct Terminal *term, char *out, usize n)
ch4->ch = '#'; ch4->ch = '#';
// DEBUG // DEBUG
len += ch4_dif_to_str(out + len, &dif, ch4); len += ch4_dif_to_str(term->str + len, &dif, ch4);
} }
out[len++] = '\n'; term->str[len++] = '\n';
} }
out[len] = 0; term->str[len] = 0;
return len; return len;
} }

View file

@ -1,10 +1,6 @@
#pragma once #pragma once
#include <iso646.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "fumocommon.h" #include "fumocommon.h"
@ -19,16 +15,18 @@ struct Char4 {
}; };
struct Terminal { struct Terminal {
struct Char4 *buf;
char *str;
usize wid; usize wid;
usize hgt; usize hgt;
struct Char4 *buf;
}; };
usize TerminalMaxOut(struct Terminal *term); usize TerminalMaxOut(usize wid, usize hgt);
bool CreateTerminal(struct Terminal *term, usize wid, usize hgt); bool CreateTerminal(struct Terminal *term, usize wid, usize hgt);
void FreeTerminal(struct Terminal *term); void FreeTerminal(struct Terminal *term);
usize TerminalPrint(struct Terminal *term, char *out, usize n); usize TerminalPrint(struct Terminal *term);

View file

@ -3,99 +3,143 @@
struct Fumotris { struct Fumotris {
struct Terminal term;
struct TetraTemplate *bag[7];
usize bag_i;
struct Tetra board; struct Tetra board;
struct Tetra piece; struct Tetra piece;
bool is_ground; bool is_ground;
nsec last_moved;
nsec last_dropped;
}; };
void shuffle(struct Fumotris *fumo)
struct TetraTemplate *bag[7] = { &I, &O, &T, &S, &Z, &J, &L };
usize bag_i = 0;
void shuffle()
{ {
for (usize i = 6; i >= 0; i--) { for (usize i = 6; i > 0; i--) {
usize swap = rand() % i; usize swap = rand() % i;
struct TetraTemplate *tmp = bag[swap]; struct TetraTemplate *tmp = fumo->bag[swap];
bag[swap] = bag[i]; fumo->bag[swap] = fumo->bag[i];
bag[i] = tmp; fumo->bag[i] = tmp;
} }
} }
void place_piece(struct Fumotris *fumo) void check_clear()
{
}
void place(struct Fumotris *fumo)
{ {
TetraOverlay(&fumo->piece, &fumo->board); TetraOverlay(&fumo->piece, &fumo->board);
SetTetra(&fumo->piece, bag[bag_i++], 0, 0);
if (bag_i == 7) { usize lines_cleared = fumo->piece.hgt;
shuffle();
bag_i = 0; for (usize y = fumo->piece.y; y < fumo->piece.y + fumo->piece.hgt; y++) {
for (usize x = 0; x < fumo->board.wid; x++) {
if (fumo->board.blks[fumo->board.wid * y + x] == 0) {
lines_cleared -= 1;
break;
}
}
} }
TetraSet(&fumo->piece, fumo->bag[fumo->bag_i++]);
if (fumo->bag_i == 7) {
shuffle(fumo);
fumo->bag_i = 0;
}
} }
i16 get_horizontal(struct Controller *ctrl) i16 get_horizontal(struct Controller *ctrl)
{ {
return (-(i16)ctrl->axes[LEFT].is_down) + ctrl->axes[RIGHT].is_down; return (-(i16)ctrl->axes[LEFT].is_held) + ctrl->axes[RIGHT].is_held;
} }
void FumotrisStart(struct FumoInstance *inst, struct Fumotris *fumo) void FumotrisStart(struct Instance *inst, struct Fumotris *fumo)
{ {
ControllerBindMulti(&inst->ctrl, BINDS_N, controls_g, codes_g, types_g); ControllerBindMulti(&inst->ctrl, BINDS_N, CONTROLS, CODES, TYPES);
CreateTetra(&fumo->board, 10, 10);
CreateTerminal(&fumo->term, 20, 20);
for (usize i = 0; i < 7; i++)
fumo->bag[i] = templates[i];
fumo->bag_i = 1;
CreateTetra(&fumo->board, 10, 20);
TetraSet(&fumo->piece, fumo->bag[0]);
fumo->is_ground = false; fumo->is_ground = false;
fumo->last_moved = 0;
SetTetra(&fumo->piece, bag[bag_i++], 0, 0); fumo->last_dropped = 0;
} }
void FumotrisUpdate(struct FumoInstance *inst, struct Fumotris *fumo) void FumotrisUpdate(struct Instance *inst, struct Fumotris *fumo)
{ {
TetraMove(&fumo->piece, &fumo->board, get_horizontal(&inst->ctrl), 0); i16 horizontal = get_horizontal(&inst->ctrl);
if (inst->ctrl.axes[SOFT_DROP].is_down) { if (horizontal != 0 and fumo->last_moved < inst->time) {
fumo->last_moved = inst->time + 5e7;
TetraMove(&fumo->piece, &fumo->board, horizontal, 0);
}
if (inst->ctrl.axes[ROTATE_CCW].is_down)
TetraRotate(&fumo->piece, &fumo->board, 1);
if (inst->ctrl.axes[ROTATE_CW].is_down)
TetraRotate(&fumo->piece, &fumo->board, -1);
if (inst->ctrl.axes[SOFT_DROP].is_held and fumo->last_dropped < inst->time) {
fumo->last_dropped = inst->time + 5e7;
TetraMove(&fumo->piece, &fumo->board, 0, 1); TetraMove(&fumo->piece, &fumo->board, 0, 1);
} }
if (inst->ctrl.axes[HARD_DROP].is_down) { if (inst->ctrl.axes[HARD_DROP].is_down) {
while (TetraMove(&fumo->piece, &fumo->board, 0, 1)); while (TetraMove(&fumo->piece, &fumo->board, 0, 1));
place_piece(fumo); place(fumo);
} }
} }
void FumotrisOnFall(struct FumoInstance *inst, struct Fumotris *fumo) nsec FumotrisFall(struct Instance *inst, struct Fumotris *fumo)
{ {
if (!TetraMove(&fumo->piece, &fumo->board, 0, 1)) { if (!TetraMove(&fumo->piece, &fumo->board, 0, 1)) {
if (!fumo->is_ground) if (!fumo->is_ground)
fumo->is_ground = true; fumo->is_ground = true;
else else
place_piece(fumo); place(fumo);
} }
return 5e8;
} }
void FumotrisDraw(struct FumoInstance *inst, struct Fumotris *fumo) void FumotrisDraw(struct Instance *inst, struct Fumotris *fumo)
{ {
TetraTerminalClear(&fumo->board, &inst->term); TetraTerminalClear(&fumo->board, &fumo->term);
TetraTerminalDraw(&fumo->board, &inst->term); TetraTerminalDraw(&fumo->board, &fumo->term);
TetraTerminalDraw(&fumo->piece, &inst->term); TetraTerminalDraw(&fumo->piece, &fumo->term);
TerminalPrint(&fumo->term);
puts(fumo->term.str);
} }
int main() int main()
{ {
struct FumoInstance inst; struct Instance inst;
CreateFumoInstance(&inst); CreateFumoInstance(&inst);
struct Fumotris game; struct Fumotris game;
EventAdd(&inst.on_start, FumotrisStart, &game); EventAdd(&inst.on_start, &game, FumotrisStart);
EventAdd(&inst.on_update, FumotrisUpdate, &game); EventAdd(&inst.on_update, &game, FumotrisUpdate);
EventAdd(&inst.on_draw, FumotrisDraw, &game); EventAdd(&inst.on_draw, &game, FumotrisDraw);
VectorAdd(FUMOCO_T, &inst.coroutines, ); CoroutineAdd(&inst, &game, FumotrisFall);
FumoInstanceRun(&inst); FumoInstanceRun(&inst);

View file

@ -1,5 +1,6 @@
#include "fumocommon.h" #include "fumocommon.h"
#include "fumoengine.h" #include "fumoengine.h"
#include "terminal.h"
#include "tetra.h" #include "tetra.h"
#define BINDS_N 12 #define BINDS_N 12
@ -23,7 +24,7 @@ enum FumotrisControls {
}; };
u16 controls_g[BINDS_N] = { u16 CONTROLS[BINDS_N] = {
LEFT, LEFT,
RIGHT, RIGHT,
SOFT_DROP, SOFT_DROP,
@ -40,7 +41,7 @@ u16 controls_g[BINDS_N] = {
MOUSE, MOUSE,
}; };
u16 codes_g[BINDS_N] = { u16 CODES[BINDS_N] = {
0x25, 0x25,
0x27, 0x27,
0x28, 0x28,
@ -57,7 +58,7 @@ u16 codes_g[BINDS_N] = {
0 0
}; };
u16 types_g[BINDS_N] = { u16 TYPES[BINDS_N] = {
BUTTON, BUTTON,
BUTTON, BUTTON,
BUTTON, BUTTON,
@ -75,7 +76,7 @@ u16 types_g[BINDS_N] = {
}; };
struct TetraTemplate I = { struct TetraTemplate I = {
.blks = &(u8) { .blks = (u8[16]) {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
@ -86,18 +87,18 @@ struct TetraTemplate I = {
}; };
struct TetraTemplate O = { struct TetraTemplate O = {
.blks = &(u8) { .blks = (u8[4]) {
1, 1, 2, 2,
1, 1 2, 2
}, },
.wid = 2, .wid = 2,
.hgt = 2 .hgt = 2
}; };
struct TetraTemplate T = { struct TetraTemplate T = {
.blks = &(u8) { .blks = (u8[9]) {
0, 1, 0, 0, 3, 0,
1, 1, 1, 3, 3, 3,
0, 0, 0 0, 0, 0
}, },
.wid = 3, .wid = 3,
@ -105,9 +106,9 @@ struct TetraTemplate T = {
}; };
struct TetraTemplate S = { struct TetraTemplate S = {
.blks = &(u8) { .blks = (u8[9]) {
0, 1, 1, 0, 4, 4,
1, 1, 0, 4, 4, 0,
0, 0, 0 0, 0, 0
}, },
.wid = 3, .wid = 3,
@ -115,9 +116,9 @@ struct TetraTemplate S = {
}; };
struct TetraTemplate Z = { struct TetraTemplate Z = {
.blks = &(u8) { .blks = (u8[9]) {
1, 1, 0, 5, 5, 0,
0, 1, 1, 0, 5, 5,
0, 0, 0 0, 0, 0
}, },
.wid = 3, .wid = 3,
@ -125,9 +126,9 @@ struct TetraTemplate Z = {
}; };
struct TetraTemplate J = { struct TetraTemplate J = {
.blks = &(u8) { .blks = (u8[9]) {
1, 0, 0, 6, 0, 0,
1, 1, 1, 6, 6, 6,
0, 0, 0 0, 0, 0
}, },
.wid = 3, .wid = 3,
@ -135,11 +136,13 @@ struct TetraTemplate J = {
}; };
struct TetraTemplate L = { struct TetraTemplate L = {
.blks = &(u8) { .blks = (u8[9]) {
0, 0, 1, 0, 0, 7,
1, 1, 1, 7, 7, 7,
0, 0, 0 0, 0, 0
}, },
.wid = 3, .wid = 3,
.hgt = 3 .hgt = 3
}; };
struct TetraTemplate *templates[7] = { &I, &O, &T, &S, &Z, &J, &L };

View file

@ -1,20 +1,24 @@
#include "tetra.h" #include "tetra.h"
bool CreateTetra(struct Tetra *map, u16 wid, u16 hgt) bool CreateTetra(struct Tetra *tetra, u16 wid, u16 hgt)
{ {
u8 *blks = calloc(wid * hgt, sizeof(u8)); u8 *blks = calloc(wid * hgt, sizeof(u8));
if (blks == nullptr) if (blks == nullptr)
return false; return false;
map->blks = blks; *tetra = (struct Tetra) {
map->wid = wid; .blks = blks,
map->hgt = hgt;
map->x = 0; .wid = wid,
map->y = 0; .hgt = hgt,
map->rot = 0;
.x = 0,
.y = 0,
.rot = 0
};
return true; return true;
} }
@ -24,37 +28,45 @@ void FreeTetra(struct Tetra *tetra)
free(tetra->blks); free(tetra->blks);
} }
void SetTetra(struct Tetra *map, struct TetraTemplate *t, i16 x, i16 y) void TetraSet(struct Tetra *tetra, struct TetraTemplate *template)
{ {
map->blks = t->blks; tetra->blks = template->blks;
map->wid = t->wid; tetra->wid = template->wid;
map->hgt = t->hgt; tetra->hgt = template->hgt;
map->x = x; tetra->x = 0;
map->y = y; tetra->y = 0;
map->rot = 0; tetra->rot = 0;
} }
bool TetraMove(struct Tetra *piece, struct Tetra *board, i16 dx, i16 dy) usize rotate_index(usize i, usize wid, u8 rot)
{ {
if (TetraIsCollision(piece, board, dx, dy)) if(rot == 0)
return false; return i;
piece->x += dx; usize row = i / wid;
piece->y += dy; usize col = i % wid;
return true; switch (rot) {
case 1:
return (wid - col - 1) * wid + row;
case 2:
return (wid - row - 1) * wid + (wid - col - 1);
case 3:
return col * wid + (wid - row - 1);
}
return 0;
} }
bool TetraIsCollision(struct Tetra *piece, struct Tetra *board, i16 dx, i16 dy) bool TetraIsCollision(struct Tetra *t, struct Tetra *board)
{ {
i16 x_start = piece->x + dx;
i16 y_start = piece->y + dy;
usize i = 0; usize i = 0;
for (i16 y = y_start; y < y_start + piece->hgt; y++) { for (i16 y = t->y; y < t->y + t->hgt; y++) {
for (i16 x = x_start; x < x_start + piece->wid; x++, i++) { for (i16 x = t->x; x < t->x + t->wid; x++, i++) {
if(piece->blks[i] == 0) usize rot_i = rotate_index(i, t->wid, t->rot);
if(t->blks[rot_i] == 0)
continue; continue;
if(x < 0 or x >= board->wid or y < 0 or y >= board->hgt) if(x < 0 or x >= board->wid or y < 0 or y >= board->hgt)
@ -68,6 +80,53 @@ bool TetraIsCollision(struct Tetra *piece, struct Tetra *board, i16 dx, i16 dy)
return false; return false;
} }
bool TetraMove(struct Tetra *t, struct Tetra *board, i16 dx, i16 dy)
{
t->x += dx;
t->y += dy;
if (TetraIsCollision(t, board)) {
t->x -= dx;
t->y -= dy;
return false;
}
return true;
}
bool TetraRotate(struct Tetra *t, struct Tetra *board, i8 dr)
{
u8 rot = t->rot;
t->rot = (t->rot + 4 + dr) % 4;
if (TetraIsCollision(t, board)) {
t->rot = rot;
return false;
}
return true;
}
void TetraOverlay(struct Tetra *t, struct Tetra *board)
{
usize i = 0;
for (i16 y = t->y; y < t->y + t->hgt; y++) {
for (i16 x = t->x; x < t->x + t->wid; x++, i++) {
usize rot_i = rotate_index(i, t->wid, t->rot);
if(t->blks[rot_i] == 0)
continue;
if(x < 0 or x >= board->wid or y < 0 or y >= board->hgt)
continue;
board->blks[board->wid * y + x] = t->blks[rot_i];
}
}
}
void TetraTerminalClear(struct Tetra *board, struct Terminal *term) void TetraTerminalClear(struct Tetra *board, struct Terminal *term)
{ {
for (usize i = 0; i < board->wid * board->hgt; i++) { for (usize i = 0; i < board->wid * board->hgt; i++) {
@ -78,38 +137,24 @@ void TetraTerminalClear(struct Tetra *board, struct Terminal *term)
} }
} }
void TetraTerminalDraw(struct Tetra *tetra, struct Terminal *term) void TetraTerminalDraw(struct Tetra *t, struct Terminal *term)
{ {
static const u8f blk_colors[8] = { 8, 14, 11, 13, 10, 9, 12, 3 }; static const u8f blk_colors[8] = { 8, 14, 11, 13, 10, 9, 12, 3 };
usize i = 0; usize i = 0;
for (usize y = 0; y < tetra->hgt; y++) { for (usize y = 0; y < t->hgt; y++) {
for (usize x = 0; x < tetra->wid; x++, i++) { for (usize x = 0; x < t->wid; x++, i++) {
if (tetra->blks[i] == 0) usize rot_i = rotate_index(i, t->wid, t->rot);
if (t->blks[rot_i] == 0)
continue; continue;
usize term_i = (y + tetra->y) * term->wid + (x + tetra->x) * 2; usize term_i = (y + t->y) * term->wid + (x + t->x) * 2;
struct Char4 *block = term->buf + term_i; struct Char4 *block = term->buf + term_i;
u8 fg = blk_colors[tetra->blks[i]]; u8 fg = blk_colors[t->blks[rot_i]];
block[0] = (struct Char4) { .ch = '[', .color.fg = fg }; block[0] = (struct Char4) { .ch = '[', .color.fg = fg };
block[1] = (struct Char4) { .ch = ']', .color.fg = fg }; block[1] = (struct Char4) { .ch = ']', .color.fg = fg };
} }
} }
} }
void TetraOverlay(struct Tetra *piece, struct Tetra *board)
{
usize i = 0;
for (usize y = piece->y; y < piece->y + piece->hgt; y++) {
for (usize x = piece->x; x < piece->x + piece->wid; x++, i++) {
if(piece->blks[i] == 0)
continue;
if(x < 0 or x >= board->wid or y < 0 or y >= board->hgt)
continue;
board->blks[board->wid * y + x] = piece->blks[i];
}
}
}

View file

@ -4,6 +4,13 @@
#include "terminal.h" #include "terminal.h"
struct TetraTemplate {
u8 *blks;
usize wid;
usize hgt;
};
struct Tetra { struct Tetra {
u8 *blks; u8 *blks;
@ -12,30 +19,23 @@ struct Tetra {
i16 x; i16 x;
i16 y; i16 y;
u8 rot;
u8f rot;
}; };
struct TetraTemplate { bool CreateTetra(struct Tetra *tetra, u16 wid, u16 hgt);
u8 *blks;
u16 wid; void FreeTetra(struct Tetra *tetra);
u16 hgt;
};
void TetraSet(struct Tetra *tetra, struct TetraTemplate *template);
bool CreateTetra(struct Tetra *map, u16 wid, u16 hgt); bool TetraIsCollision(struct Tetra *t, struct Tetra *board);
void FreeTetra(struct Tetra *map); bool TetraMove(struct Tetra *t, struct Tetra *board, i16 dx, i16 dy);
void SetTetra(struct Tetra *map, struct TetraTemplate *t, i16 x, i16 y); bool TetraRotate(struct Tetra *t, struct Tetra *board, i8 dr);
void TetraOverlay(struct Tetra *t, struct Tetra *board);
void TetraTerminalClear(struct Tetra *board, struct Terminal *term); void TetraTerminalClear(struct Tetra *board, struct Terminal *term);
void TetraTerminalDraw(struct Tetra *map, struct Terminal *term); void TetraTerminalDraw(struct Tetra *t, struct Terminal *term);
bool TetraMove(struct Tetra *piece, struct Tetra *board, i16 dx, i16 dy);
bool TetraIsCollision(struct Tetra *piece, struct Tetra *board, i16 dx, i16 dy);
void TetraOverlay(struct Tetra *piece, struct Tetra *board);