Added CLI options for requesting a specific rule, random rules, or random curated...
authorAaron Taylor <ataylor@subgeniuskitty.com>
Sun, 14 Mar 2021 10:46:41 +0000 (03:46 -0700)
committerAaron Taylor <ataylor@subgeniuskitty.com>
Sun, 14 Mar 2021 10:46:41 +0000 (03:46 -0700)
Also bumped up the default delay by 10x.

hacks/WolframAutomata/WolframAutomata.c

index 1327532..33182e1 100644 (file)
 //        display info overlay with CA number and start conditions?
 //              -overlay
 //        which ruleset number to use? Or random? Or random from small set of hand-selected interesting examples?
 //        display info overlay with CA number and start conditions?
 //              -overlay
 //        which ruleset number to use? Or random? Or random from small set of hand-selected interesting examples?
-//              Options (with precedence): -rule N
-//                                         -rule-curated
-//                                         -rule-random
+//              In order of precedence:
+//                  -random (select a random rule on each run)
+//                  -rule N (always simulate Rule N on each run)
+//                  (if neither of the above two are specified, then a random CURATED rule is selected on each run)
 //        which starting population to use? Or random? Or one bit in middle? Or one bit on edge?  (For random: Can I allow specifying a density like 25%, 50%, 75%?)
 //              Options (with precedence): -population STRING   (string is a comma separated list of cell IDs to populate, starting from 0)
 //                                         -population-curated
 //        which starting population to use? Or random? Or one bit in middle? Or one bit on edge?  (For random: Can I allow specifying a density like 25%, 50%, 75%?)
 //              Options (with precedence): -population STRING   (string is a comma separated list of cell IDs to populate, starting from 0)
 //                                         -population-curated
@@ -54,7 +55,11 @@ struct state {
     Bool display_info;
 
     Bool * current_generation;
     Bool display_info;
 
     Bool * current_generation;
-    uint8_t ruleset;
+
+    // TODO: Describe these.
+    uint8_t rule_number;  // Note: This is not a CLI option. You're thinking of rule_requested.
+    uint8_t rule_requested; // Note: Repurposing Rule 0 as a null value.
+    Bool rule_random;
 
     /* Misc Commandline Options */
     int pixel_size; /* Size of CA cell in pixels (e.g. pixel_size=3 means 3x3 pixels per cell). */
 
     /* Misc Commandline Options */
     int pixel_size; /* Size of CA cell in pixels (e.g. pixel_size=3 means 3x3 pixels per cell). */
@@ -65,6 +70,16 @@ struct state {
     size_t number_of_cells;
 };
 
     size_t number_of_cells;
 };
 
+// TODO: Check the full set of 256 CAs for visually interesting examples.
+static const uint8_t curated_rule_list[] = {
+    22,
+    30,
+    45,
+    57,
+    73,
+    86
+};
+
 static void *
 WolframAutomata_init(Display * dpy, Window win)
 {
 static void *
 WolframAutomata_init(Display * dpy, Window win)
 {
@@ -93,18 +108,38 @@ WolframAutomata_init(Display * dpy, Window win)
 
     state->number_of_cells = state->xlim / state->pixel_size;
 
 
     state->number_of_cells = state->xlim / state->pixel_size;
 
-    /*
-     * The minimum number of generations is 2 since we must allocate enough
-     * space to hold the seed generation and at least one pass through
-     * WolframAutomata_draw(), which is where we check whether or not we've
-     * reached the end of the pixmap.
-     */
+    /* The minimum number of generations is 2 since we must allocate enough   */
+    /* space to hold the seed generation and at least one pass through        */
+    /* WolframAutomata_draw(), which is where we check whether or not we've   */
+    /* reached the end of the pixmap.                                         */
     state->num_generations = get_integer_resource(state->dpy, "num-generations", "Integer");
     if (state->num_generations < 0) state->num_generations = 2;
 
     state->num_generations = get_integer_resource(state->dpy, "num-generations", "Integer");
     if (state->num_generations < 0) state->num_generations = 2;
 
+    /* Time to figure out which rule to use for this simulation.              */
+    /* We ignore any weirdness resulting from the following cast since every  */
+    /* bit pattern is also a valid rule; if the user provides weird input,    */
+    /* then we'll return weird (but well-defined!) output.                    */
+    state->rule_requested = (uint8_t) get_integer_resource(state->dpy, "rule-requested", "Integer");
+    state->rule_random = get_boolean_resource(state->dpy, "rule-random", "Boolean");
+    /* Through the following set of branches, we enforce CLI flag precedence. */
+    if (state->rule_random) {
+        /* If this flag is set, the user wants truly random rules rather than */
+        /* random rules from a curated list.                                  */
+        state->rule_number = (uint8_t) random();
+    } else if (state->rule_requested != 0) {
+        /* Rule 0 is terribly uninteresting, so we are reusing it as a 'null' */
+        /* value and hoping nobody notices. Finding a non-zero value means    */
+        /* the user requested a specific rule. Use it.                        */
+        state->rule_number = state->rule_requested;
+    } else {
+        /* No command-line options were specified, so select rules randomly   */
+        /* from a curated list.                                               */
+        size_t number_of_array_elements = sizeof(curated_rule_list)/sizeof(curated_rule_list[0]);
+        state->rule_number = curated_rule_list[random() % number_of_array_elements];
+    }
+
     // TODO: These should be command-line options, but I need to learn how the get_integer_resource() and similar functions work first.
     state->display_info = True;
     // TODO: These should be command-line options, but I need to learn how the get_integer_resource() and similar functions work first.
     state->display_info = True;
-    state->ruleset = 30;
 
     state->current_generation = calloc(1, (sizeof(*(state->current_generation))*state->number_of_cells)); // TODO: Check calloc() call TODO: Can't recall precedence; can I eliminate any parenthesis?
     // TODO: Make the starting state a user-configurable option. At least give the user some options like 'random', 'one-middle', 'one edge', etc.
 
     state->current_generation = calloc(1, (sizeof(*(state->current_generation))*state->number_of_cells)); // TODO: Check calloc() call TODO: Can't recall precedence; can I eliminate any parenthesis?
     // TODO: Make the starting state a user-configurable option. At least give the user some options like 'random', 'one-middle', 'one edge', etc.
@@ -149,7 +184,7 @@ calculate_cell(struct state * state, int cell_id)
             cell_pattern |= 1;
         }
     }
             cell_pattern |= 1;
         }
     }
-    if ((state->ruleset >> cell_pattern) & 1) {
+    if ((state->rule_number >> cell_pattern) & 1) {
         return True;
     } else {
         return False;
         return True;
     } else {
         return False;
@@ -224,10 +259,12 @@ WolframAutomata_draw(Display * dpy, Window win, void * closure)
 static const char * WolframAutomata_defaults[] = {
     ".background:    black",
     ".foreground:    white",
 static const char * WolframAutomata_defaults[] = {
     ".background:    black",
     ".foreground:    white",
-    "*delay-usec:    2500",
+    "*delay-usec:    25000",
     // TODO: Difference between dot and asterisk? Presumably the asterisk matches all resouces of attribute "pixelsize"? Apply answer to all new options.
     "*pixel-size:    2",
     "*num-generations:    5000",
     // TODO: Difference between dot and asterisk? Presumably the asterisk matches all resouces of attribute "pixelsize"? Apply answer to all new options.
     "*pixel-size:    2",
     "*num-generations:    5000",
+    "*rule-requested:    0",
+    "*rule-random:    False",
     0
 };
 
     0
 };
 
@@ -236,6 +273,8 @@ static XrmOptionDescRec WolframAutomata_options[] = {
     { "-delay-usec",        ".delay-usec",    XrmoptionSepArg, 0 },
     { "-pixel-size",    ".pixel-size",    XrmoptionSepArg, 0 },
     { "-num-generations",    ".num-generations",    XrmoptionSepArg, 0 },
     { "-delay-usec",        ".delay-usec",    XrmoptionSepArg, 0 },
     { "-pixel-size",    ".pixel-size",    XrmoptionSepArg, 0 },
     { "-num-generations",    ".num-generations",    XrmoptionSepArg, 0 },
+    { "-rule",    ".rule-requested",    XrmoptionSepArg, 0 },
+    { "-rule-random",    ".rule-random",    XrmoptionNoArg, "True" },
     { 0, 0, 0, 0 }
 };
 
     { 0, 0, 0, 0 }
 };