Skip to content

Instantly share code, notes, and snippets.

@mbikovitsky
Last active December 31, 2015 13:39
Show Gist options
  • Save mbikovitsky/7994670 to your computer and use it in GitHub Desktop.
Save mbikovitsky/7994670 to your computer and use it in GitHub Desktop.
Source code for http://youtu.be/hSFf-0F66KE.
/* Copyright (c) 2013 Michael Bikovitsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "life.h"
field* alloc(int rows, int cols)
{
field *f = (field *)malloc(sizeof(field));
f->rows = rows;
f->cols = cols;
f->array = (char *)malloc(sizeof(char) * (rows * cols));
return f;
}
void destroy(field *f)
{
free(f->array);
free(f);
}
void randomize(field* f)
{
int row;
srand(time(NULL));
for (row = 0; row < f->rows; ++row) {
int col;
for (col = 0; col < f->cols; ++col) {
CELL(f, row, col) = rand() % 2;
}
}
}
field* read_file(const char *filename)
{
field *f;
FILE *file;
int dimensions[2];
file = fopen(filename, "r");
if (file == NULL) return NULL;
fread(dimensions, sizeof(int), 2, file);
f = alloc(dimensions[0], dimensions[1]);
fread(f->array, sizeof(char), f->rows * f->cols, file);
fclose(file);
return f;
}
static char count_neighbors(field* f, int cell_row, int cell_col)
{
char count = 0;
/* Top left */
if (cell_row - 1 >= 0 && cell_col - 1 >= 0) {
count += CELL(f, cell_row - 1, cell_col - 1);
}
/* Top center */
if (cell_row - 1 >= 0) {
count += CELL(f, cell_row - 1, cell_col);
}
/* Top right */
if (cell_row - 1 >= 0 && cell_col + 1 < f->cols) {
count += CELL(f, cell_row - 1, cell_col + 1);
}
/* Middle left */
if (cell_col - 1 >= 0) {
count += CELL(f, cell_row, cell_col - 1);
}
/* Middle right */
if (cell_col + 1 < f->cols) {
count += CELL(f, cell_row, cell_col + 1);
}
/* Bottom left */
if (cell_row + 1 < f->rows && cell_col - 1 >= 0) {
count += CELL(f, cell_row + 1, cell_col - 1);
}
/* Bottom center */
if (cell_row + 1 < f->rows) {
count += CELL(f, cell_row + 1, cell_col);
}
/* Bottom right */
if (cell_row + 1 < f->rows && cell_col + 1 < f->cols) {
count += CELL(f, cell_row + 1, cell_col + 1);
}
return count;
}
static char alive(field* f, int cell_row, int cell_col)
{
char neighbors = count_neighbors(f, cell_row, cell_col);
/* A dead cell with exactly three live neighbors becomes a live cell (birth). */
if (CELL(f, cell_row, cell_col) == 0 && neighbors == 3) {
return 1;
}
/* A live cell with two or three live neighbors stays alive (survival). */
if (CELL(f, cell_row, cell_col) == 1 && (neighbors == 2 || neighbors == 3)) {
return 1;
}
/* In all other cases, a cell dies or remains dead (overcrowding or loneliness). */
return 0;
}
void evolve(field* f, int generations)
{
int i;
for (i = 0; i < generations; ++i) {
field *old_field = alloc(f->rows, f->cols);
int row;
for (row = 0; row < f->rows; ++row) {
int col;
for (col = 0; col < f->cols; ++col) {
CELL(old_field, row, col) = CELL(f, row, col);
}
}
for (row = 0; row < old_field->rows; ++row) {
int col;
for (col = 0; col < old_field->cols; ++col) {
CELL(f, row, col) = alive(old_field, row, col);
}
}
destroy(old_field);
}
}
/* Copyright (c) 2013 Michael Bikovitsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LIFE_H
#define LIFE_H
typedef struct {
int rows;
int cols;
char* array;
} field;
#define CELL(field, row, col) ((field)->array[(row) * (field)->cols + (col)])
field* alloc(int rows, int cols);
void destroy(field *f);
void randomize(field* f);
field* read_file(const char *filename);
void evolve(field* f, int generations);
#endif /* LIFE_H */
/* Copyright (c) 2013 Michael Bikovitsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <ncurses.h>
#include <stdlib.h>
#include "life.h"
#define GEN_FORMAT "%04ld"
#define FILE_EXT "gen"
int setup (const char *filename, WINDOW **win, field **f);
void update_field (WINDOW *win, field *f, int generations);
int main(int argc, char *argv[])
{
/* Variable declarations */
field *f = NULL;
WINDOW *win = NULL;
long int reverse_generations = 0;
long int i;
char *filename = NULL;
if (argc < 3) {
printf("Invalid number of arguments.\n");
return 0;
}
if ((reverse_generations = strtol(argv[2], NULL, 0)) <= 0) {
printf("Invalid number of generations.\n");
return 0;
}
if (setup(argv[1], &win, &f) == -1) {
return 0;
}
update_field(win, f, 0);
filename = (char *)malloc(sizeof(char) * 100);
for (i = 0; i <= reverse_generations; ++i) {
FILE *output;
sprintf(filename, GEN_FORMAT "." FILE_EXT, i);
output = fopen(filename, "w");
putwin(win, output);
update_field(win, f, 1);
fclose(output);
}
delwin(win);
for (i = reverse_generations; i >= 0; --i) {
FILE *input;
sprintf(filename, GEN_FORMAT "." FILE_EXT, i);
input = fopen(filename, "r");
mvprintw(0, 0, "Generation: " GEN_FORMAT, i);
refresh();
win = getwin(input);
wrefresh(win);
delwin(win);
fclose(input);
remove(filename);
if (getch() == 'q') break;
}
for (; i >= 0; --i) {
sprintf(filename, GEN_FORMAT "." FILE_EXT, i);
remove(filename);
}
free(filename);
destroy(f);
endwin();
return 0;
}
int setup(const char *filename, WINDOW **win, field **f)
{
int height, width;
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
curs_set(0);
*f = read_file(filename);
if (*f == NULL) {
endwin();
printf("Could not open file.\n");
return -1;
}
height = (*f)->rows + 2;
width = (*f)->cols + 2;
if (height > LINES || width > COLS) {
endwin();
printf("Screen too small.\n");
return -1;
}
*win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2);
box(*win, 0, 0);
return 0;
}
void update_field(WINDOW *win, field *f, int generations)
{
int row, col;
evolve(f, generations);
for (row = 0; row < f->rows; ++row) {
for (col = 0; col < f->cols; ++col) {
if (CELL(f, row, col) == 1) {
mvwaddch(win, row + 1, col + 1, ACS_BLOCK);
} else {
mvwaddch(win, row + 1, col + 1, ' ');
}
}
}
}
#CXRLE Pos=-28,-8
x = 115, y = 31, rule = B3/S23
b4o13bo2bo34bo$o5b3o4b3o2bo2bo2b4o3b3o4b3ob3o6b3o2bo2b3ob3ob4o$o5bobo
4bo3b3obo2bo2bo3bo6bobobo8bo3b3obobobobobo2bo$o5bobo4bo4bo2bo2b4o3bo6b
obob2o7bo4bo2bobobobob4o$o5bobo4bo4bo2bo2bo6bo6bobobo8bo4bo2bobobobobo
$b4ob4ob3o4b2ob2ob4ob3o6b3obo6b3o4b2ob3obobob4o3$4o6bobo3bo47bo$o3bobo
bo3bo3bo5b3ob3o4b3ob3o2b3ob4ob4o4b3o2bo2b3ob3ob4o$4o2bobobobo2b3o4bobo
bobo4bobobobo2bobobo2bobo7bobo2bo2bobobobobo2bo$o3bobobobobo3bo5bobobo
bo4bobobobo2bobob4obo7bobo2bo2bobobobob4o$o3bobobobobo3bo5bobobobo4b3o
bobo2b3obo4bo7bobo2bo2bobobobobo$4o2b3obob2o2b2o4b3obobo4bo3b4obo3b4ob
o7b4ob2ob3obobob4o$33bo8bo2$4o20bo2bo17bo15bo31bo$o4b4ob3ob5o5bo2bo3b
4o6b3obo3b3o2b4o3bo3b3o4b3ob3o4b3o7bob4ob4ob3o2b5o$3o2bo4bobobobobo4b
3obo3bo2bo6bo3bo3bobo2bo6bo3bo6bobobo6bobo7bobo4bo2bobobo2bobobo$o4bo
4bobobobobo5bo2b3ob4o6bo3b3obobo2bo4b3o3bo6bobob2o5bobo5b3obo4b4obobo
2bobobo$o4bo4bobobobobo5bo2bobobo9bo3bobobobo2bo4bobo3bo6bobobo6bobo5b
obobo4bo4bobo2bobobo$o4bo4b3obobobo5b2obobob4o4b3o3bobob4obo4b3ob3o6b
3obo6b4o4b3obo4b4ob4obobobo3$o40bo3bo$o3b3ob3ob3o4b3ob3ob4ob3ob3o2bo3b
o2b4ob3o$o3bobobobobobo4bo3bobobo4bobobobob3ob3obo2bobobo$o3bobobobobo
bo4b2o2bobobo4bobobobo2bo3bo2b4obobo$o3bobobobob3o4bo3bobobo4b3obobo2b
o3bo2bo4bobo$3ob3obobo3bo4bo3b3obo6bob3o2b2o2b2ob4obobo$12b3o17b3o!
# Copyright (c) 2013 Michael Bikovitsky
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import re
import struct
ALIVE = 'o'
DEAD = 'b'
EOL = '$'
PATTERN = re.compile(r'(?P<run_length>\d+)(?:(?P<alive>o)|(?P<dead>b)|(?P<eol>\$))')
def expand(matchobject):
if matchobject.group('alive'):
return ALIVE * int(matchobject.group('run_length'))
if matchobject.group('dead'):
return DEAD * int(matchobject.group('run_length'))
if matchobject.group('eol'):
return EOL * int(matchobject.group('run_length'))
def main():
with open("new_horizons.rle", mode='r') as f:
lines = f.read().replace('\r', '').split('\n')
cols = int(lines[1].split(',')[0].split('=')[1])
rows = int(lines[1].split(',')[1].split('=')[1])
lines = lines[2:]
expanded = "".join([
re.sub(PATTERN, expand, line) for line in lines
])
expanded = expanded.split('!')[0]
expanded = "".join([
line + (cols - len(line)) * DEAD for line in expanded.split('$')
])
field = []
for char in expanded:
if char == ALIVE:
field.append(1)
else:
field.append(0)
packed = struct.pack("<ii{0}b".format(rows * cols),
rows, cols, *field)
with open("new_horizons.dat", mode="wb") as g:
g.write(packed)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment