Game of Life, building the public API - C programming - c

I'm building the public API for Game of Life and I don't know how to code this part.
This is a picture of "flow chart" we're suppose to follow:
Steps :
These are the public APIs we're supposed to fill out;
void gofl_get_world(int n_rows, int n_cols, cell_t world[][n_cols], double percent_alive){}
this first function should: Get the initial randomly ordered distribution of cells in the world. This is the usage: gofl_get_world(MAX_ROWS, MAX_COLS, world, 0.1)
void gofl_next_state(int n_rows, int n_cols, cell_t world[][n_cols]){}
This function does this: Calculate the next state of the world according to the rules and the actual state. I.e. this will mark all cells in the world as alive or dead.
Here are the functions we're supposed to build the public API from, I've made these myself as well so they are not pre-defined (they are tested and all returned true):
static void get_cells(cell_t arr[], int size, double percent_alive) {
int n = (int) round(percent_alive*size); //checking if cell dead or alive with size
for (int i = 0; i < size; i++){
if (i < n ){ //cell needs to be over certain thresh hold to be alive
arr[i] = 1; //alive
}
else{
arr[i] = 0; //dead
}
}
static int get_living_neighbours(int n_rows, int n_cols, const cell_t world[][n_cols], int row, int col) {
int sum = 0;
for (int r = row - 1; r <=row + 1; r++){
for(int c = col-1; c<=col +1; c++){
if(!(row == r && col == c) && is_valid_location(n_rows, n_cols, r, c)){
sum = sum + world[r][c];
}
}
}
return sum;
static void array_to_matrix(int n_rows, int n_cols, cell_t matrix[][n_cols], const cell_t arr[], int size) {
for (int i = 0; i < size; i++){
matrix[i/n_rows][i%n_cols] = arr[i];
}
static void shuffle_cells(cell_t arr[], int size) {
for(int i = size; i > 1; i--){
int j = rand()%i;
int tmp = arr[j];
arr[j] = arr[i-1];
arr[i-1] = tmp;
}
Anyone know how I can solve this? I don't know how to perform this action, thanks!

Related

Array declaration fails while trying to declare int array

I've been learning & coding sorting algorithms for some time and recently I've coded merge sort in C, and I've also coded a sort_test function to test the function that I write. In the sort test function, I'm declaring an array and assigning random values to it, but when the array size gets to 1,000,000 the program crashes. Why is that happening?
sort_test.c
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "merge_sort.h"
#include "sort_test.h"
// test size
#define MIN 10
#define MAX 1000000
// int comparator
int cmpInt(const void *elem1,const void * elem2){
int e1 = *(int *)elem1; // i-1
int e2 = *(int *)elem2; // i
if(e2 < e1){
return -1;
} else if(e2 > e1){
return 1;
} else {
return 0;
}
}
// double comparator
int cmpDouble(const void *elem1,const void *elem2){
double e1 = *(double *)elem1;
double e2 = *(double *)elem2;
if(e2 < e1){
return -1;
} else if(e2 > e1){
return 1;
} else {
return 0;
}
}
void initSeed(){
srand(time(NULL));
}
void intSortTest(){
initSeed();
for(size_t i = MIN;i <= MAX;i *=10){
int arr[i];
for(size_t j = 0; j < i;j++){
arr[j] = rand();
}
// sorting the array
mergesort(arr,0,i);
// checking if sorted array hold the
// condition i[0] <= i[1] ... <= i[n].
for(size_t j = 1;j < i;j++){
int *e1 = &arr[j-1];
int *e2 = &arr[j];
assert(cmpInt(e2,e1) <= 0);
}
printf("INT TEST : %7d\tPASSED\n",i);
}
printf("\n");
}
void doubleSortTest(){
initSeed();
for(int i = MIN; i <= MAX; i *= 10){
double arr[i];
for(int j = 0 ; j < i;j++){
arr[j] = (double)(rand() % 100) + 1.0;
}
// perform sort
//insertion_sort(arr,sizeof (double),i,cmpDouble);
for(int j = 1; j < i;j++){
double *e1 = &arr[j-1];
double *e2 = &arr[j];
assert(cmpDouble(e2,e1) <= 0);
}
printf("Double Test : %5d\tPASSED\n",i);
}
printf("\n");
}
sort_test.h
#ifndef SORT_TEST_H
#define SORT_TEST_H
void initSeed();
void intSortTest();
void doubleSortTest();
int cmpDouble(const void *elem1,const void *elem2);
int cmpInt(const void *elem1,const void * elem2);
#endif // SORT_TEST_H
merge_sort.h
#ifndef MERGE_SORT_H
#define MERGE_SORT_H
void mergesort(int *arr,int start,int end);
void merge(int *arr,int start,int med,int end);
#endif // MERGE_SORT_H
merge_sort.c
#include <stdio.h>
#include "sort_test.h"
#include "merge_sort.h"
int main(){
intSortTest();
return 0;
}
void mergesort(int *arr,int start,int end){
if(start < end){
int median = (end + start) / 2;
mergesort(arr,start,median);
mergesort(arr,median+1,end);
merge(arr,start,median,end);
}
}
void merge(int *arr,int start,int median,int end){
int i = start; int j = median+1;
int copy[end+1];
int cIndex = 0;
while(i <= median && j <= end) {
if(arr[j] <= arr[i]){
copy[cIndex++] = arr[j++];
} else {
copy[cIndex++] = arr[i++];
}
}
while(i <= median){
copy[cIndex++] = arr[i++];
}
while(j <= end){
copy[cIndex++] = arr[j++];
}
for(int k = 0; k < cIndex; k++){
arr[start++] = copy[k];
}
}
It is because you are allocating the arrays on the stack. Try the following code instead.
void intSortTest(){
initSeed();
for(size_t i = MIN;i <= MAX;i *=10){
int *arr = malloc(i*sizeof(int)); // <-- changed this
for(size_t j = 0; j < i;j++){
arr[j] = rand();
}
// sorting the array
mergesort(arr,0,i);
// checking if sorted array hold the
// condition i[0] <= i[1] ... <= i[n].
for(size_t j = 1;j < i;j++){
int *e1 = &arr[j-1];
int *e2 = &arr[j];
assert(cmpInt(e2,e1) <= 0);
}
printf("INT TEST : %7d\tPASSED\n",i);
free(arr); // <-- added this
}
printf("\n");
}
EDIT
Also the merge algorithm is incorrect. More precisely, you have a problem with the value list boundaries.
When you define the start and end index of a value list, the values are in arr[start] to arr[end-1], not arr[end]. The number of values is then end-start. With this convention, you have an empty list when start == end.
As a consequence, the function mergesort becomes:
void mergesort(int *arr,int start,int end){
if (start+1 >= end)
return; // a list with 0 or 1 values is already sorted
int median = (end + start) / 2;
mergesort(arr,start,median);
mergesort(arr,median,end);
merge(arr,start,median,end);
}
The merge function then become as follow:
void merge(int *arr,int start,int median,int end){
int i = start; int j = median;
int *copy = malloc((end-start)*sizeof(int)); // use malloc for huge arrays
int cIndex = 0;
while(i < median && j < end) { // not i <= median && j <= end
if(arr[j] <= arr[i]){
copy[cIndex++] = arr[j++];
} else {
copy[cIndex++] = arr[i++];
}
}
while(i < median){ // not i <= median
copy[cIndex++] = arr[i++];
}
while(j < end){ // not j <= median
copy[cIndex++] = arr[j++];
}
for(int k = 0; k < cIndex; k++){
arr[start++] = copy[k];
}
free(copy);
}
As you can see, there are only minor differences.
With this code, your program runs without error.
Now that the code is visible, it is fairly easy to see that you are indeed blowing the stack as I suggested in one of my many comments.
In merge(), you have:
int copy[end+1];
as well as in intSortTest() having:
int arr[i];
where i reaches 1,000,000.
When end is 1,000,000 — it is set from i — you have an array of one million int values being sorted, and a copy with another one million int values (plus 1), so you attempt to place two million 4-byte int values on the stack — and 8,000,000 bytes blows the stack limits. Since 800,000 bytes (the previous size) fits on the stack in both Unix and Windows, it isn't 100% clear which you are using. There isn't much margin for error on Unix/Linux; the limit is thoroughly blown on Windows because neither 4 MB array fits on the stack.
The recommended fix is to use dynamic memory allocation (malloc() et al) instead of stack allocation — in both the sort test function and in the main merge() code.

Optimizing Conway's Game of life

I'm working on speeding up Conway's Game of Life. Right now, the code looks at a cell and then adds up the 3x3 area immediately surrounding the point, then subtracts the value at the point we're looking at. Here's the function that is doing that:
static int neighbors2 (board b, int i, int j)
{
int n = 0;
int i_left = max(0,i-1);
int i_right = min(HEIGHT, i+2);
int j_left = max(0,j-1);
int j_right = min(WIDTH, j+2);
int ii, jj;
for (jj = j_left; jj < j_right; ++jj) {
for (ii = i_left; ii < i_right; ii++) {
n += b[ii][jj];
}
}
return n - b[i][j];
}
And here is the code I've been trying to use to iterate through pieces at a time:
//Iterates through the first row of the 3x3 area
static int first_row(board b, int i, int j) {
int f = 0;
int i_left = max(0,i-1);
int j_left = max(0,j-1);
int j_right = min(WIDTH, j+2);
int jj;
for (jj = j_left; jj < j_right; ++jj) {
f += b[i_left][jj];
}
return f;
}
//Iterates and adds up the second row of the 3x3 area
static int second_row(board b, int i, int j) {
int g = 0;
int i_right = min(HEIGHT, i+2);
int j_left = max(0,j-1);
int j_right = min(WIDTH, j+2);
int jj;
if (i_right != i) {
for (jj = j_left; jj < j_right; ++jj) {
g += b[i][jj];
}
}
return g;
}
//iterates and adds up the third row of the 3x3 area.
static int third_row(board b, int i, int j) {
int h = 0;
int i_right = min(HEIGHT, i+2);
int j_left = max(0,j-1);
int j_right = min(WIDTH, j+2);
int jj;
for (jj = j_left; jj < j_right; ++jj) {
h += b[i_right][jj];
}
return h;
}
//adds up the surrounding spots
//subtracts the spot we're looking at.
static int addUp(board b, int i, int j) {
int n = first_row(b, i, j) + second_row(b, i, j) + third_row(b, i, j);
return n - b[i][j];
}
But, for some reason it isn't working. I have no idea why.
Things to note:
sometimes i == i_right, so we do not want to add up a row twice.
The three functions are supposed to do the exact same thing as neighbors2 in separate pieces.
min and max are functions that were premade for me.
sometimes sometimes j == j_right, so we do not want to add up something twice. I'm pretty confident the loop takes care of this however.
Tips and things to consider are appreciated.
Thanks all. I've been working on this for a couple hours now and have no idea what is going wrong. It seems like it should work but I keep getting incorrect solutions at random spots among the board.
In neighbors2, you set i_left and i_right so that the're limited to the rows of the grid. If the current cell is in the top or bottom row, you only loop through two rows instead of 3.
In first_row() and last_row() you also limit it to the rows of the grid. But the result is that these functions will add the cells on the same row as the current cell, which is what second_row does. So you end up adding those rows twice.
You shouldn't call first_row() when i = 0, and you shouldn't call third_row() when i == HEIGHT.
static int addUp(board b, int i, int j) {
int n = (i == 0 ? 0 : first_row(b, i, j)) +
second_row(b, i, j) +
(i == HEIGHT ? 0 : third_row(b, i, j));
return n - b[i][j];
}
Another option would be to do the check in the functions themselves:
function first_row((board b, int i, int j) {
if (i == 0) {
return 0;
}
int f = 0;
int j_left = max(0,j-1);
int j_right = min(WIDTH, j+2);
int jj;
for (jj = j_left; jj < j_right; ++jj) {
f += b[i][jj];
}
return f;
}
and similarly for third_row(). But doing it in the caller saves the overhead of the function calls.
BTW, your variable names are very confusing. All the i variables are for rows, which go from top to bottom, not left to right.
#include <stdio.h>
#include <stdlib.h>
#define ROWSDISP 50
#define COLSDISP 100
int rows=ROWSDISP+2, cols=COLSDISP+2;
This is to avoid illegal indexes when stepping over the neighbours.
struct onecell {char alive;
char neibs;} **cells;
This is the foundation of a (dynamic) 2D-array, of a small struct.
To create space for each row plus the space to hold an array of row pointers:
void init_cells()
{
int i;
cells = calloc(rows, sizeof(*cells));
for(i=0; i<=rows-1; i++)
cells[i] = calloc(cols, sizeof(**cells));
}
I skip the rand_fill() and glider() funcs. A cell can be set by
cells[y][x].alive=1.
int main(void) {
struct onecell *c, *n1, *rlow;
int i, j, loops=0;
char nbs;
init_cells();
rand_fill();
glider();
while (loops++ < 1000) {
printf("\n%d\n", loops);
for (i = 1; i <= rows-2; i++) {
for (j = 1; j <= cols-2; j++) {
c = &cells[ i ][ j ];
n1 = &cells[ i ][j+1];
rlow = cells[i+1];
nbs = c->neibs + n1->alive + rlow[ j ].alive
+ rlow[j+1].alive
+ rlow[j-1].alive;
if(c->alive) {
printf("#");
n1->neibs++;
rlow[ j ].neibs++;
rlow[j+1].neibs++;
rlow[j-1].neibs++;
if(nbs < 2 || nbs > 3)
c->alive = 0;
} else {
printf(" ");
if(nbs == 3)
c->alive = 1;
}
c->neibs = 0; // reset for next cycle
}
printf("\n");
}
}
return(0);
}
There is no iterating a 3x3 square here. Of the 8 neighbours,
only the 4 downstream ones are checked; but at the same time
their counters are raised.
A benchmark with 100x100 grid:
# time ./a.out >/dev/null
real 0m0.084s
user 0m0.084s
sys 0m0.000s
# bc <<<100*100*1000/.084
119047619
And each of these 100M cells needs to check 8 neighbours, so this is close to the CPU frequency (1 neighbour check per cycle).
It seems twice as fast as the rosetta code solution.
There also is no need to switch the boards. Thanks to the investment in the second field of a cell.

Sorting one array and copying the order over to another

I have two arrays side by side, one lists the different teams and the other lists the scores. I am able to sort the order of scores in descending order. Can this order then be used to move the corresponding team to the correct position of the leader board? eg. move the two teams with 100 points (USA and Germany) to the top of the board
#include <stdio.h>
int main()
{
char teams[18][20]={"England","Ireland","Wales","Scotland","France","Italy","Germany","Uraguay","Belgium","USA","Mexico","Australia","Belize","Denmark","Sweden","Japan","South Africa","Algeria"};
int points[18]={43,5,77,23,89,0,100,46,94,100,45,55,32,65,11,37,26,78};
int i;
int j;
int a;
for (i = 0; i < 18; ++i)
{
printf("%i ",i+1);
printf("%s",teams[i]);
printf("\t%d\n", points[i]);
}
printf("\n");
for (i = 0; i < 18; ++i)
{
for (j = i + 1; j < 18; ++j)
{
if (points[i] < points[j])
{
a = points[i];
points[i] = points[j];
points[j] = a;
}
}
}
for (i = 0; i < 18; ++i)
{
printf("%i ",i+1);
printf("%s",teams[i]);
printf("\t%d\n", points[i]);
}
return 0;
}
As mentioned in a comment, the typical solution is to model your data as an array of structures, rather than separate arrays. This makes sense, since the data is associated with each other.
You'd have something like:
struct score {
const char *name;
int points;
} scores[] = {
{ "England", 43 },
{ "Ireland", 5 },
/* and so on */
};
Then you can use qsort() (or your own sorting code, if that's of interest) to sort entire structure instances, and the all the data will remain together since entire structures are being moved around.
Also arrange your teams array when sorting;
a = points[i];
b = teams[i];
points[i] = points[j];
teams[i] = teams[j];
points[j] = a;
teams[j] = b;
The obvious way (as pointed out by others) is embedding your arrays into a struct, but if you are forced to use parallel arrays you can build your own function and sort both arrays at once:
#include <stdio.h>
static int comp(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
static void swap(int v1[], char *v2[], int a, int b)
{
int temp1;
char *temp2;
temp1 = v1[a];
v1[a] = v1[b];
v1[b] = temp1;
temp2 = v2[a];
v2[a] = v2[b];
v2[b] = temp2;
}
static void sort(int v1[], char *v2[], int left, int right, int (*comp)(const void *, const void *))
{
int i, last;
if (left >= right) return;
swap(v1, v2, left, (left + right) / 2);
last = left;
for (i = left + 1; i <= right; i++) {
if (comp(&v1[i], &v1[left]) < 0)
swap(v1, v2, ++last, i);
}
swap(v1, v2, left, last);
sort(v1, v2, left, last - 1, comp);
sort(v1, v2, last + 1, right, comp);
}
int main(void)
{
char *teams[] = {"England","Ireland","Wales","Scotland","France","Italy","Germany","Uraguay","Belgium","USA","Mexico","Australia","Belize","Denmark","Sweden","Japan","South Africa","Algeria"};
int points[] = {43,5,77,23,89,0,100,46,94,100,45,55,32,65,11,37,26,78};
size_t i, n = sizeof(points) / sizeof(*points);
sort(points, teams, 0, n - 1, comp);
for (i = 0; i < n; i++) {
printf("%s->%d\n", teams[i], points[i]);
}
return 0;
}
Output:
Italy->0
Ireland->5
Sweden->11
Scotland->23
South Africa->26
Belize->32
Japan->37
England->43
Mexico->45
Uraguay->46
Australia->55
Denmark->65
Wales->77
Algeria->78
France->89
Belgium->94
Germany->100
USA->100

How to delete multiple elements from a array at the same time

I want to delete multiple elements from array using index array,this is my code:
// b is an index array, n is size of b,
// player is the array need to be delete elements,
// size is the size of player
void play_cards(int b[],int n,int player[],int *size){
int i;
for(i = 0; i < n; i++)
delete_cards(b[i],player,size);
}
void delete_cards(int n,int player[],int *size){
int i;
for(i = n; i < *size; i++)
player[i] = player[i+1];
*size -= 1;
}
int main(void){
int player[10] = {1,2,3,3,4,4,5,5,6,7};
int index[6] = {2,3,4,5,6,7};
int size = 10;
play_cards(index,6,player,&size);
for(int i = 0; i < size; i++)
printf("%d|",player[i]);
puts("");
return 0;
}
I expect print the player should be 1,2,6,7 instead of 1,2,3,4. How should I fix it?
First I would not call the function delete_cards as it suggests that it deletes multiple cards which it does not - just delete_card would make things more clear.
Anyway - when you change the player array before you have played all cards in the index array, you change the meaning of the indexes. This is why your current code doesn't work.
So you can do two things:
a) Play all cards first and then delete the cards played. This could be done by first marking played card with -1 and then have a loop where you removed all element being -1
or
b) Play a card, delete it and adjust the remaining elements in index by decrementing them by one. Note: This solution requires that index is sorted (lowest first).
Solution a) could look something like this:
void delete_played_cards(int player[],int *size)
{
int i;
int next_pos = 0;
int deleted = 0;
for(i = 0; i < *size; i++)
{
if (player[i] != -1)
{
player[next_pos] = player[i];
if (i != next_pos)
{
player[i] = -1;
}
++next_pos;
}
else
{
++deleted;
}
}
*size -= deleted;
}
void play_cards(int b[],int n,int player[],int *size)
{
int i;
for(i = 0; i < n; i++)
{
player[b[i]] = -1; // Mark card as played
}
delete_played_cards(player,size);
}
int main(void)
{
int player[10] = {1,2,3,3,4,4,5,5,6,7};
int index[6] = {2,3,4,5,6,7};
int size = 10;
play_cards(index,6,player,&size);
for(int i = 0; i < size; i++)
printf("%d|",player[i]);
puts("");
return 0;
}
Modify play_cards:
void play_cards(int b[], int n, int player[], int *size)
{
int i;
for(i = n-1; i >= 0; i--)
delete_cards(b[i],player,size);
}
This will start deleting from the end of array.
As BLUEPIXY mentioned.
here is a pseudocode that you can work with:
given a sorted list, 1..n
for i = 2 up to length of list:
if list[i] is equal to list[i-1]:
shift the sublist [2..] 1 position to the left
else
increment i by 1
If you want to delete easily and efficiently without using loop you can use memcpy
#include <stdio.h>
#include <string.h>
#define INDEX_MAX 6
int main ()
{
int size = 10;
int src[] = {1,2,3,3,4,4,5,5,6,7};
int index[] = {2,3,4,5,6,7};
int x;
size = size - INDEX_MAX;
memcpy(src+2, src+8, sizeof(int)*(size-2));// - 2 since index 1 and 2 remains in the array
for(x = 0; x < size; x++){
printf("%d",src[x]);
}
return(0);
}

Knapsack algorithm for large input

I have developed this knapsack algorithm based on pseudo-code found on wikipedia. It works fine for small number of items and capacity (n=6, v=2014), but it crashes for large numbers (n=5, v=123456789).
Additional problem is, that my program is tested by makefile with time limit set at 1 second.
What can i do to save time and memory?
v - Knapsack capacity
n - Number of items
weight[] - Weights
value[] - Values
int knapSack(int v, int weight[], int value[], int n){
int a, i, j;
int **ks;
ks = (int **)calloc(n+1, sizeof(int*));
for(a = 0; a < (n+1); a++) {
ks[a] = (int *)calloc(v+1, sizeof(int));
}
for (i = 1; i <= n; i++){
for (j = 0; j <= v; j++){
if (weight[i-1] <= j){
ks[i][j] = max(value[i-1] + ks[i-1][j-weight[i-1]], ks[i-1][j]);
} else {
ks[i][j] = ks[i-1][j];
}
}
}
int result = ks[n][v];
for(i = 0; i < (n+1); i++) {
free(ks[i]);
}
free(ks);
return result;
}
An array of 123456789 integer elements declared on the stack will crash many implementations of C. Sounds like this is your problem. Did you declare your arrays inside of a function (on the stack)?
// on heap
static int v[123456789]={0};
// on the stack (inside a function like main() )
int foo()
{
int v[123456789]={0};
}

Resources