-/* (c) 2021 Aaron Taylor <ataylor at subgeniuskitty dot com> */
-/* See LICENSE.txt file for copyright and license details. */
+/* (c) 2021 Aaron Taylor <ataylor at subgeniuskitty dot com> */
+/* See LICENSE.txt file for copyright and license details. */
#include "screenhack.h"
+/* Keep this source code C89 compliant per XScreensaver's instructions. */
+
/* -------------------------------------------------------------------------- */
/* Data Structures */
/* -------------------------------------------------------------------------- */
enum seed_population seed;
};
+/* The following array contains rule numbers and starting seeds which were */
+/* preselected as being visually interesting. */
static const struct curated_ruleset curated_ruleset_list[] = {
{ 18, middle_cell},
{ 30, middle_cell},
unsigned short bg_red, bg_green, bg_blue;
};
+/* Since randomly selected colors would occasionally produce visually */
+/* indistinguishable foreground/background pairs, this array provides a */
+/* preselected list of complementary color pairs. */
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 */
/* Helper Functions */
/* -------------------------------------------------------------------------- */
+/* Some rules demonstrate behavior dominated by the starting seed. Thus, in */
+/* addition to a 50/50 random split of active/inactive cells, include other, */
+/* more biased random distributions in order to demonstrate such behavior. */
static void
randomize_seed_density(struct state * state)
{
static void *
WolframAutomata_init(Display * dpy, Window win)
{
- struct state * state = calloc(1, sizeof(*state));
+ struct state * state;
+ XGCValues gcv;
+ XWindowAttributes xgwa;
+ XColor fg, bg;
+ XColor blackx, blacks;
+ size_t color_index;
+ const struct curated_ruleset * curated_ruleset = NULL;
+
+ state = calloc(1, sizeof(*state));
if (!state) {
fprintf(stderr, "ERROR: Failed to calloc() for state struct in WolframAutomata_init().\n");
exit(EXIT_FAILURE);
}
- XGCValues gcv;
- XWindowAttributes xgwa;
- const struct curated_ruleset * curated_ruleset = NULL;
-
state->dpy = dpy;
state->win = win;
/* Set foreground and background colors for active/inactive cells. Either */
/* the user provided an index into the pre-defined color_list[] or a */
/* random entry from that same array should be selected. */
- size_t color_index = get_integer_resource(state->dpy, "color-index", "Integer");
+ color_index = get_integer_resource(state->dpy, "color-index", "Integer");
if (color_index == -1) {
color_index = random() % sizeof(color_list)/sizeof(color_list[0]);
} else if (color_index >= sizeof(color_list)/sizeof(color_list[0])) {
fprintf(stderr, "WARNING: Color index out of range.\n");
color_index = 0;
}
- XColor fg, bg;
fg.red = color_list[color_index].fg_red;
fg.green = color_list[color_index].fg_green;
fg.blue = color_list[color_index].fg_blue;
bg.red = color_list[color_index].bg_red;
bg.green = color_list[color_index].bg_green;
bg.blue = color_list[color_index].bg_blue;
- /* TODO: Since I 'alloc', presumably I must also 'free' these colors */
- /* at some point. Where/how? I don't want to eventually crash my */
- /* X server after months of use. */
XAllocColor(state->dpy, xgwa.colormap, &fg);
XAllocColor(state->dpy, xgwa.colormap, &bg);
state->fg = gcv.foreground = fg.pixel;
state->evolution_history = XCreatePixmap(state->dpy, state->win, state->dpy_width, state->num_generations*state->cell_size, xgwa.depth);
/* Pixmap contents are undefined after creation. Explicitly set a black */
/* background by drawing a black rectangle over the entire pixmap. */
- XColor blackx, blacks;
XAllocNamedColor(state->dpy, DefaultColormapOfScreen(DefaultScreenOfDisplay(state->dpy)), "black", &blacks, &blackx);
XSetForeground(state->dpy, state->gc, blacks.pixel);
XFillRectangle(state->dpy, state->evolution_history, state->gc, 0, 0, state->dpy_width, state->num_generations*state->cell_size);
int window_y_offset;
/* Calculate and record new generation. */
- Bool new_generation[state->dpy_width];
+ Bool * new_generation = malloc(state->dpy_width * sizeof(Bool));
+ if (new_generation == NULL) {
+ fprintf(stderr, "ERROR: Failed to malloc() when calculating new generation.\n");
+ exit(EXIT_FAILURE);
+ }
for (xpos = 0; xpos < state->number_of_cells; xpos++) {
new_generation[xpos] = calculate_cell(state, xpos);
}
for (xpos = 0; xpos < state->number_of_cells; xpos++) {
state->current_generation[xpos] = new_generation[xpos];
}
+ free(new_generation);
render_current_generation(state);
/* Check for end of simulation. */
return state->delay_microsec;
}
+static void
+WolframAutomata_reshape(Display * dpy, Window win, void * closure, unsigned int w, unsigned int h)
+{
+ struct state * state = closure;
+ XWindowAttributes xgwa;
+ XGetWindowAttributes(state->dpy, state->win, &xgwa);
+
+ /* Only restart the simulation if the window changed size. */
+ if (state->dpy_width != xgwa.width || state->dpy_height != xgwa.height) {
+ WolframAutomata_free(dpy, win, closure);
+ closure = WolframAutomata_init(dpy, win);
+ }
+}
+
static const char * WolframAutomata_defaults[] = {
- "*delay: 25000",
"*admiration-delay: 5",
- "*length: 5000",
- "*cell-size: 2",
+
"*color-index: -1",
- "*seed-density: -1",
- "*seed-left: False",
- "*seed-center: False",
- "*seed-right: False",
+
+ "*cell-size: 2",
"*random-cell-size: False",
+
+ "*delay: 25000",
"*random-delay: False",
+
+ "*length: 5000",
"*random-length: False",
- "*random-rule: False",
+
"*rule: -1",
+ "*random-rule: False",
+
+ "*seed-density: -1",
+ "*seed-left: False",
+ "*seed-center: False",
+ "*seed-right: False",
+
0
};
static XrmOptionDescRec WolframAutomata_options[] = {
- { "-delay", ".delay", XrmoptionSepArg, 0 },
{ "-admiration-delay", ".admiration-delay", XrmoptionSepArg, 0 },
- { "-length", ".length", XrmoptionSepArg, 0 },
- { "-cell-size", ".cell-size", XrmoptionSepArg, 0 },
+
{ "-color-index", ".color-index", XrmoptionSepArg, 0 },
- { "-seed-density", ".seed-density", XrmoptionSepArg, 0 },
- { "-seed-left", ".seed-left", XrmoptionNoArg, "True" },
- { "-seed-center", ".seed-center", XrmoptionNoArg, "True" },
- { "-seed-right", ".seed-right", XrmoptionNoArg, "True" },
+
+ { "-cell-size", ".cell-size", XrmoptionSepArg, 0 },
{ "-random-cell-size", ".random-cell-size", XrmoptionNoArg, "True" },
+
+ { "-delay", ".delay", XrmoptionSepArg, 0 },
{ "-random-delay", ".random-delay", XrmoptionNoArg, "True" },
+
+ { "-length", ".length", XrmoptionSepArg, 0 },
{ "-random-length", ".random-length", XrmoptionNoArg, "True" },
- { "-random-rule", ".random-rule", XrmoptionNoArg, "True" },
+
{ "-rule", ".rule", XrmoptionSepArg, 0 },
- { 0, 0, 0, 0 }
-};
+ { "-random-rule", ".random-rule", XrmoptionNoArg, "True" },
-static void
-WolframAutomata_reshape(Display * dpy, Window win, void * closure, unsigned int w, unsigned int h)
-{
- struct state * state = closure;
- XWindowAttributes xgwa;
- XGetWindowAttributes(state->dpy, state->win, &xgwa);
+ { "-seed-density", ".seed-density", XrmoptionSepArg, 0 },
+ { "-seed-left", ".seed-left", XrmoptionNoArg, "True" },
+ { "-seed-center", ".seed-center", XrmoptionNoArg, "True" },
+ { "-seed-right", ".seed-right", XrmoptionNoArg, "True" },
- /* Only restart the simulation if the window changed size. */
- if (state->dpy_width != xgwa.width || state->dpy_height != xgwa.height) {
- WolframAutomata_free(dpy, win, closure);
- closure = WolframAutomata_init(dpy, win);
- }
-}
+ { 0, 0, 0, 0 }
+};
XSCREENSAVER_MODULE ("1D Nearest-Neighbor Cellular Automata", WolframAutomata)