update ascii grid printed to the screen without reprinting grid - c

int main() {
struct matrix m;
m.rows = 20;
m.columns = 20;
m.grid = create_grid(m.rows,m.columns,'&');
/* Example animation */
printf("\033[H\033[2J");
for (int i = 0; i < m.columns; i++) {
update_matrix(m.grid,10,i,'x');
if ( i > 0) {
update_matrix(m.grid,10,i-1,'&');
}
printf("\033[H\033[2J");
sleep(1);
printMatrix(m.grid,m.rows,m.columns);
}
for (int i = 0; i < m.rows; i++) {
free(m.grid[i]);
}
free(m.grid);
return 0;
}
void update_matrix(char** grid, int row,int column,char symbol) {
grid[row][column] = symbol;
}
char** create_grid(int rows, int columns, char symbol) {
int i,j;
char **grid = malloc(rows * sizeof(char *));
for (i = 0; i < rows; i++) {
grid[i] = malloc(columns * sizeof(char));
}
for (i = 0; i < rows; i++) {
for(j = 0; j < columns; j++) {
grid[i][j] = symbol;
}
}
return grid;
}
void printMatrix(char** array, int rows, int columns) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
printf("%c",array[i][j]);
}
printf("\n");
}
}
my method of animation is essentially to...
print the matrix
update the matrix
pause
clear the screen
reprint the matrix
The problem with this method of animation is that it creates a flickering effect and i'm sure is very inefficient. What can I do so that I do not have to clear the screen and reprint the entire matrix each time.
I run linux.

Apart from using ncurses, you could do
printf("\033%d;%df", row, column);
to set the cursor to the required row and column (note that in here, first row is 1 and not 0) instead of
printf("\033[H\033[2J");
Print the matrix once after setting it up and then change the displayed matrix when modifications are made.
You might want to position the cursor to the first row and column before printing the initial matrix like
printf("\033[%d;%df", 1, 1);
m.grid = create_grid(m.rows,m.columns,'&');
printMatrix(m.grid, m.rows, m.columns);
/* Example animation */
for (int i = 0; i < m.columns; i++) {
update_matrix(m.grid,10,i,'x');
printf("%c[%d;%df", 0x1B, 10+1, i+1);
printf("%c", 'x');
if ( i > 0) {
update_matrix(m.grid,10,i-1,'&');
printf("%c[%d;%df", 0x1B, 10+1, i-1+1);
printf("%c", '&');
}
sleep(1);
fflush(stdout);
}
fflush(stdout); may be needed to flush the output stream. Otherwise the changes written to stdout may not come on screen the moment they are changed.
But for such uses ncurses is better.
Have a look here and at this wikipedia page as well.

Related

How to undo a stack when the struct contains a char ** variable?

This code below is something like a candy crush game, where you pop similar letters in a cluster, then they'll disappear and you score. On main, I tried to play it one step ahead and then undo it, and it works since the score managed to undo (from 0 to some score then back to 0 again). However, I just can't figure out why the game board isn't updated?
typedef struct {
int rs;
int cs;
char **board;
int score;
} Instance;
with random letters (a, b ,c or d)
extern Game *create(int nrows, int ncols) {
if (nrows > MAX_ROWS || ncols > MAX_COLS) {
return NULL;
}
Game *b;
b->top = 0;
b->stack[b->top].rs = nrows;
b->stack[b->top].cs = ncols;
b->stack[b->top].board = malloc(sizeof(char *) * nrows);
for (int row = 0; row < nrows; row++) {
b->stack[b->top].board[row] = malloc(sizeof(char) * ncols);
}
srand(time(0));
for (int row = 0; row < nrows; row++) {
for (int column = 0; column < ncols; column++) {
int random = rand() % 4;
if (random == 0) {
b->stack[b->top].board[row][column] = A;
} else if (random == 1) {
b->stack[b->top].board[row][column] = B;
} else if (random == 2) {
b->stack[b->top].board[row][column] = C;
} else {
b->stack[b->top].board[row][column] = D;
}
}
}
return b;
}
// Display the current matrix
extern void display(Game *b) {
/** Prints top border **/
printf(" +-");
for (int top = 0; top < b->stack[b->top].cs; top++) {
printf("--");
}
printf("+\n");
/** Prints the board **/
for (int row = 0; row < b->stack[b->top].rs; row++) {
if (row < 10) {
printf("0%d | ", row);
} else {
printf("%d | ", row);
}
for (int column = 0; column < b->stack[b->top].cs; column++) {
printf("%c ", b->stack[b->top].board[row][column]);
}
printf("|\n");
}
/** Prints bottom border **/
printf(" +-");
for (int bot = 0; bot < b->stack[b->top].cs; bot++) {
printf("--");
}
printf("+\n");
/** Prints vertical column indices **/
printf(" ");
for (int tens = 0; tens < b->stack[b->top].cs; tens++) {
printf("%d ", tens/10);
}
printf("\n");
printf(" ");
int count = 0;
for (int ones = 0; ones < b->stack[b->top].cs; ones++) {
if (count > 9) {
count = 0;
}
printf("%d ", count);
count++;
}
}
extern int select(Game *b, int r, int c) {
char colour = b->stack[b->top].board[r][c];
int n = recursive_helper(b, r, c);
if (n == 1) {
b->stack[b->top].board[r][c] = colour;
return 0;
}
b->stack[b->top].score += n*(n-1);
return n;
}
int main() {
Game *b = create(5, 10);
display(b);
printf("\n");
printf("%d", bp_score(b));
printf("\n");
select(b, 2, 2);
display(b);
printf("\n");
printf("%d", bp_score(b));
printf("\n");
b->top--;
display(b);
printf("\n");
printf("%d", bp_score(b));
printf("\n");
}
As pointed in the comments, your create function doesn't instantiate a Game struct, you need b = malloc(sizeof(Game));
Another error is that your mallocs use sizeof(int*) and sizeof(int) instead of sizeof(char*) and sizeof(char).
Other than that, your problem comes from the fact that b->stack[b->top+1] = b->stack[b->top]; copies a structure, but the board is a pointer and points to the same object! You only have one char** pointer and a single board in memory.
Thus, when you do b->top-- while you do access another struct, it still points to the same fully updated board.
You need to create a function Instance CopyInstance(Instance src) that creates a new board in the new struct and then copies each cell from the source board in the new one. That way each Instance will point to a different board!

Building a function using Dynamic memory allocation

#include <stdio.h>
#include <stdlib.h>
void addition(int column, int row) {
int **array_a = (int **)malloc(sizeof(int*) * column);
int **array_b = (int **)malloc(sizeof(int*) * column);
int **array_c = (int **)malloc(sizeof(int*) * column);
for (int i = 0; i < column; i++) {
array_a[i] = (int *)malloc(sizeof(int) * row);
}
for (int i = 0; i < column; i++) {
for (int k = 0; k < row; k++) {
array_a[i][k] = rand();
}
for (int i = 0; i < column;) {
array_b[i] = (int *)malloc(sizeof(int) * row);
}
for (int i = 0; i < column; i++) {
for (int k = 0; k < row; k++) {
array_b[i][k] = rand();
}
}
for (int i = 0; i < column;) {
array_c[i] = (int *)malloc(sizeof(int) * row);
}
for (int i = 0; i < column; i++) {
for (int k = 0; k < row; k++) {
array_c[i][k] = array_a[i][k] + array_b[i][k];
}
}
for (int i = 0; i < column; i++) {
for (int k = 0; k < row; k++) {
printf("%d ", array_c[i][k]);
}
free(array_a);
free(array_b);
free(array_c);
}
}
}
int main(void) {
int column, row;
scanf("%d" "%d", &column, &row);
addition(column, row);
return 0;
}
I'm building a function that creates two 2D arrays and fills the values with random numbers and combines their values.
There is no error but the printf isn't working. Any way to make it work?
I don't know how to explain in more details but if you ask me I'll answer.
There are multiple problems in your code:
the loops are not properly nested: the body of the second for (int i = 0; i < column; i++) loop should stop right after the nested for for (int k = 0; k < row; k++) loop.
there are missing i++ increments in some of the loops: for (int i = 0; i < column;) should be
for (int i = 0; i < column; i++)
This is the main issue as it causes an infinite loop, repeatedly initializing array_b[0] with a newly allocated block, until memory is exhausted and beyond.
you do not check for memory allocation failure.
your use or columns and rows is odd: the first index in a 2D usually refers to rows and the second to columns, but since your usage is consistent, it is probably not a problem.
you do not output a newline after each row or column: all output is produced on a single line without a trailing newline. This may cause your output to not appear on some systems. You might want to pause the program after the output to let the user see the output.
casting the return value of malloc() is not necessary in C.
you do not free the subarrays.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int **allocate_array(int column, int row) {
int **array = malloc(sizeof(array[0]) * column);
if (array == NULL)
return NULL;
for (int i = 0; i < column; i++) {
array_a[i] = malloc(sizeof(array[i][0]) * row);
if (array_a[i] == NULL) {
while (i-- > 0) {
free(array[i]);
}
free(array);
return NULL;
}
}
return array;
}
void free_array(int **array, int column, int row) {
if (array) {
for (int i = 0; i < column; i++) {
free(array[i]);
}
free(array);
}
}
void addition(int column, int row) {
int **array_a = allocate_array(column, row);
int **array_b = allocate_array(column, row);
int **array_c = allocate_array(column, row);
if (array_a && array_b && array_c) {
for (int i = 0; i < column; i++) {
for (int k = 0; k < row; k++) {
array_a[i][k] = rand();
}
}
for (int i = 0; i < column; i++) {
for (int k = 0; k < row; k++) {
array_b[i][k] = rand();
}
}
for (int i = 0; i < column; i++) {
for (int k = 0; k < row; k++) {
array_c[i][k] = array_a[i][k] + array_b[i][k];
}
}
for (int i = 0; i < column; i++) {
for (int k = 0; k < row; k++) {
printf("%d ", array_c[i][k]);
}
printf("\n");
}
}
free_array(array_a, column, row);
free_array(array_b, column, row);
free_array(array_c, column, row);
}
int main(void) {
int column, row;
if (scanf("%d%d", &column, &row) == 2 && column > 0 && row > 0)
addition(column, row);
return 0;
}

Check diagonally winner in Connect N using C

I'm doing the game Connect N using C and I'm having a hard time trying to code an algorithm to check if there is a winner diagonally.
char **BASE;
int piecesToWin, ROWS, COLS;
printf("Enter how many connected pieces to win?: ");
scanf("%d", &piecesToWin);
ROWS = 2 + piecesToWin;
COLS = 3 + piecesToWin;
BASE = (char **) malloc(ROWS * sizeof(char *)); // Allocate the row pointers
for (int i = 0; i < ROWS; i++) // Allocate each row separately
BASE[i] = (char *) malloc(COLS * sizeof(char));
// Fill all with space to start
for (int i = 0; i < ROWS; i++)
for (int j = 0; j < COLS; j++)
BASE[i][j] = ' ';
After this, I insert a piece to the board and then, I check if there is a winner diagonally.
if (diagAscWin(ROWS, COLS, BASE, piecesToWin, 'X')) {
printf("X has won!.");
}
if (diagDescWin(ROWS, COLS, BASE, piecesToWin, 'X')) {
printf("X has won!.");
}
What I have tried to check diagonally:
bool diagAscWin(int ROWS, int COLS, char **BASE, int numToWin, char letter) {
bool isWinner = false;
for (int i=3; i<ROWS; i++){
for (int j=0; j<COLS-3; j++){
if (BASE[i][j] == letter && BASE[i-1][j+1] == letter && BASE[i-2][j+2] == letter && BASE[i-3][j+3] == letter)
isWinner = true;
}
}
return isWinner;
}
bool diagDescWin(int ROWS, int COLS, char **BASE, int numToWin, char letter) {
bool isWinner = false;
for (int i=3; i<ROWS; i++){
for (int j=3; j<COLS; j++){
if (BASE[i][j] == letter && BASE[i-1][j-1] == letter && BASE[i-2][j-2] == letter && BASE[i-3][j-3] == letter)
isWinner = true;
}
}
return isWinner;
}
These functions are not working. When I have N pieces diagonally, diagAscWin and diagDescWin don't see them and always return false. Also, I'm not sure if I need to initialize i or j with 3 or j<COLS-3. I was trying to replicate a solution from another thread.
Also, I have tried this:
bool diagRightWin(int ROWS, int COLS, char **BASE, int numToWin, char letter) {
bool isWinner = false;
int count;
for (int rowStart = 0; rowStart < ROWS - 4; rowStart++) {
count = 0;
int row, col;
for (row = rowStart, col = 0; row < ROWS && col < COLS; row++, col++) {
if (BASE[row][col] == letter) {
count++;
if (count >= numToWin) isWinner = true;
} else {
count = 0;
}
}
}
return isWinner;
}
bool diagLeftWin(int ROWS, int COLS, char **BASE, int numToWin, char letter) {
bool isWinner = false;
int count;
for (int rowStart = 0; rowStart < ROWS - 4; rowStart++) {
count = 0;
int row, col;
for (row = rowStart, col = 0; row < ROWS && col < COLS; row++, col++) {
if (BASE[row][col] == letter) {
count++;
if (count >= numToWin) isWinner = true;
} else {
count = 0;
}
}
}
return isWinner;
}
These two functions also always return false.
I have tried different logics with no luck. The correct thing is to check how many numToWin pieces are diagonally to say if there is a winner.
I have tried to replicate:
Connect 4 check for a win algorithm
Java: How to check diagonal Connect Four win in 2D array
Javascript - Connect Four game validation
Checking for a line of four (Connect Four in Java)
My goal is to check if there is a winner diagonally (on any direction), having in mind that the board can be big or small, we don't know the size. What we know for sure is the piecesToWin which is the number of pieces that needs to be together to say there is a winner.
The main problem is that you are not exiting the function when you find a match of 4 elements. Also the function looping needs to be modified as shown.
You need two functions to check left diagonal and right diagonal
/ <-- left diagonal right diagonal --> \
/ \
/ \
/ \
I have modified the check functions and also added the functionality to check for variable number of elements in a diagonal.
// this function checks diagnonal sloping left "/"
//
bool diagLeftWin(int ROWS, int COLS, char **BASE, int numToWin, char letter) {
for (int i=0; i<ROWS-numToWin; i++){
for (int j=0; j<COLS-numToWin; j++){
char curr = BASE[i][j];
if (curr == letter) {
int k;
for (k=1; k<numToWin; k++) {
if (curr != BASE[i+k][j+k]) {
break;
}
}
if (k == numToWin) {
// match found
return true;
}
}
}
}
return false;
}
// this function checks diagnonal sloping right "\"
//
bool diagLeftWin(int ROWS, int COLS, char **BASE, int numToWin, char letter) {
for (int i=ROWS-numToWin; i>=0; i--){
for (int j=0; j<COLS-numToWin; j++){
char curr = BASE[i][j];
if (curr == letter) {
int k;
for (k=1; k<numToWin; k++) {
if (curr != BASE[i-k][j+k]) {
break;
}
}
if (k == numToWin) {
// match found
return true;
}
}
}
}
return false;
}
These functions check the entire board every time. You can optimise it to only check around newly added pieces to the board.

Simple I/O Function w/ C

I've just recently started trying to learn C through the tutorials on Wikibooks. I've read the beginning C pages listed here and am attempting to do the exercises. I'm having a problem with the second question on loops: wherein I'm trying to make a function to output a triangle made up of lines of * characters, where the height is 2n-1 if the width is n. My first thought was to make a nested loop, the outer of which would create a variable for the line number, and compare it to the max height. The inner loop would create a variable that would essentially serve as the index of the * character within that particular line. My problem is I don't know how to deal with making the lines after the max width decrease in size. Can anyone point me in the right direction? Here is my code:
#include <stdio.h>
void triangle(int);
int main() {
int width;
printf("%s", "Please enter a width for your triangle: ");
scanf("%d", & width);
triangle(width);
return 0;
}
void triangle(int width) {
for (int line = 1; line <= (2 * width) - 1; line++) {
for (int i = 0; i < line && i < width; i++) {
printf("%s", "*");
}
printf("%s", "\n");
}
}
Try this:
void triangle(int width) {
int line, i, rev = 0;
for (line = 1; line < width; ++line) {
for (i = 0; i < line && i < width; i++) {
printf("*");
}
printf("\n");
}
for (; line; --line) {
for (i = 0; i < line && i < width; i++) {
printf("*");
}
printf("\n");
}
}
if you want to do it in one pair of nested for loops try this:
void triangle(int width) {
int i, j, height, tmp;
height = 2 * width - 1;
tmp = 1;
for (i = 0; i < height; i++) {
for (j = 0; j < tmp; j++) {
putchar('*');
}
putchar('\n');
if (i < height / 2) {
tmp++;
} else {
tmp--;
}
}
}

Writing values in a 2 dimensional array in c

Being new to C, and this website, I'm unfamiliar with this problem I'm having. I have a 2 dimensional array with [8][8] elements. I'm trying to get the user to enter numbers into the array until finished. The program is far from finished, but I'm stuck on this problem before I can move on. Basically I use a for loop to let the user enter into each element. However, when the first row is complete, it overwrites it's last value onto the first column second row element spot. How can I prevent this from happening: Here's my code:
#include <stdio.h>
#include <string.h>
int Check_rules();
void Print_Array(int array[][8], int size)
{
int i, j;
for (i = 0; i <= size; i++)
{
printf("\n");
for (j = 0; j <= size; j++)
{
printf("%d ",array[i][j]);
}
}
printf("\n\n");
}
int main()
{
int size = 8;
int i, j;
int fullArray[size][size];
int grid1[3][3];
int grid2[3][3];
int grid3[3][3];
int grid4[3][3];
int grid5[3][3];
int grid6[3][3];
int grid7[3][3];
int grid8[3][3];
int grid9[3][3];
for (i = 0; i <= size; i++)
{
for (j = 0; j <= size; j++)
fullArray[i][j] = 0;
}
printf("Want to play a game? Enter values 1-9 starting in row 1 column 1, \nand we will work our way from there. Here's the playing board.\nIt's Sudoku, so follow the rules of the game.\n\n");
for (i = 0; i <= size; i++)
{
printf("\n");
for (j = 0; j <= size; j++)
printf("%d ",fullArray[i][j]);
}
printf("\n\n");
int tmp;
char *keeper = (" ");//space for marker
for (i = 0; i <= size; i++)
{
for (j = 0; j <= size; j++)
{
printf("Enter first value(press 0 and ENTER to skip a box, \nand -1 to cancel game): ");
scanf("%d", &tmp);
if(tmp == -1)
return 0;
fullArray[i][j] = tmp;
Print_Array(fullArray,size);
}
}
return 0;
}
If you run this you'll see my problem when you enter the last value in row 1. It overwrites the second row first column element spot?
Everywhere you have <= size, you actually want < size. This is because C uses 0-based indexes. That means if you have an array with 5 elements, the indexes are 0, 1, 2, 3, 4. In a loop like for (int i = 0; i <= 5; i++), i would get the values 0, 1, 2, 3, 4, 5. That last one is an invalid index into the array. Using i < 5 fixes the problem (ensures i stops before it reaches 5).
Fixed and cleaned up version of your code:
#include <stdio.h>
#include <string.h>
void printArray(int size, int array[][size]) {
for (int i = 0; i < size; i++) {
printf("\n");
for (int j = 0; j < size; j++) {
printf("%d ", array[i][j]);
}
}
printf("\n\n");
}
int main() {
int size = 8;
int fullArray[size][size];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
fullArray[i][j] = 0;
}
}
printf("Enter values in row 1 column 1, and we will work our way from there. Here's the playing board. \n\n");
printArray(size, fullArray);
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
printf("Enter first value (press 0 and ENTER to skip a box, or -1 to cancel game): ");
int number;
scanf("%d", &number);
if(number == -1) {
return 0;
}
fullArray[i][j] = number;
printArray(size, fullArray);
}
}
return 0;
}
EDIT
To clarify, this is fixed version of the original code in the question. The new code is a bit different, but I think the issue is the same.

Resources