C Chomp questions? - c

I'm trying to create the game Chomp. I am halfway through but pretty stuck.
The game will have 5 different functions. Pointers and structs are not allowed.
This is how far I have come and I have been struggeling with a few problems for a while, but I can't figure out how to solve them by myself so I thought I could get some help here.
BUGS
a) If you first input 2 2 and then input 2 1 it will say that the position already has been eaten, even though it's a perfectly valid position to eat. Instead of checking if the position is != 'O' I should check if it is == 'O', but that won't work either because in the check_move() loop the row and col will not always be an O...
b) If you input a position that is not inside the matrix (i.e. 20 20) you will get two lines of errors. I don't understand why. Of course I only want to display one error, not two.
c) If you input a position that has already been eaten you will get the error "Already been eaten!" several times due to the loop that is looping through the print several times.
QUESTION
a) What is the best way to alternate between Player 1 and Player 2? I thought about an int that will increase by +1 every time a player makes a valid move. Then I will check if the value of the int is odd or even. Odd = Player 1 and even = Player 2 or vice verca. But that won't work because I'm not allowed to have any more global variables than I currently has. And I'm only allowed to return one value from one function (check_move()).
#include <stdio.h>
int height = 4;
int width = 10;
char matrix[4][10];
void initialize()
{
for(int row = 0; row < height; row++)
for(int col = 0; col < width; col++)
matrix[row][col] = 'O';
}
void print_board()
{
printf("\n\n");
for(int row = 0; row < height; row++)
{
for(int col = 0; col < width; col++)
{
printf("%c", matrix[row][col]);
}
printf("\n");
}
printf("\n\n");
}
void get_move(int player, int input[])
{
printf("Player %d, make your move: ", player);
scanf("%d %d", &input[0], &input[1]);
}
int check_move(int position[])
{
int row = position[0];
int col = position[1];
int status = 1;
if(row <= height && col <= width)
{
for(row; row <= height; row++)
{
for(col; col <= width; col++)
{
// Checks if position already has been eaten
if(matrix[row-1][col-1] != 'O')
{
printf("Already eaten!\n");
status = 0;
}
}
}
}
else if(row >= height || col >= width)
{
printf("Your move must be inside the matrix!\n");
status = 0;
}
return status;
}
void update_board(int x, int y)
{
for(int xi = x; xi <= 10; ++xi)
{
for(int yi = y; yi <= 10; ++yi)
matrix[xi-1][yi-1] = ' ';
}
}
int main(void)
{
int player = 1;
int position[2];
initialize();
print_board();
while(1){
get_move(player, position);
check_move(position);
while(check_move(position) != 1)
{
printf("Try again!\n\n");
get_move(player, position);
}
update_board(position[0], position[1]);
print_board();
}
getchar();
getchar();
getchar();
return 0;
}

Bug a and c:
Your check_move function is wrong, you should only test if the position played is eaten or not, the status of the other positions are not relevant:
int check_move(int pos[])
{
if(pos[0] < 1 || pos[0] > height || pos[1] < 1 || pos[1] > width)
{
printf("Your move must be inside the matrix!\n");
return 0;
}
if(matrix[ pos[0] - 1 ][ pos[1] - 1 ] != 'O' ) {
printf("Already eaten!\n");
return 0;
}
return 1;
}
Bug b:
You get the error message twice because you're calling check_move twice in your main:
check_move(position);
while(check_move(position) != 1)
Just remove the useless first call to check_move().
Question a:
You can switch between players by updating the variable player inside your main :
player = (player + 1) % maxNumberOfPlayer;
This will go from 0 to maxNumberOfPlayer - 1, so you may use printf("Player %d, make your move: ", player + 1); for a more user-friendly output. Also, if maxNumberOfPlayer = 2, player = (player + 1) % 2; is equivalent to player = !player.

In main, inside your while loop just add:
player = !player;
Which will toggle player between 0 and 1.

Related

Having issues finding the bug with implementing Conway's Game of Life. Below is the source code

The rules of Conway's Game of life is each cell on a grid has two states: living or dead. 1. If a living cell has fewer than 2 or more than 3 neighbors, the cell dies. 2.If a living cell has 2 or 3 neighbors, it lives on. 3.If a dead cell has exactly 3 neighbors, it is born in the next generation.
I first created two small 5 by 5 grid with arrays to contain the cells. One array is for the previous configuration and another array is for the updated new array. "-" symbolizes a dead cell and "O" symbolizes an alive cell. I set up a loop that prints out the initial/old configuration, update the configuration and store it in the new array, and rewrote the old array with the updated array. Then the terminal would be emptied out. The next iteration would then print the updated world. However, the second generation is incorrect. I'm not sure where the problem lies.
#include <stdio.h>
#include <unistd.h>
void update_world(void);
void print_world(void);
int check(int width, int height);
//create a 5 by 5 array which would be the "world"
char cell[5][5];
char new_cell[5][5];
int main(void) {
//initialize array to "-"s (dead)
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
cell[i][j] = '-';
}
}
//initialize configuration ie. put some life into the world
cell[0][1] = 'O';
cell[4][0] = 'O';
cell[1][2] = 'O';
cell[1][4] = 'O';
cell[4][4] = 'O';
cell[0][2] = 'O';
//outer loop for iteration of each cycle
for (int i = 0; i < 10; i++) //goes for 10 generations
{
print_world();
update_world();
//write new cell into old cell before the new cell updates
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
cell[i][j] = new_cell[i][j];
}
}
sleep(1);
printf("\033[2J\033[H"); //clear terminal
}
}
//print out the world onto terminal
void print_world(void)
{
for (int column = 0; column < 5; column++)
{
for (int row = 0; row < 5; row++)
{
if (row % 5 == 0)
printf("\n");
printf("%c", cell[row][column]);
}
}
printf("\n");
}
//update world
void update_world(void)
{
//traverse world
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
//checks the conditions to decide whether the cell is alive or dead in the next generation
if (check(i, j) == 1)
new_cell[i][j] = '-'; //cell dies
else if (check(i,j) == 0){
new_cell[i][j] = 'O'; //cell is born
}
else
new_cell[i][j] = cell[i][j]; //cell stays the same
}
}
}
//check if cell should die, be born, or stay as is
int check(int width, int height)
{
int alive = 0;
//traverse cell's neightboring cells (including itself)
for (int h = height - 1; h <= height + 1; h++)
{
for (int w = width - 1; w <= width + 1; w++)
{
//if cell (h,w) is a surrounding cell, within bounds of the grid, and is alive
if (!(h == height && w == width) && h >= 0 && h < 5
&& w >= 0 && w < 5 && cell[h][w] == 79)
alive++;//increment alive count
}
}
//check conditions
if (alive > 3 || alive < 2)
return 1; //cell dies
else if (alive == 3)
return 0; //cell is born or lives on to next generation
return 2; //alive count = 2, nothing changes
}
You switch coordinates in check().
In update_world() you call it with i and j for cell[i][j], and these parameters are named width (for i) and height (for j) inside check().
But then you test cell[h][w], with h running from height - 1 to height + 1 and w running from width - 1 to width + 1. It should be cell[w][h] instead.
Other note:
Since the return value of check() will not change between calls, you can simplify the body of the loops in update_world() by caching the value. Anyway, it can be simpler with a switch:
//checks the conditions to decide whether the cell is alive or dead in the next generation
switch (check(i, j))
{
case 1:
new_cell[i][j] = '-'; //cell dies
break;
case 0:
new_cell[i][j] = 'O'; //cell is born
break;
default:
new_cell[i][j] = cell[i][j]; //cell stays the same
break;
}

problem about using a dynamically allocated 2d array in a c program

I'm having a problem on making a move on my 9 x 9 tic tac toe program.
When I enter a coordinate such as (5,5), The x is displayed correctly on the grid.
MY PROBLEM IS THAT when I enter a coordinate which has the number 7 in it such as (4,7), TWO X's ARE DISPLAYED ON THE GRID.
I previously did the program declaring my array as a global variable. All was working fine. The issue started when I switched to a dynamically allocated array and passed the array using a double-pointer.
So I'm guessing that my problem is because of my array.
Can someone tell me where does this issue occur and how to fix it please.
I have declared the array in my main
//previously the array was declared here
//char grid[ROW][COLUMN];
int main()
{
//dynamically create an array of pointers os size ROW
char **grid = (char **)malloc(ROW * sizeof(char *));
// dynamically allocate memory of size ROW*COLUMN and let *grid point to it
*grid = (char *)malloc(sizeof(char) * ROW * COLUMN);
make move method
int make_move(char **grid, int x, int y,int row, int col, char letter)
{
if (x < 0 || x >= row || y < 0 || y >= col || grid[x][y] != ' ' )
{
// checks to see if the input is valid
return 1;
}
if( grid[x][y] == ' ')
grid[x][y] = letter;
// sets the coordinates in the grid to the letter
return 0;
}
update grid method
// Updates the grid accordingly every time a move is made
void update_grid(char **grid,int x, int y, int row, int col)
{
// int counter = 1;
//checks the input
while (x < 0 || x >= row || y < 0 || y >= col || grid[x][y] != ' ')
{
fputs("Error, Move not valid! Please reenter: ", stderr);
scanf("%d,%d", &x, &y);
}
++counter;
{
//Acts as an increment for the turns of the players
if(counter % 2 == 0)
{
//checks to see if it is player X's turn
grid[x][y] = 'X';
}
if(counter % 2 != 0)
{
//checks to see if it is player O's turn
grid[x][y] = 'O';
}
//prints grid
printf(" ");
for (int c = 0; c < col; c++)
{
printf(" ");
printf(" %d", c);
}
printf("\n");
for (int r = 0; r < row; ++r)
{
printf("%d", r);
printf("|");
for (int dot = 0; dot < (col*row); ++dot)
{
printf("|");
printf("%c", grid[r][dot]);
printf(" ");
if (dot == col - 1)
{
// stops j from over printing
printf("|| \n");
break;
}
}
}
}
}
As B. Go said your malloc is wrong, here's how it should look.
//dynamically create an array of pointers os size ROW
char **grid = malloc(ROW * sizeof(char *));
for(size_t i = 0; i < ROW; i++){
grid[i] = malloc(COLUMN);
}
you allocated ROW pointers but you only filled the first one, you need to give them each COLUMN bytes of data.

Program suddenly has a spike in cpu usage and looks like it is paused

I have added 2 functions:
int aiCheckScore(char arr[7][7], int inp, int height, Player player)
int aiFindMostRelevant(char arr[7][7], Player player)
The first makes a score for a given position in a 2D array. The score is equal to how many of the same kind elements we would have in a row (vertically, horizontally or diagonally and it keeps the best one of those 3) if we added one in this position (excluding the one we add just now)
The second function checks 7 positions at a time and finds the one with the best score and returns that. I tried to add a little randomness and make it so that if 2 positions have the same score the program would choose the last one 30% of the time (so that it wouldn't always take the first one).
Without the bit where I add the randomness the code runs just fine. As soon as I add it the program halts right after it calls for the 12th time the first function. Furthermore, the CPU usage from the program suddenly spikes and remains at 50% from below 5% it was before.
I have modified the code which creates the randomness a couple of times but nothing seems to change. I can't even comprehend why it would cause such an issue.
My 2 functions are:
int aiCheckScore(char arr[7][7], int inp, int height, Player player) {
int i, j;
int score[4] = { 0 };
//check horizontal score
for (i = inp - 1; i >= 0; i--) { //everything left
if (arr[height][i] != player.symb)
break;
++score[0];
}
for (i = inp + 1; i <= 6; i) { //everything right
if (arr[height][i] != player.symb)
break;
++score[0];
}
//check vertical score (we only have to check down)
for (i = height + 1; i <= 6; i++) {
if (arr[i][inp] != player.symb)
break;
++score[1];
}
//check diagonal (which starts left and above and goes down and right)
j = height - 1;
for (i = inp - 1; i >= 0 && j >= 0; i--) { //above and left
if (arr[j][i] != player.symb)
break;
++score[2];
--j;
}
j = height + 1;
for (i = inp + 1; i <= 6 && j <= 6; i++) { //down and right
if (arr[j][i] != player.symb)
break;
++score[2];
++j;
}
//check diagonal (which starts left and down and goes up and right)
j = height + 1;
for (i = inp - 1; i >= 0 && j <= 6; i--) { //down and left
if (arr[j][i] != player.symb)
break;
++score[3];
++j;
}
j = height - 1;
for (i = inp + 1; i <= 6 && j >= 0; i++) { //up and right
if (arr[j][i] != player.symb)
break;
++score[3];
--j;
}
int bestscore = score[0];
for (i = 0; i <= 3; i++) {
if (score[i] > bestscore)
bestscore = score[i];
}
printf("%d", bestscore);
return bestscore;
}
int aiFindMostRelevant(char arr[7][7], Player player) {
int i, height;
int score[7] = { 0 };
for (i = 0; i <= 6; i++) {
height = findHeight(arr, i);
if (height == -1) {//skip the columns that are full
score[i] = -100; //and give them a very bad score
}
else {
score[i] = aiCheckScore(arr, i, height, player);
}
}
int bestscore = score[0];
int bestposition = 0;
int num;
for (i = 0; i <= 6; i++) {
num = (int)rand() % 10;
if (score[i] == bestscore) { //if 2 positions have the same score
if (num >= 7) { //there is a 30% chance the ai will take the new one to add some variety
bestposition = i;
}
}
if (score[i] > bestscore) { //always take the position with the best score
bestscore = score[i];
bestposition = i;
}
}
return bestposition;
}
Any help solving this problem would be greatly appreciated and any suggestions to generally improve my code are welcome
Looks like there is no increment in one of the loops.
Change:
for (i = inp + 1; i <= 6; i) to for (i = inp + 1; i <= 6; ++i)
and see if it helps.

Build a simple text square/rectangle using "Xs" and printf

I am trying to build a square/rectangle using "Xs" on a 1:1 scale with the length and width, but the logic seems to be not perfect
void draw (float x, float y) {
int i, j;
int length = (int)x + 0;
int width = (int)y + 0;
for (i = 1; i < length; i++) {
for (j = 1; j < width; j++) {
if (((i = 1) || (i = length)) && ((j = 1) || (j = width))) {
printf("x");
} else {
printf(" ");
}
}
printf("\n");
}
}
The problem is that the loop iterates endlessly printing x's everywhere. I'm expecting Xs to be printed out in either a square or rectangular shape (depending on the length or width).
I see 3 flaws in your logic.
you mix = (assignment) with == comparison.
This is why your loop never ends: you always reset i to 1 with your if (((i = 1) || (i = length)) &...
you're not going far enough with your variables:
if i < length, then you'll never have it reach length and print the bottom line of X's
you can't draw a rectangle because your && in the test (((i = 1) || (i = length)) && ((j = 1) || (j = width))) is too restrictive. It can't work if width different from length.
You must learn the logic by yourself using tutorials:
Here such questions will be discarded by sometime-sad people. But as a welcome, here it is (you can replace y in the second case by x, but I thought it would help you understand):
#include <stdio.h>
#include <string.h>
void draw (float x, float y)
{
int i,j;
int length = (int)x + 0;
int width = (int)y + 0;
for(i=1; i<=length; i++) {
for(j=1;j<=width;j++) {
if(((i==1)||(i==length))) {
printf("x");
} else {
if (((j==1)||(j==width))) {
printf("y");
} else {
printf(" ");
}
}
}
printf("\n");
}
}

how to create a diamond in c using only 3 printf and 3 n\t\

I am attempting to create a diamond in c with the constraints of only 3 printfs and 3 n\t. this requires me to use loops. I know how to make an upside down triangle and a triangle but cant use that because there are too many printfs. i will attach my code so far. I am aware it does not make a diamond, and some awfully strange shape, but that it what i'm trying to work off and edit to make into a diamond, I just haven't been able to figure it out.
if (type_of_shape == 5)
{
for (i = 0; i < width; i++)
{
for (j = 0;j < ((width - 1) / 2) - i ||(width -1)/2 < i && j + (width-1)/2 < i; j++)
{
printf(" ");
}
for (k = 0;k<width && k < (j*2+1) ; k++)
{
printf("*");
}
printf("\n");
}
}
//int width = 5;
int row, col;
int spaces, stars;
int half, rate;
half = width / 2 + 1;
rate = 1;
for(row = 1; 0 < row && row <= half; row += rate) {
spaces = half - row;
stars = row * 2 -1;
printf("%*s", spaces, "");
for (col = 0; col < stars; col++)
printf("*");
printf("\n");
if(row == half)
rate = -rate;
}
I got it down to a single line which has a single loop, with a single printf statement.
It involved some tricky use of abs.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int w = 9;
for(int l=0; l < w; ++l) printf("%*.*s\n", abs(w/2 - l)+abs((2*l+1)-(2*l+1>w)*2*w), abs((2*l+1)-(2*l+1>w)*2*w), "**************");
return 0;
}
2 loops (one for, one while).
2 printf statements.
Note:
This works with odd Widths.
An even width produces a diamond with Width+1
My IDEOne code
int main(void)
{
int width = 9;
int layer;
width+=2;
for(layer=0; layer<width/2; ++layer)
{
printf("%*.*s\n", width/2+layer + 1,layer*2 + 1, "**************************");
}
layer--;
while (layer --> 0)
{
printf("%*.*s\n", width/2+layer + 1,layer*2 + 1, "**************************");
}
return 0;
}
Output
Success time: 0 memory: 2168 signal:0
*
***
*****
*******
*********
*******
*****
***
*
Here's a solution with no loops at all. (looping accomplished via recursion), and 3 printf statements:
#include <stdio.h>
void drawDiamond(int width, int stars)
{
static const char* txt = "*****************************";
if (stars == width) {
printf("%*.*s\n",width, width, txt);
return;
}
printf("%*.*s\n", (width+stars)/2, stars, txt);
drawDiamond(width, stars+2);
printf("%*.*s\n", (width+stars)/2, stars, txt);
}
int main(void)
{
drawDiamond(9, 1);
return 0;
}

Resources