-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMain2.c
205 lines (160 loc) · 7.24 KB
/
Main2.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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Main2.c
This program is an optimized version of Main.c Where Main.c allocates a chunk of memory for each
line, the goal of this implementation is to allocate a single chunk of memory for the entire cellular
automaton. This should hopefully reduce the run time of the program compaired to Main.c
*/
#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] + '0';
}
char* runCellularAutomaton(const char* rule, const int generations, char* cells, int initialConditionsLength) {
const int imageWidth = initialConditionsLength + 2 * generations;
const int fullAutomatonSize = generations * (imageWidth + 1) ;
char* automatonData = (char*)malloc((fullAutomatonSize) * sizeof(char)); // plus 1 to hold the null terminator
if (NULL == automatonData) {
printf("Error allocating memory!\n");
return NULL;
}
int length = initialConditionsLength;
int initialOffset = (imageWidth - initialConditionsLength) / 2;
// set the entire automaton to 0
memset(automatonData, '0', (fullAutomatonSize) * sizeof(char));
// set the new line for each generation
for (int i = 0; i < generations; i++)
automatonData[i * imageWidth + (imageWidth - 1)] = '\n';
// set the very last char to be the null terminator
// automatonData[fullAutomatonSize] = '\0';
// set the first generation to be the content of cells
memcpy(automatonData + initialOffset, cells, initialConditionsLength * sizeof(char));
length += 2;
char neighborhood[4];
neighborhood[3] = '\0';
// return automatonData;
for (int i = 1; i < generations; i++) {
int paddingOffset = initialOffset - i;
// int paddingOffset = initialOffset - i - (1 * i);
for (int j = paddingOffset; j < paddingOffset + length; j++) {
// neighborhood[0] = automatonData[(i - 1) * (imageWidth + 1) + j - 1];
// neighborhood[1] = automatonData[(i - 1) * (imageWidth + 1) + j ] ;
// neighborhood[2] = automatonData[(i - 1) * (imageWidth + 1) + j + 1 ];
neighborhood[0] = automatonData[((i - 1) * (imageWidth + 1) + j - 1 )- i];
neighborhood[1] = automatonData[((i - 1) * (imageWidth + 1) + j )- i ] ;
neighborhood[2] = automatonData[((i - 1) * (imageWidth + 1) + j + 1 )- i];
for (int k = 0; k < 3; k++)
if (neighborhood[k] != '0' && neighborhood[k] != '1') {
printf("Error: (i, j) is (%d, %d)\n", i, j);
// show the automaton data
printf("\"\"\"\n%s\n\"\"\"\n", automatonData);
// free the allocated memory
free(automatonData);
return NULL;
}
// automatonData[i * (imageWidth + 1) + j] = calculateCell(neighborhood, rule);
// automatonData[i * (imageWidth + 1) + j] = '1';
// automatonData[(i * (imageWidth + 1) + j) - i] = calculateCell(neighborhood, rule);
automatonData[(i * (imageWidth + 1) + j) - i] = '1';
}
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_c2.pbm", ruleNumber, generations, initialConditions);
// Calculate the maximum possible size of the content
// Each cell will be '0' or '1' plus a newline character at the end of each generation.
// Plus the header size (assuming 20 characters for "P1\n", imageWidth, and generations)
int maxSize = generations * (imageWidth + 1) + 21;
char *content = (char *)malloc(sizeof(char) * maxSize);
if (!content) {
printf("Error allocating memory for file content!\n");
return 1; // Memory allocation failed
}
// Start building the content
int offset = sprintf(content, "P1\n%d %d\n", imageWidth, generations);
offset += sprintf(content + offset, "%s\n", automatonData);
FILE *file = fopen(filename, "w");
if (!file) {
printf("Error creating output file!\n");
free(content); // Free allocated memory
return 1;
}
// Write the entire content in one go
fputs(content, file);
fclose(file);
// Free the allocated memory for the content
free(content);
return 0;
}
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';
cells[i] = initialConditions[i];
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;
}
printf("automata data --> \"\"\"\n%s\n\"\"\"", automatonData); // UNCOMMENT TO PRINT THE AUTOMATON DATA (FOR TESTING PURPOSES
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;
}