From b7c1fcf41180a32faad0f3df161c231eb6390e57 Mon Sep 17 00:00:00 2001 From: Benjamin Winston Date: Thu, 19 Jun 2025 22:04:11 -0400 Subject: ytz -> yhtz --- Makefile | 2 +- yhtz.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ytz.c | 175 --------------------------------------------------------------- 3 files changed, 176 insertions(+), 176 deletions(-) create mode 100644 yhtz.c delete mode 100644 ytz.c diff --git a/Makefile b/Makefile index b4fd173..cfe591b 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,2 @@ debug: - cc -g ytz.c + cc -g -o yhtz yhtz.c diff --git a/yhtz.c b/yhtz.c new file mode 100644 index 0000000..cf556db --- /dev/null +++ b/yhtz.c @@ -0,0 +1,175 @@ +#include +#include +#include + +/* + 0000 0000 0000 0000 0000 0000 0000 0000 + rc topscore botflag. botscore. + topflag x x + + 0000 0000 0000 0000 0000 0000 0000 0000 + xd4. d3.d 2.d1 .d0. prng state.... .... +*/ + +typedef struct { + uint8_t topflag_w_roll; + uint8_t topscore; + uint8_t botflag; + uint8_t botscore; + uint16_t dice; + uint16_t seed; +} yhtz_state; + +/* ROLLS */ +#define GET_ROLL(s) ((uint8_t)((s & 0xC0) >> 6)) /* top 2 bits */ +#define SET_ROLL(s, x) (s & 0x3F | ((uint8_t)x << 6)) + +/* TOP NUMBERS */ +#define GET_NUM(s, x) ((uint8_t)((s & (1 << x)) >> x)) +#define GET_ACE(s) (GET_NUM(s, 0)) +#define GET_TWO(s) (GET_NUM(s, 1)) +#define GET_THREE(s) (GET_NUM(s, 2)) +#define GET_FOUR(s) (GET_NUM(s, 3)) +#define GET_FIVE(s) (GET_NUM(s, 4)) +#define GET_SIX(s) (GET_NUM(s, 5)) + +#define SET_NUM(s, x) (s | (1 << x)) +#define SET_ACE(s) (SET_NUM(s, 0)) +#define SET_TWO(s) (SET_NUM(s, 1)) +#define SET_THREE(s) (SET_NUM(s, 2)) +#define SET_FOUR(s) (SET_NUM(s, 3)) +#define SET_FIVE(s) (SET_NUM(s, 4)) +#define SET_SIX(s) (SET_NUM(s, 5)) + +/* DICE */ +#define GET_D(s, x) ((uint8_t)((s & (0x07 << (3 * x))) >> (3 * x))) +#define GET_D0(s) (GET_D(s, 0)) +#define GET_D1(s) (GET_D(s, 1)) +#define GET_D2(s) (GET_D(s, 2)) +#define GET_D3(s) (GET_D(s, 3)) +#define GET_D4(s) (GET_D(s, 4)) + +#define SET_D(s, x, y) (s & (0xFFFF ^ (0x0007 << (3 * x))) | (y << (3 * x))) +#define SET_D0(s, y) (SET_D(s, 0, y)) +#define SET_D1(s, y) (SET_D(s, 1, y)) +#define SET_D2(s, y) (SET_D(s, 2, y)) +#define SET_D3(s, y) (SET_D(s, 3, y)) +#define SET_D4(s, y) (SET_D(s, 4, y)) + +/* 16-bit prng, with thanks/apologies to Dr. Lemire (https://lemire.me/blog/2019/07/03/a-fast-16-bit-random-number-generator/) */ +uint32_t hash16(uint32_t input, uint32_t key) { + uint32_t hash = input * key; + return ((hash >> 16) ^ hash) & 0xFFFF; +} + +uint16_t wyhash16(uint16_t* seed) { + *seed += 0xfc15; + return hash16(*seed, 0x2ab); +} + +uint16_t roll_die(uint16_t* seed) { + const uint16_t s = 6; /* generating in the range of [0,6) */ + uint16_t x = wyhash16(seed); + uint32_t m = (uint32_t)x * (uint32_t)s; + uint32_t l = (uint16_t)m; + if (l < s) { + uint16_t t = -s % s; + while (l < t) { + x = wyhash16(seed); + m = (uint32_t)x * (uint32_t)s; + l = (uint16_t)m; + } + } + return (m >> 16) + 1; /* we ultimately want [1,7) */ +} + +void print_dice(yhtz_state* state) { + char* label = "die %d "; + char* top = ",---,"; + char* mid = "| %d | "; + char* bot = "'---'"; + + for (int i = 0; i < 5; i++) + printf(label, i); + printf("\n%s %s %s %s %s\n", top, top, top, top, top); + for (int i = 0; i < 5; i++) + printf(mid, GET_D(state->dice, i)); + printf("\n%s %s %s %s %s\n", bot, bot, bot, bot, bot); +} + +void ask_for_rerolls(yhtz_state* state) { + char buf[10]; + printf("which dice should be re-rolled? "); + fgets(buf, sizeof(buf), stdin); + + int dice[6] = { -1, -1, -1, -1, -1, -1 }; /* we only ever look for 5 dice, so should always hit -1 at some point */ + sscanf(buf, "%d %d %d %d %d", &dice[0], &dice[1], &dice[2], &dice[3], &dice[4]); + + for (int i = 0; i < 5; i++) { + if (dice[i] == -1) + break; + state->dice = SET_D(state->dice, dice[i], 0); + } +} + +void do_turn(yhtz_state* state) { + int roll = GET_ROLL(state->topflag_w_roll); + bool reset = false; + + // if we're out of rolls, reset + if (roll == 3) { + reset = true; + roll = 0; + } + + for (int i = 0; i < 5; i++) { + if (reset || (GET_D(state->dice, i) == 0)) { + state->dice = SET_D(state->dice, i, roll_die(&(state->seed))); + } + } + state->topflag_w_roll = SET_ROLL(state->topflag_w_roll, ++roll); +} + +void init_yhtz_state(yhtz_state* state) { + state->topflag_w_roll = 0; + state->topscore = 0; + state->botflag = 0; + state->botscore = 0; + state->dice = 0; + state->seed = 13; /* TODO this isn't random */ +} + +void main() { + yhtz_state y; + init_yhtz_state(&y); + + /* + * until the win condition is met + * - roll all dice + * - up to 2 times, ask user which dice to reroll + * - ask user which category to mark it in + * - validate and update state + * + * + */ + + do_turn(&y); + + printf("new roll: %d\n", GET_ROLL(y.topflag_w_roll)); + printf("new d1: %d\n", GET_D0(y.dice)); + printf("new d2: %d\n", GET_D1(y.dice)); + printf("new d3: %d\n", GET_D2(y.dice)); + printf("new d4: %d\n", GET_D3(y.dice)); + printf("new d5: %d\n", GET_D4(y.dice)); + + print_dice(&y); + + ask_for_rerolls(&y); + do_turn(&y); + printf("newer roll: %d\n", GET_ROLL(y.topflag_w_roll)); + printf("newer d1: %d\n", GET_D0(y.dice)); + printf("newer d2: %d\n", GET_D1(y.dice)); + printf("newer d3: %d\n", GET_D2(y.dice)); + printf("newer d4: %d\n", GET_D3(y.dice)); + printf("newer d5: %d\n", GET_D4(y.dice)); +} diff --git a/ytz.c b/ytz.c deleted file mode 100644 index 6b8968b..0000000 --- a/ytz.c +++ /dev/null @@ -1,175 +0,0 @@ -#include -#include -#include - -/* - 0000 0000 0000 0000 0000 0000 0000 0000 - rc topscore botflag. botscore. - topflag x x - - 0000 0000 0000 0000 0000 0000 0000 0000 - xd4. d3.d 2.d1 .d0. prng state.... .... -*/ - -typedef struct { - uint8_t topflag_w_roll; - uint8_t topscore; - uint8_t botflag; - uint8_t botscore; - uint16_t dice; - uint16_t seed; -} ytz_state; - -/* ROLLS */ -#define GET_ROLL(s) ((uint8_t)((s & 0xC0) >> 6)) /* top 2 bits */ -#define SET_ROLL(s, x) (s & 0x3F | ((uint8_t)x << 6)) - -/* TOP NUMBERS */ -#define GET_NUM(s, x) ((uint8_t)((s & (1 << x)) >> x)) -#define GET_ACE(s) (GET_NUM(s, 0)) -#define GET_TWO(s) (GET_NUM(s, 1)) -#define GET_THREE(s) (GET_NUM(s, 2)) -#define GET_FOUR(s) (GET_NUM(s, 3)) -#define GET_FIVE(s) (GET_NUM(s, 4)) -#define GET_SIX(s) (GET_NUM(s, 5)) - -#define SET_NUM(s, x) (s | (1 << x)) -#define SET_ACE(s) (SET_NUM(s, 0)) -#define SET_TWO(s) (SET_NUM(s, 1)) -#define SET_THREE(s) (SET_NUM(s, 2)) -#define SET_FOUR(s) (SET_NUM(s, 3)) -#define SET_FIVE(s) (SET_NUM(s, 4)) -#define SET_SIX(s) (SET_NUM(s, 5)) - -/* DICE */ -#define GET_D(s, x) ((uint8_t)((s & (0x07 << (3 * x))) >> (3 * x))) -#define GET_D0(s) (GET_D(s, 0)) -#define GET_D1(s) (GET_D(s, 1)) -#define GET_D2(s) (GET_D(s, 2)) -#define GET_D3(s) (GET_D(s, 3)) -#define GET_D4(s) (GET_D(s, 4)) - -#define SET_D(s, x, y) (s & (0xFFFF ^ (0x0007 << (3 * x))) | (y << (3 * x))) -#define SET_D0(s, y) (SET_D(s, 0, y)) -#define SET_D1(s, y) (SET_D(s, 1, y)) -#define SET_D2(s, y) (SET_D(s, 2, y)) -#define SET_D3(s, y) (SET_D(s, 3, y)) -#define SET_D4(s, y) (SET_D(s, 4, y)) - -/* 16-bit prng, with thanks/apologies to Dr. Lemire (https://lemire.me/blog/2019/07/03/a-fast-16-bit-random-number-generator/) */ -uint32_t hash16(uint32_t input, uint32_t key) { - uint32_t hash = input * key; - return ((hash >> 16) ^ hash) & 0xFFFF; -} - -uint16_t wyhash16(uint16_t* seed) { - *seed += 0xfc15; - return hash16(*seed, 0x2ab); -} - -uint16_t roll_die(uint16_t* seed) { - const uint16_t s = 6; /* generating in the range of [0,6) */ - uint16_t x = wyhash16(seed); - uint32_t m = (uint32_t)x * (uint32_t)s; - uint32_t l = (uint16_t)m; - if (l < s) { - uint16_t t = -s % s; - while (l < t) { - x = wyhash16(seed); - m = (uint32_t)x * (uint32_t)s; - l = (uint16_t)m; - } - } - return (m >> 16) + 1; /* we ultimately want [1,7) */ -} - -void print_dice(ytz_state* state) { - char* label = "die %d "; - char* top = ",---,"; - char* mid = "| %d | "; - char* bot = "'---'"; - - for (int i = 0; i < 5; i++) - printf(label, i); - printf("\n%s %s %s %s %s\n", top, top, top, top, top); - for (int i = 0; i < 5; i++) - printf(mid, GET_D(state->dice, i)); - printf("\n%s %s %s %s %s\n", bot, bot, bot, bot, bot); -} - -void ask_for_rerolls(ytz_state* state) { - char buf[10]; - printf("which dice should be re-rolled? "); - fgets(buf, sizeof(buf), stdin); - - int dice[6] = { -1, -1, -1, -1, -1, -1 }; /* we only ever look for 5 dice, so should always hit -1 at some point */ - sscanf(buf, "%d %d %d %d %d", &dice[0], &dice[1], &dice[2], &dice[3], &dice[4]); - - for (int i = 0; i < 5; i++) { - if (dice[i] == -1) - break; - state->dice = SET_D(state->dice, dice[i], 0); - } -} - -void do_turn(ytz_state* state) { - int roll = GET_ROLL(state->topflag_w_roll); - bool reset = false; - - // if we're out of rolls, reset - if (roll == 3) { - reset = true; - roll = 0; - } - - for (int i = 0; i < 5; i++) { - if (reset || (GET_D(state->dice, i) == 0)) { - state->dice = SET_D(state->dice, i, roll_die(&(state->seed))); - } - } - state->topflag_w_roll = SET_ROLL(state->topflag_w_roll, ++roll); -} - -void init_ytz_state(ytz_state* state) { - state->topflag_w_roll = 0; - state->topscore = 0; - state->botflag = 0; - state->botscore = 0; - state->dice = 0; - state->seed = 13; /* TODO this isn't random */ -} - -void main() { - ytz_state y; - init_ytz_state(&y); - - /* - * until the win condition is met - * - roll all dice - * - up to 2 times, ask user which dice to reroll - * - ask user which category to mark it in - * - validate and update state - * - * - */ - - do_turn(&y); - - printf("new roll: %d\n", GET_ROLL(y.topflag_w_roll)); - printf("new d1: %d\n", GET_D0(y.dice)); - printf("new d2: %d\n", GET_D1(y.dice)); - printf("new d3: %d\n", GET_D2(y.dice)); - printf("new d4: %d\n", GET_D3(y.dice)); - printf("new d5: %d\n", GET_D4(y.dice)); - - print_dice(&y); - - ask_for_rerolls(&y); - do_turn(&y); - printf("newer roll: %d\n", GET_ROLL(y.topflag_w_roll)); - printf("newer d1: %d\n", GET_D0(y.dice)); - printf("newer d2: %d\n", GET_D1(y.dice)); - printf("newer d3: %d\n", GET_D2(y.dice)); - printf("newer d4: %d\n", GET_D3(y.dice)); - printf("newer d5: %d\n", GET_D4(y.dice)); -} -- cgit v1.2.3