Nested Loop for C Programming - c

I have some problem about Nested Loop on C programming
I tried to print the list like this:
| |0|1|2|3|4|5|6|7|8|9|
|0| | | | | | | | | | |
|1| | | | | | | | | | |
|2| | | | | | | | | | |
|3| | | | | | | | | | |
|4| | | | | | | | | | |
|5| | | | | | | | | | |
|6| | | | | | | | | | |
|7| | | | | | | | | | |
|8| | | | | | | | | | |
|9| | | | | | | | | | |
but there are something problem when i type my code and display:
| |0|1|2|3|4|5|6|7|8|9|
|0|0|0|0|0|0|0|0|0|0|0|
|1|0|1|1|1|1|1|1|1|1|1|
|2|0|2|2|2|2|2|2|2|2|2|
|3|0|3|3|3|3|3|3|3|3|3|
|4|0|4|4|4|4|4|4|4|4|4|
|5|0|5|5|5|5|5|5|5|5|5|
|6|0|6|6|6|6|6|6|6|6|6|
|7|0|7|7|7|7|7|7|7|7|7|
|8|0|8|8|8|8|8|8|8|8|8|
|9|0|9|9|9|9|9|9|9|9|9|
There is my code :
void displayBoard(Cell board[BOARD_HEIGHT][BOARD_WIDTH], Player * player)
{
int i, j;
printf("| ");
for (j = 0; j < BOARD_WIDTH; j++)
{
printf("|%d",j);
}
printf("|\n");
for (i = 0; i < BOARD_HEIGHT; i++)
{
for (j = 0; j < BOARD_WIDTH; j++)
{
printf("|%d",i);
if (j == 0)
{
printf("|%d",j);
}
}
printf("|\n");
}
printf("\n");
}
Have someone can help for this condition: only one row and one column, other is empty.

At no point in the body of the inner loop are you printing spaces. You're instead printing the value of i, which is the column number.
printf("|%d",i);
if (j == 0)
{
printf("|%d",j);
}
Instead, print i only on the first iteration and print the space each time:
if (j == 0) {
printf("|%d",i);
}
printf("| ");
Output:
| |0|1|2|3|4|5|6|7|8|
|0| | | | | | | | | |
|1| | | | | | | | | |
|2| | | | | | | | | |
|3| | | | | | | | | |
|4| | | | | | | | | |
|5| | | | | | | | | |
|6| | | | | | | | | |
|7| | | | | | | | | |
|8| | | | | | | | | |

The key to getting this done correct is enclosing the repeating logic (the blank cells) in the loop while confining the specialized logic to be outside the loop:
void displayBoard(int height, int width)
{
int i, j;
printf("| ");
for (j = 0; j < width; j++) {
printf("|%d", j);
}
printf("|\n");
for (i = 0; i < height; i++) {
printf("|%d", i);
for (j = 0; j < width; j++) {
printf("| ");
}
printf("|\n");
}
}
Look mom! no ifs

This is how you should code it:
void displayBoard(Cell board[BOARD_HEIGHT][BOARD_WIDTH], Player * player)
{
int i, j;
printf("| ");
for (j = 0; j < BOARD_WIDTH; j++)
{
printf("|%d",j);
}
printf("|\n");
for (i = 0; i < BOARD_HEIGHT; i++)
{
for (j = 0; j < BOARD_WIDTH; j++)
{
if (j == 0)
{
printf("|%d",i);
}
printf("| ");
}
printf("|\n");
}
printf("\n");
}
There are couple of issues with your current code:
You printf("|%d",i); in the inner loop for every j while what you really want is just to print it when j == 0 once. The rests, you want to printf("| "):
printf("| "); //you want to make this blank
if (j == 0)
{
printf("|%d",i); //you want to print i here, not j
}
between the print of number when j == 0 and the print of blank should be reversed:
if (j == 0)
{
printf("|%d",i); //you want to print i here, not j
}
printf("| "); //put the blank printing after the number

You are printing the number i in every line, when you want a blank or the array data. you also need to get rid of printing a zero every row, which is what you have coded in. Here is that part of the code corrected:
for (i = 0; i < BOARD_HEIGHT; i++)
{
for (j = 0; j < BOARD_WIDTH; j++)
{
if (j == 0)
{
printf("|%d",i);
}
printf("| "); ///or printf("|%d",board[i][j]) if you are after stored data
}
printf("|\n");
}
hope this helps.

Try this:
#define BOARD_HEIGHT 10
#define BOARD_WIDTH 10
void displayBoard()
{
int i, j;
printf("| ");
for (j = 0; j < BOARD_WIDTH; j++)
{
printf("|%d", j);
}
printf("|\n");
for (i = 0; i < BOARD_HEIGHT; i++)
{
printf("|%d", i);
for (j = 1; j < BOARD_WIDTH; j++)
{
printf("| ");
}
printf("| |\n");
}
}
BTW, there is no need to pass any arguments to this function.

Related

Initializing 2d array in C using memset

I am getting an exception when printing a two-dimensional array after initializing it using memset. If I initialize each element and then access it, then there is no error.
Please help to figure out the bug in the code.
#include "stdafx.h"
#include "stdlib.h"
int r = 0;
int c = 0;
int **twoDArray() {
int *arr[5];
for (r = 0; r < 5; r++) {
arr[r] = (int*)malloc(2 * sizeof(int));
}
//
for (r = 0; r < 5; r++) {
for (c = 0; c < 2; c++) {
arr[r][c] = 1;
printf("%d \n", arr[r][c]);
}
}
memset(arr, 0, 2 * 5 * sizeof(arr[0][0]));
for (r = 0; r < 5; r++) {
for (c = 0; c < 2; c++) {
printf("%d \n", arr[r][c]); //getting exception here.
}
}
return arr;
}
int main()
{
int **arr;
arr = twoDArray();
for (r = 0; r < 5; r++) {
for (c = 0; c < 2; c++) {
arr[r][c] = 0;
printf("%d \n", arr[r][c]);
}
}
return 0;
}
You don't have a 2D array. You have a 1D array of pointers to 1D arrays; each of these arrays can be (and 99.9% likely is) at a different address in memory. You therefore cannot treat them as one continuous block, as memset does.
The best (and most cache-friendly) option is to allocate the entire array dynamically:
int *arr = malloc(2 * 5 * sizeof(int));
This will require you to then do manual indexing:
for (r = 0; r < 5; r++) {
for (c = 0; c < 2; c++) {
arr[r * 2 + c] = 1;
printf("%d \n", arr[r * 2 + c]);
}
}
If you know the array size at compile time (if the 2 and 5 are actual constants), you can also make arr a pointer to an actual array, to allow syntactic 2D indexing:
typedef int Array[2];
Array *arr = malloc(5 * sizeof(Array));
for (r = 0; r < 5; r++) {
for (c = 0; c < 2; c++) {
arr[r][c] = 1;
printf("%d \n", arr[r][c]);
}
}
Note that in your original code, there was also the problem you were returning a pointer into arr, which is a local variable, making the pointer immediately dangling.
This is an array of pointers. You can be sure of two things
arr[0] to arr[4] is contiguous.
The chunk allocated is contiguous.
But who told you that the memory block allocated by each malloc which each of the pointer points to is contiguous also? Nobody did. You assumed it wrong.
In your case that's definitely not the case. That's why you invoked undefined behavior by accessing memory out of bound. (in memset).
Do this though - it would work
int (*arr)[2];
arr = malloc(sizeof *arr * 5);
// do memset - it's fine.
Don't cast the return value of malloc. It's redundant.
Something like this in earlier case:-
+-------------+
+-------+ +------>+ arr[0][0] |
arr[0] | | | | | arr[0][1]
| +-------------+ +------+------+
+-------+
| | +------+------+
arr[1] | +------->+ | |
+-------+ | | |
| | +-------------+ +------+------+
arr[2] | +-------------------------------------+ | |
+-------+ | | |
| | | +------+------+ +------+------+
arr[3] | +------------------>+ | |
+-------+ | | |
| | +------+------+
arr[4] | + |
+-------+
| +------+------+
+----------------------->+ | |
| | |
+------+------+

How can I print an array like a grid?

Hello I'm new at programming and I need to print an array (must be 1 dimensionnal) like a grid. I tried for hours now and still don't have the results I want.
The array has 16 values so the grid would be something like this :
___________
|0 |1 |2 |3 |
|4 |5 |6 |7 |
|8 |9 |10|11|
|12|13|14|15|
–––––––––––––
My code :
#include <stdio.h>
void display_grid(void)
{
int i;
int j;
int cell[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
for (i = 0; i < 4; i++)
{
printf("|");
for (j = 0; j < 16; j++)
{
printf("%d|",cell[j]);
}
printf("\n");
}
}
int main()
{
display_grid();
return 0;
}
Displays this :
|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|
|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|
|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|
|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|
I have a feeling that this would work: I changed cell[j] to cell[4 * i + j]
#include <stdio.h>
void display_grid(void)
{
int i;
int j;
int cell[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
for (i = 0; i < 4; i++)
{
printf("|");
for (j = 0; j < 4; j++)
{
printf("%d|",cell[4 * i + j]);
}
printf("\n");
}
}
int main()
{
display_grid();
return 0;
}
Does this help?
You can use the remainder operator % to determine when to print on a new line. Here is an example program with a display_grid() function that takes as arguments an array of int, the size of the array, and the desired size of each row. If the array can be evenly divided into rows of the desired number of columns, zero is returned. Otherwise a non-zero value is returned. This allows you to display a 1d array in various grid formats; nothing is printed if the array can't be evenly divided.
Currently this prints grids containing numbers with at most 2 digits (or 1 digit and a sign). It would be simple to modify it to print more digits, or a little more involved to modify so that the display width fits the maximum width needed for the input.
#include <stdio.h>
#define ARR_SZ 16
int display_grid(int *arr, size_t arr_sz, size_t row_sz);
int main(void)
{
int array[ARR_SZ];
for (size_t i = 0; i < ARR_SZ; i++) {
array[i] = i;
}
size_t row_sz = 4;
if (display_grid(array, ARR_SZ, row_sz) != 0) {
fprintf(stderr, "Array size not evenly divisible by %zu\n", row_sz);
}
row_sz = 8;
if (display_grid(array, ARR_SZ, row_sz) != 0) {
fprintf(stderr, "Array size not evenly divisible by %zu\n", row_sz);
}
row_sz = 2;
if (display_grid(array, ARR_SZ, row_sz) != 0) {
fprintf(stderr, "Array size not evenly divisible by %zu\n", row_sz);
}
row_sz = 1;
if (display_grid(array, ARR_SZ, row_sz) != 0) {
fprintf(stderr, "Array size not evenly divisible by %zu\n", row_sz);
}
row_sz = 16;
if (display_grid(array, ARR_SZ, row_sz) != 0) {
fprintf(stderr, "Array size not evenly divisible by %zu\n", row_sz);
}
row_sz = 6;
if (display_grid(array, ARR_SZ, row_sz) != 0) {
fprintf(stderr, "Array size not evenly divisible by %zu\n", row_sz);
}
row_sz = 32;
if (display_grid(array, ARR_SZ, row_sz) != 0) {
fprintf(stderr, "Array size not evenly divisible by %zu\n", row_sz);
}
return 0;
}
int display_grid(int *arr, size_t arr_sz, size_t row_sz)
{
int ret_val = arr_sz % row_sz;
if (ret_val == 0) {
/* Print top border */
putchar(' ');
for (size_t i = 1; i < 3 * row_sz; i++) {
putchar('_');
}
putchar('\n');
/* Print rows of grid */
for (size_t i = 0; i < arr_sz; i++) {
printf("|%-2d", arr[i]);
if ((i + 1) % row_sz == 0) {
printf("|\n");
}
}
/* Print bottom border */
for (size_t i = 0; i < 3 * row_sz + 1; i++) {
putchar('-');
}
putchar('\n');
}
return ret_val;
}
Program output:
___________
|0 |1 |2 |3 |
|4 |5 |6 |7 |
|8 |9 |10|11|
|12|13|14|15|
-------------
_______________________
|0 |1 |2 |3 |4 |5 |6 |7 |
|8 |9 |10|11|12|13|14|15|
-------------------------
_____
|0 |1 |
|2 |3 |
|4 |5 |
|6 |7 |
|8 |9 |
|10|11|
|12|13|
|14|15|
-------
__
|0 |
|1 |
|2 |
|3 |
|4 |
|5 |
|6 |
|7 |
|8 |
|9 |
|10|
|11|
|12|
|13|
|14|
|15|
----
_______________________________________________
|0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10|11|12|13|14|15|
-------------------------------------------------
Array size not evenly divisible by 6
Array size not evenly divisible by 32

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);
}

segmentation fault when creating connect 4 board c program

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?

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