6 changed files with 307 additions and 0 deletions
			
			
		@ -0,0 +1,12 @@ | 
				
			|||
CFLAGS := -O3 -Wall -Wextra -std=c17 -D_GNU_SOURCE | 
				
			|||
 | 
				
			|||
.PHONY: all | 
				
			|||
all: main out/ | 
				
			|||
 | 
				
			|||
.PHONY: clean | 
				
			|||
clean: | 
				
			|||
	rm -f main out/* | 
				
			|||
 | 
				
			|||
out/: | 
				
			|||
	mkdir -p $@ | 
				
			|||
	touch $@/.gitkeep | 
				
			|||
@ -0,0 +1,50 @@ | 
				
			|||
........#.##..#|#|.#.....|......#..#.|..##..||.#.. | 
				
			|||
#|##.|||.|..|||......|.##.#|#|....||#.#...#...#..# | 
				
			|||
..##...#|#..|#.|..#||#...|#....|#...#|#.|.||...|.. | 
				
			|||
.....#|||.|.#...###|....|#..#.#.#.|..#||#|....|#.| | 
				
			|||
....|.....#.||.#..#...#|....|||..#....##...|..|.#| | 
				
			|||
||...|###..|..|||..|#.##|.####.#...|.||.|....|.##. | 
				
			|||
..#.#.###..||......#|#|.|....#|.#|.|...#....#...#| | 
				
			|||
.|..||||||...#.##..|.#||.#|##|..#.#..##..#...|#... | 
				
			|||
.|.....||...#.#|.##|..|.##||..#.#..|..#.#.#..|.#|. | 
				
			|||
||...|#........#.|..##|.|..#...#...#|#|..||.|....# | 
				
			|||
#||.|.|..|.......##....|..#||#.#|.|||......|..||.. | 
				
			|||
.....#.|||.....|.#.#.......#.|..#.|.....|.|.#...#. | 
				
			|||
...#.##.#.||#.#|.#.##..#.||#.#.#|#.||.||.|......#. | 
				
			|||
|.|...#|.|####|.|..#.#|....|......|....|...||#||.. | 
				
			|||
.#...#.#......|...#.....|.....|.#|...##|||...#.|#. | 
				
			|||
||##.#...#.|...##..##.||#...#|...|##.##...#||..#|. | 
				
			|||
|.|#.||..|##.|.#.|..#..|.##.#.......#...|....||... | 
				
			|||
.|.......#..##...|.|..|#.#....|#|..##|#|.##|.|.|#. | 
				
			|||
.|....|.#|||#.#..#..|||.....||...#|.#..|..#.#...#. | 
				
			|||
...#..###.#|.##||.#.|.||###..|..|#.|#..||......||. | 
				
			|||
..##.......##|.....#...|#|..##|.#.|||.|#....|##... | 
				
			|||
#...#|##|......##|...|#..#.|..##..#..#.|##.##|#..# | 
				
			|||
|.#|.....|..#...|....|...#....#|..#.....||...|#|.| | 
				
			|||
##...#.....#.....|#|.......|....####.#..##.|.##... | 
				
			|||
.....|...|#|#..|#|.|..##.|..|....##..||.#...|..|.| | 
				
			|||
.|..|....##.||||.##|.#...|..|#|.#.|####.|..|##.#.. | 
				
			|||
#.........|##.#|..##|...|........|..|....|..#...## | 
				
			|||
.#.|...#...#...|.|...|..|.#.|....#..|.|..|..#|.... | 
				
			|||
.....#.....#|.#....|....##...##....###....#.|...|. | 
				
			|||
||.....|.|.##|.##||.#|#.##|.#..|#####|...|...||#.# | 
				
			|||
...#||....#.....##.|##|.##|#.##.#|.|.....#........ | 
				
			|||
..##.....||..#..#.|..##...#.|.|.|.|...|.#.|..|.... | 
				
			|||
|##..|..........##..#|...|......||.#....#....|..#. | 
				
			|||
...#..|.#.|...|.##|.##..##..|.|....#||#|##..||||.. | 
				
			|||
#...##......|..|#...#.#.|#||..#...|.#...|..###.||. | 
				
			|||
|#.......|#.|##|....|.....#..||.|#|#...#|....|..#| | 
				
			|||
.|.....#|##.|.#...#..#||#.....|....#||.#|.##.##.#| | 
				
			|||
|#..###..#..|#.....##...||.|.|.#.#|.||..||.||#|#.. | 
				
			|||
||||#....|#..|.|...|...||....|...#....#.##...#|... | 
				
			|||
...||##||#......|#.#..#..|.....|...#..#|...#...||| | 
				
			|||
.|#.|.|....|...#.....|#....|..#.#...#...||..##|..| | 
				
			|||
||#.|##.|...|.##......##|#..#..#.#.#.....|#|##.##. | 
				
			|||
|.#.....||.....#.#...|...|..|#|..|..#...|....|...| | 
				
			|||
###..#.#......#|..#....#......|##.##....|||.|..#|. | 
				
			|||
..#.|.#...#..|#####|.....##.|.|#......|..||.#|.... | 
				
			|||
.#||.|.##..#.|..##......|..|.|#..|.....#.....|#|.. | 
				
			|||
|##.#......#.#.#.#|||#|....#...#.|.........|||.#.. | 
				
			|||
|......||.|..#.|#||...||.#.#.##..#..#.#....#.#..#| | 
				
			|||
#.|..##.....#..|...|#...#...|.......|.|..|#|...... | 
				
			|||
##...#....#..#..#....|...#|#.||.|...|.#..###|##|.| | 
				
			|||
@ -0,0 +1,243 @@ | 
				
			|||
#include <stdlib.h> | 
				
			|||
#include <stdio.h> | 
				
			|||
#include <string.h> | 
				
			|||
#include <stdint.h> | 
				
			|||
#include <time.h> | 
				
			|||
 | 
				
			|||
struct size2d { | 
				
			|||
    unsigned w; | 
				
			|||
    unsigned h; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
struct buffer { | 
				
			|||
    char *data; | 
				
			|||
    size_t len; | 
				
			|||
    size_t alloc; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
void *xrealloc(void *ptr, size_t size) | 
				
			|||
{ | 
				
			|||
    void *res = realloc(ptr, size); | 
				
			|||
    if (!res) { | 
				
			|||
        perror("realloc"); | 
				
			|||
        exit(1); | 
				
			|||
    } | 
				
			|||
    return res; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
struct buffer buffer_alloc() | 
				
			|||
{ | 
				
			|||
    struct buffer buffer; | 
				
			|||
    buffer.len = 0; | 
				
			|||
    buffer.alloc = 0x10; | 
				
			|||
    buffer.data = xrealloc(NULL, buffer.alloc); | 
				
			|||
    return buffer; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
void buffer_append(struct buffer *buffer, char c) | 
				
			|||
{ | 
				
			|||
    if (buffer->alloc <= buffer->len) { | 
				
			|||
        buffer->alloc *= 2; | 
				
			|||
        buffer->data = xrealloc(buffer->data, buffer->alloc); | 
				
			|||
    } | 
				
			|||
    buffer->data[buffer->len++] = c; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
char *parse_acres(const char *fname, struct size2d *size) | 
				
			|||
{ | 
				
			|||
    FILE *f = fopen(fname, "r"); | 
				
			|||
    if (!f) { | 
				
			|||
        perror(fname); | 
				
			|||
        return NULL; | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    struct buffer buffer = buffer_alloc(); | 
				
			|||
    size->w = 0; | 
				
			|||
    size->h = 0; | 
				
			|||
 | 
				
			|||
    unsigned width = 0; | 
				
			|||
    int c; | 
				
			|||
 | 
				
			|||
    flockfile(f); | 
				
			|||
    while ((c = getc_unlocked(f)) != EOF) { | 
				
			|||
        if (c == '\n') { | 
				
			|||
            if (!size->w) { | 
				
			|||
                size->w = width; | 
				
			|||
            } else { | 
				
			|||
                if (size->w != width) { | 
				
			|||
                    fprintf(stderr, "ERROR: Not each line has the same width\n"); | 
				
			|||
                    goto error; | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
            width = 0; | 
				
			|||
            size->h++; | 
				
			|||
            continue; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        if (c != '.' && c != '|' && c != '#') { | 
				
			|||
            fprintf(stderr, "ERROR: Unknown character: '%c'\n", c); | 
				
			|||
            goto error; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        buffer_append(&buffer, c); | 
				
			|||
        width++; | 
				
			|||
    } | 
				
			|||
    funlockfile(f); | 
				
			|||
    fclose(f); | 
				
			|||
 | 
				
			|||
    return realloc(buffer.data, buffer.len); | 
				
			|||
 | 
				
			|||
error: | 
				
			|||
    funlockfile(f); | 
				
			|||
    fclose(f); | 
				
			|||
    free(buffer.data); | 
				
			|||
    return NULL; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
void advance_frame(char *acres, char *next, const struct size2d size) | 
				
			|||
{ | 
				
			|||
    for (unsigned y = 0; y < size.h; y++) { | 
				
			|||
        for (unsigned x = 0; x < size.w; x++) { | 
				
			|||
            char *a = next + y * size.w + x; | 
				
			|||
 | 
				
			|||
            char surrounding[8] = {'\0'}; | 
				
			|||
            if (y > 0) surrounding[0] = acres[(y - 1) * size.w + x]; | 
				
			|||
            if (x > 0) surrounding[1] = acres[y * size.w + (x - 1)]; | 
				
			|||
            if (y + 1 < size.h) surrounding[2] = acres[(y + 1) * size.w + x]; | 
				
			|||
            if (x + 1 < size.w) surrounding[3] = acres[y * size.w + (x + 1)]; | 
				
			|||
            if (y > 0 && x + 1 < size.w) | 
				
			|||
                surrounding[4] = acres[(y - 1) * size.w + (x + 1)]; | 
				
			|||
            if (y > 0 && x > 0) | 
				
			|||
                surrounding[5] = acres[(y - 1) * size.w + (x - 1)]; | 
				
			|||
            if (y + 1 < size.h && x > 0) | 
				
			|||
                surrounding[6] = acres[(y + 1) * size.w + (x - 1)]; | 
				
			|||
            if (y + 1 < size.h && x + 1 < size.w) | 
				
			|||
                surrounding[7] = acres[(y + 1) * size.w + (x + 1)]; | 
				
			|||
 | 
				
			|||
            unsigned tally = 0; | 
				
			|||
            unsigned tally2 = 0; | 
				
			|||
            char new = 0; | 
				
			|||
 | 
				
			|||
            switch (*a) { | 
				
			|||
            case '.': | 
				
			|||
            case '|': | 
				
			|||
                new = (*a == '.' ? '|' : '#'); | 
				
			|||
                for (char *c = surrounding; c < surrounding + 8; c++) { | 
				
			|||
                    if (*c == new) tally++; | 
				
			|||
                } | 
				
			|||
                if (tally >= 3) *a = new; | 
				
			|||
                break; | 
				
			|||
            case '#': | 
				
			|||
                for (char *c = surrounding; c < surrounding + 8; c++) { | 
				
			|||
                    if (*c == '#') tally++; | 
				
			|||
                    if (*c == '|') tally2++; | 
				
			|||
                } | 
				
			|||
                if (!(tally >= 1 && tally2 >= 1)) *a = '.'; | 
				
			|||
                break; | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
int render_bitmap(const char *fname, const char *acres, const struct size2d size) | 
				
			|||
{ | 
				
			|||
    FILE *f = fopen(fname, "w"); | 
				
			|||
    if (!f) { | 
				
			|||
        perror(fname); | 
				
			|||
        return 1; | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    flockfile(f); | 
				
			|||
    fprintf(f, "P6\n%u %u\n255\n", size.w, size.h); | 
				
			|||
 | 
				
			|||
    for (unsigned y = 0; y < size.h; y++) { | 
				
			|||
        for (unsigned x = 0; x < size.w; x++) { | 
				
			|||
            char color[3] = {255}; | 
				
			|||
 | 
				
			|||
            switch (acres[y * size.w + x]) { | 
				
			|||
            case '.': | 
				
			|||
                // Yellow
 | 
				
			|||
                color[0] = 205; | 
				
			|||
                color[1] = 255; | 
				
			|||
                color[2] = 110; | 
				
			|||
                break; | 
				
			|||
            case '|': | 
				
			|||
                // Green
 | 
				
			|||
                color[0] = 0; | 
				
			|||
                color[1] = 255; | 
				
			|||
                color[2] = 0; | 
				
			|||
                break; | 
				
			|||
            case '#': | 
				
			|||
                // Brown
 | 
				
			|||
                color[0] = 192; | 
				
			|||
                color[1] = 125; | 
				
			|||
                color[2] = 0; | 
				
			|||
                break; | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            fwrite_unlocked(color, 3, 1, f); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    funlockfile(f); | 
				
			|||
    fclose(f); | 
				
			|||
    return 0; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
int main(int argc, char *argv[]) | 
				
			|||
{ | 
				
			|||
    struct size2d size; | 
				
			|||
    char *acres = parse_acres("input", &size); | 
				
			|||
    if (!acres) return 1; | 
				
			|||
 | 
				
			|||
    unsigned minutes = 10; | 
				
			|||
    int render = 0; | 
				
			|||
    if (argc > 1) minutes = strtol(argv[1], NULL, 0); | 
				
			|||
    if (argc > 2 && strcmp(argv[2], "-render") == 0) render = 1; | 
				
			|||
 | 
				
			|||
    char *next = xrealloc(NULL, size.w * size.h); | 
				
			|||
    memcpy(next, acres, size.w * size.h); | 
				
			|||
 | 
				
			|||
    char *fname = NULL; | 
				
			|||
    clock_t start = clock(); | 
				
			|||
    for (unsigned i = 0; i <= minutes; i++) { | 
				
			|||
        if (i != 0) { | 
				
			|||
            advance_frame(acres, next, size); | 
				
			|||
            memcpy(acres, next, size.w * size.h); | 
				
			|||
 | 
				
			|||
            if (i % 10000 == 0) { | 
				
			|||
                double framespers = 10000 / ((double)(clock() - start) / CLOCKS_PER_SEC); | 
				
			|||
                unsigned eta = (double)(minutes - i) / framespers; | 
				
			|||
                fprintf(stderr, "Progress: %.2f%% (speed: %.2f frames/s, ETA: %u:%u:%u)\n", | 
				
			|||
                        (double)i / minutes * 100, framespers, | 
				
			|||
                        eta / 60 / 60, (eta / 60) % 60, eta % 60); | 
				
			|||
                start = clock(); | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        if (render) { | 
				
			|||
            if (asprintf(&fname, "out/frame%04u.ppm", i) == -1) { | 
				
			|||
                perror("asprintf"); | 
				
			|||
                break; | 
				
			|||
            } | 
				
			|||
            if (render_bitmap(fname, acres, size)) break; | 
				
			|||
            free(fname); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    unsigned wood = 0; | 
				
			|||
    unsigned lumber = 0; | 
				
			|||
    for (unsigned y = 0; y < size.h; y++) { | 
				
			|||
        for (unsigned x = 0; x < size.w; x++) { | 
				
			|||
            char c = acres[y * size.w + x]; | 
				
			|||
            if (c == '|') wood++; | 
				
			|||
            if (c == '#') lumber++; | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    printf("Resource value: %u\n", wood * lumber); | 
				
			|||
 | 
				
			|||
    free(next); | 
				
			|||
    free(acres); | 
				
			|||
    return 0; | 
				
			|||
} | 
				
			|||
@ -0,0 +1,2 @@ | 
				
			|||
#!/bin/sh | 
				
			|||
convert -monitor -resize 1000% -filter point -delay 5 -loop 0 out/*.ppm out.gif | 
				
			|||
| 
		 After Width: | Height: | Size: 1.8 MiB  | 
					Loading…
					
					
				
		Reference in new issue