segmentation fault when creating connect 4 board c program - c

I'm creating a connect-4 game... I have a lot of it done; however, the way I was creating my board was static & it needed to be dynamic, so I've made a side program to fix this before implementing it in my main program. For some reason, the if & else-if conditionals in this chunk of code create a segmentation fault, and I can't figure out why...
// for the rows/columns of the board
for(row = num_rows - 1; row >= 0; row--){
printf("|");
for(col = 0; col < num_columns; col++){
if(aPtr[row][col] == '0') {
printf("| X ");
}
else if(aPtr[row][col] == '1') {
printf("| O ");
}
else {
printf("| ");
}
}
puts("||");
}
when I comment these conditionals out the board prints just fine & looks like this
------ Connect *Four ------
Connect X Command Line Game
&&===================&&
|| | | | | ||
|| | | | | ||
|| | | | | ||
|| | | | | ||
|| | | | | ||
|| | | | | ||
|| | | | | ||
|| | | | | ||
|| | | | | ||
|| | | | | ||
&&===================&&
1 2 3 4 5
the entirety of this side-program is below, any insight as to why this segmentation fault is occurring will be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
void initialize(int num_rows, int num_cols, char **aPtr) {
int i, r, c;
// create the space for the board
aPtr = malloc(num_rows * sizeof(char*));
for (i = 0; i < num_rows; i++){
aPtr[i] = malloc(num_cols * sizeof (char));
}
// go through the board and set all values equal to -1
for (r = 0; r < num_rows; r++) {
for (c = 0; c < num_cols; c++) {
aPtr[r][c] = '9';
printf("%c", aPtr[r][c]);
}
printf("\n");
}
}
void printBoard(int num_rows, int num_columns, char **aPtr) {
int row, col;
printf("\n");
puts("------ Connect *Four ------");
puts("Connect X Command Line Game");
// for fancy top of board frame
printf("&&");
for(col = 1; col < num_columns; col++) {
printf("====");
}
printf("===");
printf("&&\n");
// for the rows/columns of the board
for(row = num_rows - 1; row >= 0; row--){
printf("|");
for(col = 0; col < num_columns; col++){
// if(aPtr[row][col] == '0') {
// printf("| X ");
// }
// else if(aPtr[row][col] == '1') {
// printf("| O ");
// }
// else {
printf("| ");
// }
}
puts("||");
}
// for fancy bottom of board frame
printf("&&");
for(col = 1; col < num_columns; col++) {
printf("====");
}
printf("===");
printf("&&\n");
printf(" ");
if (col < 100){
for(col = 0; col < num_columns; col++) {
if (col < 10) {
printf(" %d ", col + 1);
}
else {
printf("%d ", col + 1);
}
}
puts("\n");
}
}
// *******************************************************************************************************
// *******************************************************************************************************
int main (int argc, char *argv[]) {
char **aPtr;
int height = 10;
int width = 5;
int i;
initialize(height, width, aPtr);
printBoard(height, width, aPtr);
}

Here is the modification of your code, maybe it will help. Note that I'm passing &aPtr and *aPtr = (char*) malloc(...)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
void initialize(int num_rows, int num_cols, char **aPtr) {
int i, r, c;
// create the space for the board
*aPtr = (char*) malloc(num_rows * sizeof(char*));
if(*aPtr == NULL)
{
free(*aPtr);
printf("Memory allocation failed");
}
for (i = 0; i < num_rows; i++){
aPtr[i] = (char *) malloc(num_cols * sizeof (char));
}
// go through the board and set all values equal to -1
for (r = 0; r < num_rows; r++) {
for (c = 0; c < num_cols; c++) {
aPtr[r][c] = '9';
printf("%c", aPtr[r][c]);
}
printf("\n");
}
}
void printBoard(int num_rows, int num_columns, char **aPtr) {
int row, col;
printf("\n");
puts("------ Connect *Four ------");
puts("Connect X Command Line Game");
// for fancy top of board frame
printf("&&");
for(col = 1; col < num_columns; col++) {
printf("====");
}
printf("===");
printf("&&\n");
// for the rows/columns of the board
for(row = num_rows - 1; row >= 0; row--){
printf("|");
for(col = 0; col < num_columns; col++){
if(aPtr[row][col] == '0') {
printf("| X ");
}
else if(aPtr[row][col] == '1') {
printf("| O ");
}
else {
printf("| ");
}
}
puts("||");
}
// for fancy bottom of board frame
printf("&&");
for(col = 1; col < num_columns; col++) {
printf("====");
}
printf("===");
printf("&&\n");
printf(" ");
if (col < 100){
for(col = 0; col < num_columns; col++) {
if (col < 10) {
printf(" %d ", col + 1);
}
else {
printf("%d ", col + 1);
}
}
puts("\n");
}
}
// *******************************************************************************************************
// *******************************************************************************************************
int main (int argc, char *argv[]) {
char *aPtr;
int height = 10;
int width = 5;
int i;
initialize(height, width, &aPtr);
printBoard(height, width, &aPtr);
}
Note that you are doing: aPtr[r][c] = '9'; so your board is empty, but if you change it to say 0you would get something like:
------ Connect *Four ------
Connect X Command Line Game
&&===================&&
|| X | X | X | X | X ||
|| X | X | X | X | X ||
|| X | X | X | X | X ||
|| X | X | X | X | X ||
|| X | X | X | X | X ||
|| X | X | X | X | X ||
|| X | X | X | X | X ||
|| X | X | X | X | X ||
|| X | X | X | X | X ||
|| X | X | X | X | X ||
&&===================&&
1 2 3 4 5
I'm assuming that's what you expected?

Related

Trying to sort a struct array in Descending Order

To preface what I'm trying to do - I'm trying to make a Shortest Job First (SJF), the OS algo in C.
And to handle the sort-by-burst-time, I'm pushing all the ready processes in a stack, and then sorting that stack in a descending order. So for example - if the stack looks like 3,5,1,2 with "2" on top, I'm trying to sort it as: 5,3,2,1 with "1" on top. So when I start using pop, I'll get elements in the order I require.
But the problem with the code I'm going to show is, it orders 1,1,5,3 as 5,1,1,3. The last process "3" is never sorted.
Code for Sorting:
void sortByBurst() {
int size = top;
struct fcfs temp;
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < (size - 1 - i); j++) {
if (stack[j].burst < stack[j + 1].burst) {
temp = stack[j];
stack[j] = stack[j + 1];
stack[j + 1] = temp;
}
}
}
}
And in case you want to see where I'm handling the rest of the logic i.e making decisions on what to push - this is the for loop for that:
for (i = 0; i < numOfProc; i++) {
if (first_process == 1 && p[i].arrival <= current_time && p[i].completed == 0) {
min_index = i;
} else if (first_process == 0 && last_index != -1) {
for (int k = 0; k < numOfProc; k++) {
if (p[k].completed == 0 && p[k].arrival <= p[last_index].max_slot && p[k].inQ != 1) {
push(p[k]);
p[k].inQ = 1;
critical_case = 1;
} else if (p[k].completed == 0 && p[k].arrival > finalp[last_index].max_slot && p[k].inQ != 1) {
min_index = k;
}
}
if (critical_case == 1) {
sortByBurst();
struct fcfs compare = pop();
for (int l = 0; l < numOfProc; l++) {
if (compare.pid == p[l].pid) {
min_index = l;
break;
}
}
}
break;
}
}
The input I'm testing my code with is:
1. Process 1 | 2 (Arrival) | 1 (Burst)
2. Process 2 | 1 (Arrival) | 5 (Burst)
3. Process 3 | 4 (Arrival) | 1 (Burst)
4. Process 4 | 0 (Arrival) | 6 (Burst)
5. Process 5 | 2 (Arrival) | 3 (Burst)
Required Output:
1. Process 4 | 0 (Arrival) | 6 (Burst)
2. Process 1 | 2 (Arrival) | 1 (Burst)
3. Process 3 | 4 (Arrival) | 1 (Burst)
4. Process 5 | 2 (Arrival) | 3 (Burst)
5. Process 2 | 1 (Arrival) | 5 (Burst)
Output I'm Getting:
1. Process 4 | 0 (Arrival) | 6 (Burst)
2. Process 5 | 2 (Arrival) | 3 (Burst)
3. Process 3 | 4 (Arrival) | 1 (Burst)
4. Process 1 | 2 (Arrival) | 1 (Burst)
5. Process 2 | 1 (Arrival) | 5 (Burst)
As you can see, the Process 5 should be at 4th place in the list. But because in Stack - it's still on Top even after sorting, the algo is not working as it should. Kindly look into what I'm doing wrong here.
Complete Code:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
struct fcfs {
int pid, arrival, burst, min_slot, max_slot, wait_time, completed, inQ;
};
struct fcfs stack[10];
int top = -1;
void push(struct fcfs process);
struct fcfs pop();
void sortByBurst();
void pline(int x);
void main() {
int i, numOfProc, j;
int counter = 0;
int current_time = 0;
int completed = 0;
struct fcfs p[10], finalp[10];
int first_process = 1;
int prevMaxSlot = 0;
int last_index = -1;
int critical_case = 0;
printf("Enter total number of Processes \n");
scanf("%d", &numOfProc);
for (i = 0; i < numOfProc; i++) {
printf("Enter Arrival Time & Burst Time for Process %d: \n", i + 1);
scanf("%d %d", &p[i].arrival, &p[i].burst);
p[i].pid = i + 1;
p[i].wait_time = 0;
p[i].completed = 0;
p[i].inQ = 0;
}
int prev = 0;
while (completed != numOfProc) {
int min_index = -1;
for (i = 0; i < numOfProc; i++) {
if (first_process == 1 && p[i].arrival <= current_time && p[i].completed == 0) {
min_index = i;
} else if (first_process == 0 && last_index != -1) {
for (int k = 0; k < numOfProc; k++) {
if (p[k].completed == 0 && p[k].arrival <= p[last_index].max_slot && p[k].inQ != 1) {
push(p[k]);
p[k].inQ = 1;
critical_case = 1;
} else if (p[k].completed == 0 && p[k].arrival > finalp[last_index].max_slot && p[k].inQ != 1) {
min_index = k;
}
}
if (critical_case == 1) {
sortByBurst();
struct fcfs compare = pop();
for (int l = 0; l < numOfProc; l++) {
if (compare.pid == p[l].pid) {
min_index = l;
break;
}
}
}
break;
}
}
if (min_index == -1) {
current_time++;
} else {
if (p[min_index].arrival == prevMaxSlot) {
p[min_index].min_slot = prevMaxSlot;
p[min_index].max_slot = p[min_index].arrival + p[min_index].burst;
} else if (p[min_index].arrival < prevMaxSlot || p[min_index].arrival == prevMaxSlot) {
p[min_index].min_slot = prevMaxSlot;
p[min_index].max_slot = p[min_index].min_slot + p[min_index].burst;
} else if (p[min_index].arrival > prevMaxSlot) {
p[min_index].min_slot = p[min_index].arrival;
p[min_index].max_slot = p[min_index].arrival + p[min_index].burst;
}
p[min_index].wait_time = (first_process == 1) ? 0 : abs(p[i].min_slot - prev);
p[min_index].completed = 1;
prev = current_time;
prevMaxSlot = p[min_index].max_slot;
finalp[counter++] = p[min_index];
first_process = 0;
last_index = min_index;
completed++;
}
}
pline(44);
printf("Slot\tPID\tArrival\t\tBurst\n");
pline(44);
for (i = 0; i < numOfProc; i++) {
if ((finalp[i].min_slot - finalp[i - 1].max_slot) > 0 && i > 0) {
printf("%d - %d\tNONE\tNONE\t\tNONE\n", finalp[i - 1].max_slot, finalp[i].min_slot);
} else if ((abs(0 - finalp[i].min_slot) > 0 && i == 0)) {
printf("0 - %d\tNONE\tNONE\t\tNONE\n", finalp[i].min_slot);
}
printf("%d - %d\t%d\t%d\t\t%d\n", finalp[i].min_slot, finalp[i].max_slot, finalp[i].pid, finalp[i].arrival,
finalp[i].burst);
}
pline(44);
}
void pline(int x) {
for (int i = 0; i < x; i++) {
printf("-");
}
printf("\n");
}
void push(struct fcfs process) {
if (top == 10)
printf("\n Overflow");
else {
top = top + 1;
stack[top] = process;
}
}
struct fcfs pop() {
struct fcfs process;
if (top == -1)
printf("Underflow");
else {
process = stack[top];
top = top - 1;
}
return process;
}
void sortByBurst() {
int size = top + 1;
struct fcfs temp;
for (int i = 1; i < size - 1; i++) {
for (int j = 0; j < (size - 1 - i); j++) {
if (stack[j].burst < stack[j + 1].burst) {
temp = stack[j];
stack[j] = stack[j + 1];
stack[j + 1] = temp;
}
}
}
}
The issue was with top & i = 1;
In the sorting function, int size = top + 1 and initializing the for loop with i = 0 fixed it.
Thanks a lot to all who contributed.

Pattern is being printed weird when used in an array in c

I have created an array and some functions that print different patterns each. My problem is that they are printed inside the array in a weird way. The below is the main part of the code and just one function for the example.
int castle(int patternWidth, int doorStart, int doorEnd, int N, int i, int j, int row, int col, char** array)
{
if (N >= 3 && N <= 20)
{
for (i = 1; i <= (N + 1); i++)
{
array[row][col] = '*'; col++;
array[row][col] = ' '; col++;
}
row++;
patternWidth = (((N + 1) * 2) - 1);
doorStart = (patternWidth - 3) / 2;
doorEnd = doorStart + 3;
for (i = 0; i < N; i++)
{
for (j = 1; j <= patternWidth; j++)
{
if(N - i <= 2 && j > doorStart && j <= doorEnd)
{
array[row][col] = ' '; col++;
}
else
{
array[row][col] = '*'; col++;
}
}
row++;
}
}
return 0;
}
int main()
{
int N = 0, M = 0, i = 0, j = 0, a = 0, b = 0, s = 0, width = 0, height = 0, patternWidth = 0, doorStart = 0, doorEnd = 0, option = 0, num = 3, col = 0, row = 0;
char** array;
printf("Give height board size:");
scanf("%d", &height);
printf("Give width board size:");
scanf("%d", &width);
array = (char**)malloc(height * sizeof(char*));
for (i = 0; i < width; i++)
{
array[i] = (char*)malloc(height * sizeof(char));
}
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
array[i][j] = ' ';
}
}
while (option != 6)
{
printf("\nOption: 1-5, 6 to exit\n"
"1) Stairs and flag\n"
"2) Castle\n"
"3) Trap door\n"
"4) Platform\n"
"5) Obstacles\n"
"Option:");
scanf("%d", &option);
if (option == 1)
{
printf("Valid values 6 - 20\n");
printf("Size:");
scanf("%d", &N);
printf("Height Position:");
scanf("%d", &row);
printf("Width Position:");
scanf("%d", &col);
stairs_flag(N, i, j, b, a, num, col, row, array);
}
else if (option == 2)
{
printf("Valid values 3 - 15\n");
printf("Size:");
scanf("%d", &N);
printf("Height Position:");
scanf("%d", &row);
printf("Width Position:");
scanf("%d", &col);
castle(patternWidth, doorStart, doorEnd, N, i, j, row, col, array);
}
else if (option == 3)
{
printf("Valid values 3 - 18\n");
printf("Size of N:");
scanf("%d", &N);
printf("Height Position:");
scanf("%d", &row);
printf("Width Position:");
scanf("%d", &col);
trap_door(N, patternWidth, i, j, col, row, array);
}
else if (option == 4)
{
printf("Valid values of N 3 - 20\n");
printf("Size of N:");
scanf("%d", &N);
printf("Valid values of M 6, 8, 10, 12, 14, 16, 18, 20\n");
printf("Size of M");
scanf("%d", &M);
printf("Height Position:");
scanf("%d", &row);
printf("Width Position:");
scanf("%d", &col);
platform(N, M, i, j, col, row, array);
}
else if (option == 5)
{
printf("Valid values 2 - 10\n");
printf("Size of N:");
scanf("%d", &N);
printf("Height Position:");
scanf("%d", &row);
printf("Width Position:");
scanf("%d", &col);
obstacles(N, i, s, j, patternWidth, row, col, array);
}
print_array(array, height, width);
}
free(array);
return 0;
}
The expected result and the correct one is this :
|------------------------------------------------------------|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| * * * * * |
| ********* |
| ********* |
| *** *** |
| *** *** |
| |
| |
| |
| |
| |
|------------------------------------------------------------|
But the actual result is this:
|------------------------------------------------------------|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| * * * * * |
| ********* |
| ********* |
| *** *** |
| *** *** |
| |
| |
| |
| |
| |
|------------------------------------------------------------|
For example, in the two arrays above, the board is 60 width and 20 height and for the pattern I gave the position 10 for both height and width. Every line of the pattern should be under the previous one and print a pattern but in reality it prints every line under the previous one but further more than the previous. How can I correct this? Is there any mistake in the function code. For every function I have done the same thing. I've put array[row][col] = '*'; col++; for the asterisks and array[row][col] = ' '; col++; for the spaces and row++; to print each line in a new line.
Thank you for your time
The problem seems to be that your column index col keeps increasing throughout the castle() function. If you want the asterisks to be aligned under each other, you need to set the column index back to its original value at the start of the for-loops.
For example, you could make it
int castle(int patternWidth, int doorStart, int doorEnd, int N, int i, int j, int row, int col, char** array)
{
int column_index = col;
if (N >= 3 && N <= 20)
{
for (i = 1; i <= (N + 1); i++)
{
array[row][col] = '*'; col++;
array[row][col] = ' '; col++;
}
row++;
patternWidth = (((N + 1) * 2) - 1);
doorStart = (patternWidth - 3) / 2;
doorEnd = doorStart + 3;
for (i = 0; i < N; i++)
{
for (j = 1; j <= patternWidth; j++)
{
col = column_index;
if(N - i <= 2 && j > doorStart && j <= doorEnd)
{
array[row][col] = ' '; col++;
}
else
{
array[row][col] = '*'; col++;
}
}
row++;
}
}
return 0;
}
where I added a command int column_index = col; which stores the original value at the start of the function, and a line col = column_index; at the start of the inner for-loop, putting the stored value back in the variable.

Adding numbers to a grid C

So I am relatively new to C and have been practicing questions on it. So I came across the question, 'Where can I go?': http://www.chegg.com/homework-help/questions-and-answers/c-coding-java-c--c-coding-bouncy-string-tasked-write-program-take-parameters-command-line--q19411844
I manage to write a part of the code, but I am not sure how to get this
| | | |
| | | |
| | | |
| |X| |
I somewhat have the logic of when the counter for width = x - 1, counter for width = x + 1, counter for height = y - 1 (basically the first few steps that can be moved to from the starting position, X) the numbers placed there would be limit - 1.
Same for when it goes on
for i less than or equal to limit
the spaces between the limit - 1, will now be filled with limit - 2. So it will be like x-1 && y-1, y-2, y-1 && x+1, x+2 and so on until the last where 0 is placed.
But how do you write this and fix it in the for loop?
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main()
{
int width, height, x, y, max;
printf("Enter width: ");
scanf("%d\n", &width);
printf("Enter height: ");
scanf("%d\n", &height);
printf("Enter x: ");
scanf("%d\n", &x);
printf("Enter y: ");
scanf("%d\n", &y);
printf("Enter walking limit: ");
scanf("%d\n", &max);
int b = 0, a = 0; // initalize local variable
for (a = 0; a < height; a++) {
// fill the width
for (b = 0; b < width + 1; b++ ) {
printf("|");
if (b==x && a==y)
{
printf("X");
}else if(((b==x-1) && (a==y)) || ((b==x+1) && (a==y)) || ((a==y-1) && (b==x)))
{
printf("%d", max-1);
}else if(//i am not sure if this will be needed)
{
for(int i = 2; i <= max; i++)
{
//add max - i to spaces after C until max is over.
}
}
}
printf("\n");
}
return 0;
}
You should split your code in several functions.
I have done a quick example below.
First we need a function to display the array.
You need to create your array, see the malloc.
Then you set the max steps at the correct position.
Then you need a function to do the propagation, this is a very naive way to do.
Scan the array and set to the value minus one all the cell around.
Do it max times.
For example:
Enter width: 9
Enter height: 9
Enter x: 3
Enter y: 7
Enter walking limit: 3
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | |0| | | | | |
| | |0|1|0| | | | |
| |0|1|2|1|0| | | |
|0|1|2|3|2|1|0| | |
| |0|1|2|1|0| | | |
The code
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
static void array_print(int *array, int width, int height)
{
for (int i = 0; i < height; i++) {
printf("|");
for (int j = 0; j < width; j++) {
int val = array[i * width + j];
if (val < 0) {
printf(" |");
} else {
printf("%d|", val);
}
}
printf("\n");
}
}
/**
*
* Update the array if x, y is inside the limit and
* if val is greater than the already set value
*
*/
static void
array_upate(int *array, int width, int height, int x, int y, int val) {
if (x >= 0 && x < width && y >= 0 && y < height) {
int prev = array[y * width + x];
if (val > prev) {
array[y * width + x] = val;
}
}
}
static void array_propagate(int *array, int width, int height)
{
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int val = array[i * width + j];
if (val > 0) {
array_upate(array, width, height, j, i - 1, val - 1);
array_upate(array, width, height, j, i + 1, val - 1);
array_upate(array, width, height, j - 1, i, val - 1);
array_upate(array, width, height, j + 1, i, val - 1);
}
}
}
}
int main()
{
int width, height, x, y, max;
int *array;
printf("Enter width: ");
scanf("%d", &width);
printf("Enter height: ");
scanf("%d", &height);
printf("Enter x: ");
scanf("%d", &x);
printf("Enter y: ");
scanf("%d", &y);
printf("Enter walking limit: ");
scanf("%d", &max);
/* allocate the array */
array = malloc(sizeof(int) * width * height);
/* Set all to -1 */
memset(array, -1, sizeof(int) * width * height);
/* set the start to max */
array_upate(array, width, height, x, y, max);
/* do the propagation */
while (max-- > 0) {
array_propagate(array, width, height);
}
array_print(array, width, height);
free(array);
}

C: Program that recursively computes matrix determinant

I am trying to make this program, but it is not working, its failing in attributing values for the second line of the aux matrix, and i cant see why, can anyone help me? Thanks!
Oh, and I have already putted some debugging lines, and, apparently, everything is fine, it's just not attributing the values.
#include <stdio.h>
#include <math.h>
void zerar(int n,int m[][n]) {
int i, j;
for (i=0; i<n; i++) {
for (j=0; j<n; j++) {
m[i][j] = 0;
}
}
}
void printm(int n, int matriz[][n]) {
int i,j;
for (i=0; i<n; i++) {
for (j=0; j<n; j++) {
printf("\t%d", matriz[i][j]);
}
printf("\n");
}
}
int det(int n, int m[][n]) {
int i, j, k, x, y, soma=0, aux[n][n];
zerar(n, aux);
if (n < 1) {}
else if (n == 1) {
return m[0][0];
}
else if (n == 2) {
soma = (m[0][0] * m[1][1]) - (m[0][1] * m[1][0]);
return soma;
}
else {
for (i=0; i<n; i++) {
for (j=1, x=0; j<n; j++) {
for (k=0, y=0; k<n; k++) {
if (k == i) {
continue;
}
else {
printf("\n\n");
printf("\nx=%d, y=%d, j=%d, k=%d, i=%d\n", x, y, j, k, i);
aux[x][y] = m[j][k];
printm(n-1, aux);
y++;
}
}
x++;
}
soma += m[0][i]*pow(-1, i+2)*det(n-1, aux);
}
return soma;
}
}
int main()
{
int m[3][3] = {{4, 3, 2}, {1, 4, 5}, {2, 1, 2}};
det(3, m);
printf("%d", det(3, m));
printf("\n\n");
printm(3, m);
printf("\n\n");
}
When the input matrix is of size n x n, the size of the auxiliary matrix, aux, needs to be n-1 x n-1.
Change
int i, j, k, x, y, soma=0, aux[n][n];
to
int i, j, k, x, y, soma=0, aux[n-1][n-1];
You said in a comment:
Can someone explain me please why it have to be that way?
If you use aux[n][n] and n is 3, the memory layout of the object is:
+---+---+---+---+---+---+---+---+---+
| | | | | | | | | |
+---+---+---+---+---+---+---+---+---+
and you fill up the data as though it is a 2 x 2 matrix.
0 1 2
+---+---+---+---+---+---+---+---+---+
| x | x | | x | x | | | | |
+---+---+---+---+---+---+---+---+---+
In the next recursive call, you treat that memory as though it is a 2 x 2 array.
0 1
+---+---+---+---+---+---+---+---+---+
| x | x | | x | x | | | | |
+---+---+---+---+---+---+---+---+---+
^ ^
| Ignored
Using uninitialized array element
In theory, the program is subject to undefined behavior if you use aux[n][n] instead of aux[n-1][n-1].

Tile merging algorithm 2048 game

I am trying to recreate the game 2048 in C, but I can't get the algorithms to move or merge tiles together to function properly.
In the original 2048 game you would move tiles together like this:
2 | 2 | 4 | 4 4 | 8 | |
---+---+---+--- *swipes to the left* -> ---+---+---+---
8 | | 8 | 16| | |
So two tiles that are the same can merge into one tile that is twice the size. My version is almost the same, but instead of using numbers I use characters that increment by one when they merge, so[A|A] would merge to [B], etc. I did that only to not have to deal with varying size tiles.
So my board is stored as a 4*4 char array inside a struct I called grid (I know probably a bit redundant)
typedef struct grid {
char tiles[4][4];
} Grid;
I have tried to make algorithms to move and merge up, down, left and right, but they don't work properly.
void pushLeft(Grid * grid)
{
int i, j, k;
for(i = 0; i < 4; i++) //Row number i
{
for(j = 1; j < 4; j++) //Column number j
{
if(grid->tiles[i][j] != ' ') //tile is not empty
{
int flag = 1; //flag to prevent merging more than one level at a time
//Starting on column k, push tile as far to the left as possible
for(k = j; k > 0; k--)
{
if(grid->tiles[i][k-1] == ' ') //neighbor tile is empty
{
grid->tiles[i][k-1] = grid->tiles[i][k];
grid->tiles[i][k] = ' ';
}
else if(grid->tiles[i][k-1] == grid->tiles[i][k] && flag) //neighbor equals
{
grid->tiles[i][k-1]++;
grid->tiles[i][k] = ' ';
flag = 0;
}
else //Can't push or merge
{
flag = 1;
break;
}
}
}
} // Done with row
}
}
void pushRight(Grid * grid)
{
int i, j, k;
for(i = 0; i < 4; i++) //Row number i
{
for(j = 2; j >= 0; j--) //Column number j
{
if(grid->tiles[i][j] != ' ') //tile is not empty
{
int flag = 1; //flag to prevent merging more than one level at a time
//Starting on column k, push tile as far to the right as possible
for(k = j; k < 3; k++)
{
if(grid->tiles[i][k+1] == ' ') //neighbor tile is empty
{
grid->tiles[i][k+1] = grid->tiles[i][k];
grid->tiles[i][k] = ' ';
}
else if(grid->tiles[i][k+1] == grid->tiles[i][k] && flag) //neighbor equals
{
grid->tiles[i][k+1]++;
grid->tiles[i][k] = ' ';
flag = 0;
}
else //Can't push or merge
{
flag = 1;
break;
}
}
}
} // Done with row
}
}
void pushUp(Grid * grid)
{
int i, j, k;
for(i = 0; i < 4; i++) //Column number i
{
for(j = 1; j < 4; j++) //Row number j
{
if(grid->tiles[j][i] != ' ') //tile is not empty
{
int flag = 1; //flag to prevent merging more than one level at a time
//Starting on row k, push tile as far upwards as possible
for(k = j; k > 0; k--)
{
if(grid->tiles[k-1][i] == ' ') //neighbor tile is empty
{
grid->tiles[k-1][i] = grid->tiles[i][k];
grid->tiles[k][i] = ' ';
}
else if(grid->tiles[k-1][i] == grid->tiles[i][k] && flag) //neighbor equals
{
grid->tiles[k-1][i]++;
grid->tiles[k][i] = ' ';
flag = 0;
}
else //Can't push or merge
{
flag = 1;
break;
}
}
}
} // Done with column
}
}
void pushDown(Grid * grid)
{
int i, j, k;
for(i = 0; i < 4; i++) //Column number i
{
for(j = 2; j >= 0; j--) //Row number j
{
if(grid->tiles[j][i] != ' ') //tile is not empty
{
int flag = 1; //flag to prevent merging more than one level at a time
//Starting on row k, push tile as far down as possible
for(k = j; k < 3; k++)
{
if(grid->tiles[k+1][i] == ' ') //neighbor tile is empty
{
grid->tiles[k+1][i] = grid->tiles[i][k];
grid->tiles[k][i] = ' ';
}
else if(grid->tiles[k+1][i] == grid->tiles[i][k] && flag) //neighbor equals
{
grid->tiles[k+1][i]++;
grid->tiles[k][i] = ' ';
flag = 0;
}
else //Can't push or merge
{
flag = 1;
break;
}
}
}
} // Done with column
}
}
I tested these algorithms with some hardcoded testdata. The algorithm to push the tiles to the left seems to be working correctly. pushRight almost works, but it merges two levels at the same time, so [B|A|A] merges into [C] but should merge into [B|B].
pushUp seems to be almost always just wiping the entire board with empty tiles (spaces).
pushDows seems to be removing some tiles.
Does anyone see the problem or know a way to do this? I have thought about using recursive algorithms, but I just can't wrap my head around it.
I would personally break the swipe into two steps as the swipe left and swipe right are actually functionally the same regarding tile combination. The only difference is that the remaining tiles are bunched to either the left or the right depending on direction.
Below is a quick algorithm to replace two tiles with the a new one. I scan left->right and replace the left tile with the new tile, zero the right tile and then make sure I exclude this new tile from comparison:
typedef struct grid {
char tiles[4][4];
} Grid;
void eliminateHoriz (Grid* g)
{
int row, col, col2;
for (row=0; row<4; row++)
{
for (col=0; col<4; col++)
{
if (g->tiles[row][col])
{
for (col2=col+1; col2<4; col2++)
{
if (g->tiles[row][col2])
{
if (g->tiles[row][col] == g->tiles[row][col2])
{
g->tiles[row][col++] *= 2;
g->tiles[row][col2] = 0;
}
break;
}
}
}
}
}
}
void showGrid (Grid* g)
{
int row, col;
for (row=0; row<4; row++)
for (col=0; col<4; col++)
printf ("%4d%c",
g->tiles[row][col],
col == 3 ? '\n' : ' ');
printf ("\n");
}
int main()
{
Grid g = {{2,2,4,4,
8,0,8,0,
8,8,8,4,
2,2,2,2}};
showGrid (&g);
eliminateHoriz (&g);
showGrid (&g);
system ("pause");
return 0;
}
Output of this:
2 2 4 4
8 0 8 0
8 8 8 4
2 2 2 2
4 0 8 0
16 0 0 0
16 0 8 4
4 0 4 0
After this a simple compaction step could be made, or output realtime to a second buffer, or which ever. Less duplication.
I only have done the case of pushing the lines to the left, but it the same method for every direction. I took the code of the answer and modify it; take a look:
typedef struct grid {
int tiles[4][4];
} Grid;
/* Functions prototypes */
void pushLeft(Grid* grid);
void showGrid (Grid* g);
void find_great_tile(Grid* grid);
/* Main function */
int main()
{
Grid g = {{4,2,2,8,
2,8,2,2,
16,2,0,2,
128,128,64,64}};
/*
The sequence is:
--> Show the grid
--> PushLeft
--> Find great tile
--> PushLeft
--> Show the grid
*/
printf("\n\n\n\n");
showGrid (&g);
printf("\n\n\n\n");
pushLeft(&g);
showGrid (&g);
printf("\n\n\n\n");
find_great_tile(&g);
showGrid(&g);
printf("\n\n\n\n");
pushLeft(&g);
showGrid(&g);
printf("\n\n\n\n");
return 0;
}
/* Functions definitions */
void pushLeft(Grid* grid){
int row, col, col2;
for (row = 0; row < 4; row++)
{
for (col = 0; col < 4; col++)
{
if (!grid->tiles[row][col])
{
for (col2 = col+1; col2 < 4; col2++)
{
if (grid->tiles[row][col2])
{
/*
if (grid->tiles[row][col] == grid->tiles[row][col2])
{
grid->tiles[row][col++] *= 2;
grid->tiles[row][col2] = 0;
}
break;
*/
grid->tiles[row][col] = grid->tiles[row][col2];
grid->tiles[row][col2] = 0;
break;
}
}
}
}
}
}
void showGrid (Grid* grid){
int row, col;
for(row = 0; row < 4; row++){
fprintf(stdout, "\t\t |");
for(col = 0; col < 4; col++)
{
/*
In case there's any number in the matrix, it will print those numbers, otherwise, it'll print a space (it is the alternative of putting a 0)
*/
if(grid->tiles[row][col])
{
printf("%4d |", grid->tiles[row][col]);
}else
printf("%4c |", ' ');
}
fprintf(stdout, "\n\n");
}
}
void find_great_tile(Grid* grid){
int row, col, col2;
for(row = 0; row < 4; row++)
{
for(col = 0; col < 4; col++)
{
if(grid->tiles[row][col])
{
col2 = col+1;
if(grid->tiles[row][col2])
{
if(grid->tiles[row][col] == grid->tiles[row][col2])
{
grid->tiles[row][col++] *= 2;
grid->tiles[row][col2] = 0;
}
}
}
}
}
}
Output of this:
| 4 | 2 | 2 | 8 |
| 2 | 8 | 2 | 2 |
| 16 | 2 | | 2 |
| 128 | 128 | 64 | 64 |
| 4 | 2 | 2 | 8 |
| 2 | 8 | 2 | 2 |
| 16 | 2 | 2 | |
| 128 | 128 | 64 | 64 |
| 4 | 4 | | 8 |
| 2 | 8 | 4 | |
| 16 | 4 | | |
| 256 | | 128 | |
| 4 | 4 | 8 | |
| 2 | 8 | 4 | |
| 16 | 4 | | |
| 256 | 128 | | |
Of course, you can compress the steps doing:
--> PushLeft
--> FindGreatTile
--> PushLeft

Resources