107 lines
2.6 KiB
C
107 lines
2.6 KiB
C
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include <png.h>
|
|
|
|
typedef struct args {
|
|
int height;
|
|
char *png_filename;
|
|
bool print_to_stdout;
|
|
} args;
|
|
|
|
|
|
int parse_args(int argc, char **argv, args *args)
|
|
{
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Usage:\n");
|
|
fprintf(stderr, " %s --stdout # To print as an ASCII table.\n", argv[0]);
|
|
fprintf(stderr, " %s file.png # To write a PNG file.\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
if (sscanf(argv[1], "%i", &(args->height)) == EOF) {
|
|
fprintf(stderr, "Can't read height as an integer.\n");
|
|
return 1;
|
|
}
|
|
|
|
if (argc > 2) {
|
|
if (strcmp(argv[2], "--stdout") == 0)
|
|
args->print_to_stdout = true;
|
|
else
|
|
args->png_filename = argv[2];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void print_line(int width)
|
|
{
|
|
printf("+");
|
|
for (int x = 0; x < width; x++)
|
|
printf("---+");
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
void terrain_to_stdout(int width, int **terrain)
|
|
{
|
|
for (int x = 0; x < width; x++) {
|
|
print_line(width);
|
|
printf("|");
|
|
for (int y = 0; y < width; y++) {
|
|
if (terrain[x][y] == 0)
|
|
printf(" |");
|
|
else if (terrain[x][y] < 10)
|
|
printf(" %i |", terrain[x][y]);
|
|
else
|
|
printf("%3i|", terrain[x][y]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
print_line(width);
|
|
}
|
|
|
|
#define ONE_GRAIN "\x3E\x92\xCC"
|
|
#define TWO_GRAINS "\x2A\x62\x8F"
|
|
#define THREE_GRAINS "\x13\x29\x3D"
|
|
#define CMAP "\xFF\xFF\xFF" ONE_GRAIN TWO_GRAINS THREE_GRAINS
|
|
|
|
int terrain_to_png(int width, int **terrain, char *filename)
|
|
{
|
|
png_image image;
|
|
png_byte *bytes;
|
|
|
|
bytes = malloc(sizeof(*bytes) * width * width);
|
|
memset(&image, 0, (sizeof image));
|
|
image.version = PNG_IMAGE_VERSION;
|
|
image.format = PNG_FORMAT_FLAG_COLORMAP|PNG_FORMAT_FLAG_COLOR;
|
|
image.width = width;
|
|
image.height = width;
|
|
image.colormap_entries = 4;
|
|
for (int x = 0; x < width; x++)
|
|
for (int y = 0; y < width; y++)
|
|
bytes[x * width + y] = terrain[x][y];
|
|
if (png_image_write_to_file(&image, filename, 0, bytes, width, CMAP))
|
|
return 0;
|
|
|
|
fprintf(stderr, "pngtopng: error: %s\n", image.message);
|
|
return 1;
|
|
}
|
|
|
|
void save_terrain(int width, int **terrain, args *args)
|
|
{
|
|
if (args->png_filename)
|
|
terrain_to_png(width, terrain, args->png_filename);
|
|
if (args->print_to_stdout)
|
|
terrain_to_stdout(width, terrain);
|
|
}
|
|
|
|
int sandpile_width(int ngrains) {
|
|
int width;
|
|
|
|
width = pow(ngrains / 2 / 3.1415926535, 0.5) * 2 + 1;
|
|
width += 1 - width % 2; // Ensure width is odd (terrain has a center)
|
|
return width;
|
|
}
|