+struct curated_ruleset {
+ uint8_t rule;
+ enum seed_population seed;
+};
+
+static const struct curated_ruleset curated_ruleset_list[] = {
+ { 18, middle_cell},
+ { 30, middle_cell},
+ { 45, middle_cell},
+ { 54, middle_cell},
+ { 57, middle_cell},
+ { 73, middle_cell},
+ {105, middle_cell},
+ {109, middle_cell},
+ {129, middle_cell},
+ {133, middle_cell},
+ {135, middle_cell},
+ {150, middle_cell},
+ { 30, edge_cell},
+ { 45, edge_cell},
+ { 57, edge_cell},
+ { 60, edge_cell},
+ { 75, edge_cell},
+ {107, edge_cell},
+ {110, edge_cell},
+ {133, edge_cell},
+ {137, edge_cell},
+ {169, edge_cell},
+ {225, edge_cell},
+ { 22, random_cell},
+ { 30, random_cell},
+ { 54, random_cell},
+ { 62, random_cell},
+ { 90, random_cell},
+ {105, random_cell},
+ {108, random_cell},
+ {110, random_cell},
+ {126, random_cell},
+ {146, random_cell},
+ {150, random_cell},
+ {182, random_cell},
+ {184, random_cell},
+ {225, random_cell},
+ {240, random_cell}
+};
+
+struct color_pair {
+ /* The type 'unsigned short' comes from the XColor struct definition, */
+ /* reproduced below. */
+ /* */
+ /* typedef struct { */
+ /* unsigned long pixel; */
+ /* unsigned short red, green, blue; */
+ /* char flags; */
+ /* char pad; */
+ /* } XColor; */
+ /* */
+ /* The red, green, and blue values are always in the range 0 to 65535 */
+ /* inclusive, independent of the number of bits actually used in the */
+ /* display hardware. The server scales these values to the range used */
+ /* by the hardware. Black is represented by (0,0,0), and white is */
+ /* represented by (65535,65535,65535). */
+ unsigned short fg_red, fg_green, fg_blue;
+ unsigned short bg_red, bg_green, bg_blue;
+};
+
+static const struct color_pair color_list[] = {
+ /* For mapping X11 color names to RGB values: */
+ /* https://www.ehdp.com/methods/x11-color-names-rgb-values.htm */
+ /* Remember that our values range from 0-65535 inclusive, so scale the */
+ /* usual 0-255 range accordingly. */
+ /* */
+ /* +---------------------------------------+ */
+ /* | foreground | | background | */
+ /* | red,green,blue | | red,green,blue | */
+ {65535, 0, 0, 0, 0, 0}, /* {"red", "black"}, */
+ {32767,32767, 0, 0, 0, 0}, /* {"olive", "black"}, */
+ { 0,32767,32767, 0, 0, 0}, /* {"teal", "black"}, */
+ {27524,22937,52428, 0, 0, 0}, /* {"slateblue", "black"}, */
+ {60947,33422,60947, 0, 0, 0}, /* {"violet", "black"}, */
+ {41287, 8519,61602, 0, 0, 0}, /* {"purple", "black"}, */
+ {65535,65535,65535, 0, 0, 0}, /* {"white", "black"}, */
+ {65535,65535,65535, 0,25558, 0}, /* {"white", "darkgreen"}, */
+ {65535,65535,65535, 36044, 0,36044}, /* {"white", "darkmagenta"}, */
+ {65535,65535,65535, 36044, 0, 0}, /* {"white", "darkred"}, */
+ {65535,65535,65535, 0, 0,36044}, /* {"white", "darkblue"}, */
+ {11796,20315,20315, 36494,65535,65535}, /* {"darkslategray", "darkslategray1"}, */
+ {45219,50461,57015, 11796,20315,20315}, /* {"lightsteelblue", "darkslategray"}, */
+ {10023,16448,35723, 16383,26869,57670}, /* {"royalblue4", "royalblue"}, */
+ {61166,57311,52428, 35723,33667,30840}, /* {"antiquewhite2", "antiquewhite4"}, */
+ {51914,65535,28784, 21626,27524,11796}, /* {"darkolivegreen1", "darkolivegreen"}, */
+ {49601,65535,49601, 26985,35723,26985}, /* {"darkseagreen1", "darkseagreen4"}, */
+ {65535,49151,52428, 36044, 0, 0}, /* {"pink", "darkred"}, */
+ {44563,55704,58981, 0,25558, 0}, /* {"lightblue", "darkgreen"}, */
+ {65535, 0, 0, 0, 0,65535}, /* {"red", "blue"}, */
+ {65535, 0, 0, 0,25558, 0}, /* {"red", "darkgreen"}, */
+ { 0,65535,65535, 0,32767,32767}, /* {"aqua", "teal"}, */
+ { 0, 0,36044, 0,32767,32767}, /* {"darkblue", "teal"}, */
+ {61602,58981,32767, 11796,36044,22281}, /* {"khaki", "seagreen"}, */
+ {61602,58981,32767, 21626,27524,11796}, /* {"khaki", "darkolivegreen"}, */
+ {30801,34733,39321, 11796,20315,20315}, /* {"lightslategray", "darkslategray"}, */
+ {65535,25558,18349, 11796,20315,20315}, /* {"tomato", "darkslategray"}, */
+ {65535,25558,18349, 0,36044,36044} /* {"tomato", "darkcyan"} */
+};
+
+/* -------------------------------------------------------------------------- */
+/* Helper Functions */
+/* -------------------------------------------------------------------------- */
+
+static void
+generate_random_seed(struct state * state)
+{
+ int i;
+ for (i = 0; i < state->number_of_cells; i++) {
+ state->current_generation[i] = ((random() % 100) < state->population_density) ? True : False;
+ }
+}
+
+/* This function sanitizes the index used to access cells in a generation. */
+/* Specifically, it wraps the index, creating a circular universe for the */
+/* cells and ensuring every cell has two neighbors. */
+static size_t
+sindex(struct state * state, int index)
+{
+ while (index < 0) {
+ index += state->number_of_cells;
+ }
+ while (index >= state->number_of_cells) {
+ index -= state->number_of_cells;
+ }
+ return (size_t) index;
+}
+
+/* For more information on the encoding used for state->rule_number and on */
+/* the method used to apply it: https://en.wikipedia.org/wiki/Wolfram_code */
+static Bool
+calculate_cell(struct state * state, int cell_id)
+{
+ uint8_t cell_pattern = 0;
+ int i;
+ for (i = -1; i < 2; i++) {
+ cell_pattern = cell_pattern << 1;
+ if (state->current_generation[sindex(state, cell_id+i)] == True) {
+ cell_pattern |= 1;
+ }
+ }
+ if ((state->rule_number >> cell_pattern) & 1) {
+ return True;
+ } else {
+ return False;
+ }
+}
+
+static void
+render_current_generation(struct state * state)
+{
+ size_t xpos;
+ for (xpos = 0; xpos < state->number_of_cells; xpos++) {
+ if (state->current_generation[xpos] == True) {
+ XFillRectangle(state->dpy, state->evolution_history, state->gc, xpos*state->cell_size, state->ypos, state->cell_size, state->cell_size);
+ } else {
+ XSetForeground(state->dpy, state->gc, state->bg);
+ XFillRectangle(state->dpy, state->evolution_history, state->gc, xpos*state->cell_size, state->ypos, state->cell_size, state->cell_size);
+ XSetForeground(state->dpy, state->gc, state->fg);
+ }
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+/* Screenhack API Functions */
+/* -------------------------------------------------------------------------- */
+
+static Bool
+WolframAutomata_event(Display * dpy, Window win, void * closure, XEvent * event)
+{
+ return False;
+}
+
+static void
+WolframAutomata_free(Display * dpy, Window win, void * closure)
+{
+ struct state * state = closure;
+ XFreeGC(state->dpy, state->gc);
+ XFreePixmap(state->dpy, state->evolution_history);
+ free(state->current_generation);
+ free(state);
+}
+