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.
Related
I need to input a matrix, where the first element of a row is the student ID number, and the other 12 elements are student points and GPA. Each row represents one student. What the program needs to do is calculate the total point amount, and then sort the matrix so it goes in descending order by the amount of points.
This is my code:
#include <stdio.h>
int main() {
int number_of_students,i,j;
double matrix[50][50],GPA,grades,total,GPA_before;
printf("Number of students: ");
scanf("%d", &number_of_students);
printf("Input students: ");
for(i=0; i<number_of_students; i++){
for(j=0; j<12; j++){
scanf("%lf", &matrix[i][j]);
}
}
printf("Final list: \n");
for(i=0; i<number_of_students; i++){
GPA_before=(matrix[i][2]+matrix[i][3]+matrix[i][4]+matrix[i][5])*2.5;
if(GPA_before==50){
GPA=GPA_before+3;
}
else{
GPA=GPA_before;
}
grades=(matrix[i][6]+matrix[i][7]+matrix[i][8]+matrix[i][9]+matrix[i][10]+matrix[i][11])*0.67;
total=GPA+grades+matrix[i][12];
printf("%d. %g | %g\n",i,matrix[i][1],total);
}
return 0;
}
And this is what I get:
Number of students: 4
Input students: 123456 4.00 4.50 5.00 5.00 5 5 5 4 4 5 15
456789 4.50 5.00 4.00 3.50 3 5 4 5 5 2 10
789321 5.00 5.00 4.50 3.00 5 4 5 3 5 3 15
456987 4.50 4.50 4.50 5.00 4 4 4 5 5 5 25
Final list:
1. 123456 | 80.01
2. 456789 | 68.58
3. 789321 | 75.5
4. 456987 | 89.34
The matrix should be sorted from highest number of points to the lowest, not by ID. It is specified not to sort the list while printing it out, the matrix itself must be sorted.
I would really appreciate the help.
Firstly, I saw a few things in your code that I would like to point out and change, if possible.
You are allocating an 2-D Array of 50 rows and 50 columns. However, you're only utilizing 12 of those columns. So, first thing that I would like you to fix is the use of those extra unnecessary array indexes. So, I wrote the following code:
const int MAX = 50;
const int NUM_INPUTS = 12;
int number_of_students, i, j;
double matrix[MAX][NUM_INPUTS + 1], GPA, grades, total;
Note: I added NUM_INPUTS + 1, that we will use to store the total of that you were calculating in the loop and also printing it too.
Now, another thing I would like to point out, is your use of loops. You're iteration is beginning from the index 1. You're not using the 0th index. So, you'll have to fix each loop from this:
for(i=1; i<=number_of_students; i++){
for(j=1; j<=12; j++){
scanf("%lf", &matrix[i][j]);
}
}
to this:
for (i = 0; i < number_of_students; i++) {
for (j = 0; j < NUM_INPUTS; j++) {
scanf("%lf", &matrix[i][j]);
}
}
Now, this indexing from 0 will cause the code that you wrote for the calculations, to not work properly, so, you will have to fix that too:
for(i=1; i<=number_of_students; i++){
GPA_before=(matrix[i][2]+matrix[i][3]+matrix[i][4]+matrix[i][5])*2.5;
if(GPA_before==50){
GPA=GPA_before+3;
}
else{
GPA=GPA_before;
}
grades=(matrix[i][6]+matrix[i][7]+matrix[i][8]+matrix[i][9]+matrix[i][10]+matrix[i][11])*0.67;
total=GPA+grades+matrix[i][12];
You were using this code in-junction with printf. I used this code to calculate the total and then store it in the index matrix[i][NUM_INPUTS].
Now, I slightly changed your code and loop for storing the total in the matrix itself becomes:
for (i = 0; i < number_of_students; i++) {
GPA = (matrix[i][1] + matrix[i][2] + matrix[i][3] + matrix[i][4]) * 2.5;
if (GPA == 50) {
GPA += 3;
}
grades = (matrix[i][5] + matrix[i][6] + matrix[i][7] + matrix[i][8] + matrix[i][9] + matrix[i][10]) * 0.67;
total = GPA + grades + matrix[i][11];
matrix[i][NUM_INPUTS] = total;
}
Now, this made it easy for me to implement a basic Bubble Sort algorithm to sort your matrix:
int k;
for (i = 0; i < number_of_students; i++) {
for (j = 0; j < number_of_students - 1; j++) {
if (matrix[j][NUM_INPUTS] > matrix[j + 1][NUM_INPUTS]) {
double temp;
for (k = 0; k < NUM_INPUTS + 1; k++) {
temp = matrix[j][k];
matrix[j][k] = matrix[j + 1][k];
matrix[j + 1][k] = temp;
}
}
}
}
Now, since the matrix itself has been sorted, we will simply print the final matrix:
for (i = 0; i < number_of_students; i++) {
printf("%d. %g | %g\n", i + 1, matrix[i][0], matrix[i][NUM_INPUTS]);
}
Note: One more thing you can do (totally for input validation) is write an if statement, that would check if the user input for number of students is in the range of 1 <= number_of_students <= MAX (50), if it is greater than that, it would cause an out-of-bounds exception or a Buffer Overflow.
if(number_of_students > MAX || number_of_students <= 0) {
printf("Invalid number of students");
return 1;
}
I hope you understood what I wrote and would love if you'd upvote as this is my first answer here.
Here's the full source code:
#include <stdio.h>
int main() {
const int MAX = 50;
const int NUM_INPUTS = 12;
int number_of_students, i, j;
double matrix[MAX][NUM_INPUTS + 1], GPA, grades, total;
printf("Number of students: ");
scanf("%d", &number_of_students);
if(number_of_students > MAX || number_of_students <= 0) {
printf("Invalid number of students");
return 1;
}
printf("Input students: ");
for (i = 0; i < number_of_students; i++) {
for (j = 0; j < NUM_INPUTS; j++) {
scanf("%lf", &matrix[i][j]);
}
}
// Firstly calculating the total and storing it in the final index of the matrix:
for (i = 0; i < number_of_students; i++) {
GPA = (matrix[i][1] + matrix[i][2] + matrix[i][3] + matrix[i][4]) * 2.5;
if (GPA == 50) {
GPA += 3;
}
grades = (matrix[i][5] + matrix[i][6] + matrix[i][7] + matrix[i][8] + matrix[i][9] + matrix[i][10]) * 0.67;
total = GPA + grades + matrix[i][11];
matrix[i][NUM_INPUTS] = total;
}
// Sorting this based on total:
for (i = 0; i < number_of_students; i++) {
for (j = 0; j < number_of_students - 1; j++) {
if (matrix[j][NUM_INPUTS] > matrix[j + 1][NUM_INPUTS]) {
double temp;
for (int k = 0; k < NUM_INPUTS + 1; k++) {
temp = matrix[j][k];
matrix[j][k] = matrix[j + 1][k];
matrix[j + 1][k] = temp;
}
}
}
}
printf("Final list:\n");
for (i = 0; i < number_of_students; i++) {
printf("%d. %g | %g\n", i + 1, matrix[i][0], matrix[i][NUM_INPUTS]);
}
return 0;
}
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);
}
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?
I have a task to get a positive integer from the user, and then print a triangle that will look like this (for the integer 5 for example):
1
1 2
1 3 5
1 4 7 10
1 5 9 13 17
this is the code that I managed to make:
int num, line,addition,sum,termNum;
printf("Enter a positive integer: ");
scanf("%d",&num);
printf("%d\n",1);
for (line=2;line<=num;line++)
{
addition = line-1;
termNum=1;
printf("%d ",termNum);
for (sum=2;sum<=line;sum++)
{
termNum+=addition;
printf("%d ",termNum);
}
printf("\n");
}
But the output is not aligned to the right, it looks like this:
1
1 2
1 3 5
1 4 7 10
1 5 9 13 17
I cant create functions or use arrays, only loops and ifs, and the various control characters such as %c %s %d %-12c etc...
Variable types must be int,double,char. (not strings or char* etc)
Any ideas?
Thanks.
OP a needs nudge to pre-calculate maximum line width.
Below fill-in-the-blank code calculates the max line width, which seem to be OP's stumbling block.
int main(void) {
int x = 5;
int width = 0;
for (int col = 0; col < ___ ; col++) { // How many iterations?
int value = col* ___ + ___; // Determine each value: 1 5 9 13 17
// find print width
do {
width++; // add 1 per digit
value /= ___; // What base is the number displayed?
} while (value > ___); // When to quit (hint: not much)
width++; // add 1 for ' ' separator
}
printf("%d\n", width); // Should be a dozen
}
Alternative
for (int col = 0; col < ___ ; col++) {
int value = col* ___ + ___;
width += snprintf(NULL, 0, "%d ", value);
}
Maximum printed number will be the very last number. That is line
num and column num. It will thus be 1 + (num - 1) ^ 2.
The printed width of a decimal number N is ceil(log(N+1) / log(10)).
The easiest way to align your numbers is to print them all the same
width, that is the width of the maximum number:
ceil(log(1 + (num - 1) ^ 2) / log(10)).
int num, line, addition, sum, termNum;
printf("Enter a positive integer: ");
scanf("%d", &num);
int width = ceil(log10(1 + 1 + (num - 1) * (num - 1)));
char format[] = "%0000000000d%c";
sprintf(format, "%%%dd%%c", width);
for (sum = 1 + 1; sum <= num; sum++) {
int i;
for (i = 0; i <= width; i++)
putchar(' ');
}
printf(format, 1, '\n');
for (line = 2; line <= num; line++) {
for (sum = line + 1; sum <= num; sum++) {
int i;
for (i = 0; i <= width; i++)
putchar(' ');
}
addition = line - 1;
termNum = 1;
printf(format, termNum, ' ');
for (sum = 2;sum <= line; sum++) {
termNum += addition;
printf(format, termNum, ' ');
}
printf("\n");
}
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