home · contact · privacy
Fix buggy healthy_addch().
[plomrogue] / libplomrogue.c
index fd6675575567b019ec4f10595e8bfbd2b0e697c6..9f872e1d406158f3a77920de025e6bd9309752c9 100644 (file)
@@ -1,3 +1,4 @@
+#include <math.h> /* pow() */
 #include <stddef.h> /* NULL */
 #include <stdint.h> /* ?(u)int(8|16|32)_t, ?(U)INT8_(MIN|MAX) */
 #include <stdlib.h> /* free, malloc */
@@ -339,7 +340,8 @@ static uint8_t shade_hex(uint32_t left_angle, uint32_t right_angle,
  */
 static uint8_t eval_position(uint16_t dist, uint16_t hex_i, char * fov_map,
                              struct yx_uint8 * test_pos,
-                             struct shadow_angle ** shadows)
+                             struct shadow_angle ** shadows,
+                             const char * symbols_obstacle)
 {
     int32_t left_angle_uncorrected =   ((CIRCLE / 12) / dist)
                                      - (hex_i * (CIRCLE / 6) / dist);
@@ -356,7 +358,7 @@ static uint8_t eval_position(uint16_t dist, uint16_t hex_i, char * fov_map,
     uint16_t pos_in_map = test_pos->y * maplength + test_pos->x;
     uint8_t all_shaded = shade_hex(left_angle, right_angle_1st, middle_angle,
                                    shadows, pos_in_map, fov_map);
-    if (!all_shaded && 'X' == worldmap[pos_in_map])
+    if (!all_shaded && NULL != strchr(symbols_obstacle, worldmap[pos_in_map]))
     {
         if (set_shadow(left_angle, right_angle_1st, shadows))
         {
@@ -377,8 +379,9 @@ static uint8_t eval_position(uint16_t dist, uint16_t hex_i, char * fov_map,
 /* Update field of view in "fovmap" of "worldmap_input" as seen from "y"/"x".
  * Return 1 on malloc error, else 0.
  */
-extern uint8_t build_fov_map(uint8_t y, uint8_t x,
-                             char * fovmap, char * worldmap_input)
+extern uint8_t build_fov_map(uint8_t y, uint8_t x, char * fovmap,
+                             char * worldmap_input,
+                             const char * symbols_obstacle)
 {
     worldmap = worldmap_input;
     struct shadow_angle * shadows = NULL;
@@ -407,7 +410,8 @@ extern uint8_t build_fov_map(uint8_t y, uint8_t x,
             }
             if (mv_yx_in_dir_legal(dir_char, &test_pos))
             {
-                if (eval_position(circle_i, hex_i, fovmap, &test_pos, &shadows))
+                if (eval_position(circle_i, hex_i, fovmap, &test_pos, &shadows,
+                                  symbols_obstacle))
                 {
                     return 1;
                 }
@@ -419,3 +423,238 @@ extern uint8_t build_fov_map(uint8_t y, uint8_t x,
     free_angles(shadows);
     return 0;
 }
+
+static uint16_t * score_map = NULL;
+static uint16_t neighbor_scores[6];
+
+/* Init AI score map. Return 1 on failure, else 0. */
+extern uint8_t init_score_map()
+{
+    uint32_t map_size = maplength * maplength;
+    score_map = malloc(map_size * sizeof(uint16_t));
+    if (!score_map)
+    {
+        return 1;
+    }
+    uint32_t i = 0;
+    for (; i < map_size; i++)
+    {
+        score_map[i] = UINT16_MAX;
+    }
+    return 0;
+}
+
+/* Set score_map[pos] to score. Return 1 on failure, else 0. */
+extern uint8_t set_map_score(uint16_t pos, uint16_t score)
+{
+    if (!score_map)
+    {
+        return 1;
+    }
+    score_map[pos] = score;
+    return 0;
+}
+
+/* Get score_map[pos]. Return uint16_t value on success, -1 on failure. */
+extern int32_t get_map_score(uint16_t pos)
+{
+    if (!score_map)
+    {
+        return -1;
+    }
+    return score_map[pos];
+}
+
+/* Free score_map. */
+extern void free_score_map()
+{
+    free(score_map);
+    score_map = NULL;
+}
+
+/* Write into "neighbors" scores of the immediate neighbors of the score_map
+ * cell at pos_i (array index), as found in the directions north-east, east,
+ * south-east etc. (clockwise order). Use kill_score for illegal neighborhoods
+ * (i.e. if direction would lead beyond the map's border).
+ */
+static void get_neighbor_scores(uint16_t pos_i, uint16_t kill_score,
+                                uint16_t * neighbors)
+{
+    uint32_t map_size = maplength * maplength;
+    uint8_t open_north     = pos_i >= maplength;
+    uint8_t open_east      = pos_i + 1 % maplength;
+    uint8_t open_south     = pos_i + maplength < map_size;
+    uint8_t open_west      = pos_i % maplength;
+    uint8_t is_indented    = (pos_i / maplength) % 2;
+    uint8_t open_diag_west = is_indented || open_west;
+    uint8_t open_diag_east = !is_indented || open_east;
+    neighbors[0] = !(open_north && open_diag_east) ? kill_score :
+                   score_map[pos_i - maplength + is_indented];
+    neighbors[1] = !(open_east) ? kill_score : score_map[pos_i + 1];
+    neighbors[2] = !(open_south && open_diag_east) ? kill_score :
+                   score_map[pos_i + maplength + is_indented];
+    neighbors[3] = !(open_south && open_diag_west) ? kill_score :
+                   score_map[pos_i + maplength - !is_indented];
+    neighbors[4] = !(open_west) ? kill_score : score_map[pos_i - 1];
+    neighbors[5] = !(open_north && open_diag_west) ? kill_score :
+                   score_map[pos_i - maplength - !is_indented];
+}
+
+/* Call get_neighbor_scores() on neighbor_scores buffer. Return 1 on error. */
+extern uint8_t ready_neighbor_scores(uint16_t pos)
+{
+    if (!score_map)
+    {
+        return 1;
+    }
+    get_neighbor_scores(pos, UINT16_MAX, neighbor_scores);
+    return 0;
+}
+
+/* Return i-th position from neighbor_scores buffer.*/
+extern uint16_t get_neighbor_score(uint8_t i)
+{
+    return neighbor_scores[i];
+}
+
+/* Iterate over scored cells in score_map geometry. Compare each cell's score
+ * against the score of its immediate neighbors in 6 directions. If any
+ * neighbor's score is at least two points lower than the current cell's score,
+ * re-set it to 1 point higher than its lowest-scored neighbor. Repeat this
+ * whole process until all cells have settled on their final score. Ignore cells
+ * whose score is greater than UINT16_MAX - 1 (treat those as unreachable). Also
+ * ignore cells whose score is smaller or equal the number of past iterations.
+ * Return 1 on error, else 0.
+ */
+extern uint8_t dijkstra_map()
+{
+    if (!score_map)
+    {
+        return 1;
+    }
+    uint16_t max_score = UINT16_MAX - 1;
+    uint32_t map_size = maplength * maplength;
+    uint32_t pos;
+    uint16_t i_scans, neighbors[6], min_neighbor;
+    uint8_t scores_still_changing = 1;
+    uint8_t i_dirs;
+    for (i_scans = 0; scores_still_changing; i_scans++)
+    {
+        scores_still_changing = 0;
+        for (pos = 0; pos < map_size; pos++)
+        {
+            uint16_t score = score_map[pos];
+            if (score <= max_score && score > i_scans)
+            {
+                get_neighbor_scores(pos, max_score, neighbors);
+                min_neighbor = max_score;
+                for (i_dirs = 0; i_dirs < 6; i_dirs++)
+                {
+                    if (min_neighbor > neighbors[i_dirs])
+                    {
+                        min_neighbor = neighbors[i_dirs];
+                    }
+                }
+                if (score_map[pos] > min_neighbor + 1)
+                {
+                    score_map[pos] = min_neighbor + 1;
+                    scores_still_changing = 1;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+extern uint8_t zero_score_map_where_char_on_memdepthmap(char c,
+                                                        char * memdepthmap)
+{
+    if (!score_map)
+    {
+        return 1;
+    }
+    uint32_t map_size = maplength * maplength;
+    uint16_t pos;
+    for (pos = 0; pos < map_size; pos++)
+    {
+        if (c == memdepthmap[pos])
+        {
+            score_map[pos] = 0;
+        }
+    }
+    return 0;
+}
+
+extern void age_some_memdepthmap_on_nonfov_cells(char * memdepthmap,
+                                                 char * fovmap)
+{
+    uint32_t map_size = maplength * maplength;
+    uint16_t pos;
+    for (pos = 0; pos < map_size; pos++)
+    {
+        if ('v' != fovmap[pos])
+        {
+            char c = memdepthmap[pos];
+            if( '0' <= c && '9' > c && !(rrand() % (uint16_t) pow(2, c - 48)))
+            {
+                memdepthmap[pos]++;
+            }
+        }
+    }
+}
+
+extern uint8_t set_cells_passable_on_memmap_to_65534_on_scoremap(char * mem_map,
+                                                  const char * symbols_passable)
+{
+    if (!score_map)
+    {
+        return 1;
+    }
+    uint32_t map_size = maplength * maplength;
+    uint16_t pos;
+    for (pos = 0; pos < map_size; pos++)
+    {
+        if (NULL != strchr(symbols_passable, mem_map[pos]))
+        {
+            score_map[pos] = 65534;
+        }
+    }
+    return 0;
+}
+
+
+extern void update_mem_and_memdepthmap_via_fovmap(char * map, char * fovmap,
+                                                  char * memdepthmap,
+                                                  char * memmap)
+{
+    uint32_t map_size = maplength * maplength;
+    uint16_t pos;
+    for (pos = 0; pos < map_size; pos++)
+    {
+        if ('v' == fovmap[pos])
+        {
+            memdepthmap[pos] = '0';
+            memmap[pos] = map[pos];
+        }
+    }
+}
+
+/* USEFUL FOR DEBUGGING
+#include <stdio.h>
+extern void write_score_map()
+{
+    FILE *f = fopen("score_map", "a");
+
+    fprintf(f, "\n---------------------------------------------------------\n");
+    uint32_t y, x;
+    for (y = 0; y < maplength; y++)
+    {
+        for (x = 0; x < maplength; x++)
+        {
+            fprintf(f, "%2X", score_map[y * maplength + x] % 256);
+        }
+        fprintf(f, "\n");
+    }
+    fclose(f);
+}
+*/