-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMain.c
165 lines (131 loc) · 5.3 KB
/
Main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LENGTH_INITIAL_CONDITIONS 1000
char* ruleToBinaryArray(char ruleNumber) {
char* ruleBinary = (char*)malloc(8 * sizeof(char));
for (char i = 0; i < 8; i++)
ruleBinary[i] = (ruleNumber >> i) & 1;
return ruleBinary;
}
// the neighborhood must be an actual string, with ascii values of 0 and 1 and a null terminator
char calculateCell(const char *neighborhood, const char* ruleBinary) {
char index = strtol(neighborhood, NULL, 2);
return ruleBinary[index];
}
char** runCellularAutomaton(const char* rule, const int generations, char* cells, int initialConditionsLength) {
const int imageWidth = initialConditionsLength + 2 * generations;
char** automatonData = (char**)malloc(generations * sizeof(char*));
if (NULL == automatonData) {
printf("Error allocating memory!\n");
return NULL;
}
int length = initialConditionsLength;
int initialOffset = (imageWidth - initialConditionsLength) / 2;
// allocate memory for the entire Cellular Automaton
for (int i = 0; i < generations; i++) {
char* row = (char*)malloc((imageWidth + 1)* sizeof(char));
if (NULL == row) {
printf("Error allocating memory!\n");
for (int j = 0; j < i; j++) // free the memory allocated by this function so far
free(automatonData[j]);
free(automatonData);
return NULL; // return null to indicate that the function failed and the caller should gracefully exit
}
// memset(row, 0, (imageWidth + 1) * sizeof(char));
memset(row, 0, (imageWidth + 1) * sizeof(char));
row[imageWidth] = '\0';
if (i == 0)
memcpy(row + initialOffset, cells, initialConditionsLength * sizeof(char));
automatonData[i] = row;
}
length += 2;
char neighborhood[4];
neighborhood[3] = '\0';
for (int i = 1; i < generations; i++) {
int paddingOffset = initialOffset - i;
for (int j = paddingOffset; j < paddingOffset + length; j++) {
char* previousRow = automatonData[i - 1];
neighborhood[0] = previousRow[j - 1] + '0';
neighborhood[1] = previousRow[j] + '0';
neighborhood[2] = previousRow[j + 1] + '0';
automatonData[i][j] = calculateCell(neighborhood, rule);
}
length += 2;
}
return automatonData;
}
int outputToFile(char** automatonData, int ruleNumber, int generations, const char *initialConditions, int imageWidth) {
char filename[MAX_LENGTH_INITIAL_CONDITIONS + 50];
sprintf(filename, "results/r%d_g%d_i%s_c.pbm", ruleNumber, generations, initialConditions);
FILE *file = fopen(filename, "w");
if (!file) {
printf("Error creating output file!\n");
return 1;
}
fprintf(file, "P1\n%d %d\n", imageWidth, generations);
for (int i = 0; i < generations; i++) {
for (int j = 0; j < imageWidth; j++)
fprintf(file, "%d", automatonData[i][j]);
fprintf(file, "\n");
}
return fclose(file);
}
int main() {
int exitCode = 0;
FILE *inputFile = fopen("input.txt", "r");
if (!inputFile) {
printf("Error opening input file!\n");
return 1;
}
int resultFlag;
int ruleNumber, generations;
char initialConditions[MAX_LENGTH_INITIAL_CONDITIONS];
resultFlag = fscanf(inputFile, "%d %s %d", &ruleNumber, initialConditions, &generations);
if (3 != resultFlag) { // example: if there are less than 3 lines in the input.txt
printf("Error reading input file! Got %d elements instead of the expectecd 3\n", resultFlag);
fclose(inputFile);
return 1;
}
resultFlag = fclose(inputFile);
if (0 != resultFlag) {
printf("Error closing input file!\n");
return 1;
}
char* rule = ruleToBinaryArray(ruleNumber);
int initialConditionsLength = strlen(initialConditions);
char* cells = (char*)malloc((initialConditionsLength + 1) * sizeof(char));
// char* cells = NULL; // UNCOMMENT TO TEST ERROR HANDLING .. REMEMBER TO COMMENT OUT THE LINE ABOVE
if (NULL == cells) {
printf("Error allocating memory!\n");
exitCode = 1;
goto CLEAN_UP_AND_EXIT_3;
}
cells[initialConditionsLength] = '\0';
for (int i = 0; i < initialConditionsLength; i++)
cells[i] = initialConditions[i] - '0';
char** automatonData = runCellularAutomaton(rule, generations, cells, initialConditionsLength);
// char** automatonData = NULL; // UNCOMMENT TO TEST ERROR HANDLING .. REMEMBER TO COMMENT OUT THE LINE ABOVE
if (NULL == automatonData) {
printf("Error running cellular automaton!\n");
exitCode = 1;
goto CLEAN_UP_AND_EXIT_2;
}
int imageWidth = strlen(initialConditions) + 2 * generations;
resultFlag = outputToFile(automatonData, ruleNumber, generations, initialConditions, imageWidth);
// resultFlag = 1; // UNCOMMENT TO TEST ERROR HANDLING
if (0 != resultFlag) {
printf("Error writing to file!\n");
exitCode = 1;
goto CLEAN_UP_AND_EXIT;
}
CLEAN_UP_AND_EXIT:
for (int i = 0; i < generations; i++)
free(automatonData[i]);
free(automatonData);
CLEAN_UP_AND_EXIT_2:
free(cells);
CLEAN_UP_AND_EXIT_3:
free(rule);
return exitCode;
}