Why does my function always return 1? - c

I'm writing a function that's supposed to check whether there is a winner or not in a game of "noughts and crosses", or "three in a row".
The game works by first drawing out 3 x 3 squares in the command prompt. The user then moves the cursor between the squares, and presses enter to place an "X". The next selected square gets an "O" placed in it, and then an "X" again, and so on. After turn 5 (the first possible turn there could be a winner) the program checks if there is a winner after every turn, and if none is found after 9 turns (when all squares have something in them) the program declares a draw.
However, the function I've written to check for a winner always returns 1 when it's called, which means there is a winner (X more specifically, since thatäs the one that made the last move). Therefore the game ends on turn 5, no matter what the squares contain.
Here is my code:
int control(char p[3][3]) {
int i;
for (i = 0; i <= 3; i++) //Checks if any of the horizontals have 3 of the same markers in a row
if (p[i][1] == p[i][2] && p[i][2] == p[i][3])
return 1;
for (i = 0; i <= 3; i++) //Checks if any of the vertical columns have 3 of the same markers
if (p[1][i] == p[2][i] && p[2][i] == p[3][i])
return 1;
else if (p[1][1] == p[2][2] && p[2][2] == p[3][3]) //Checks if top left, middle and bottom right squares have the same marker
return 1;
else if (p[3][1] == p[2][2] && p[2][2] == p[1][3]) //Checks if the top right, middle and bottom left have the same marker
return 1;
else //If none of the above have the same 3 markers, the game keeps going
return 0;
}

You are passing in a 3x3 array (with indices 0, 1 and 2 in each dimension), but in your loops you are iterating 4 times (indices 0, 1, 2 and 3). Try for (i = 0; i < 3; i++) in your loops instead, as your loops will now check values beyond the boundaries of the p array, and if you are unlucky the contents of that memory causes your control function to return 1.
Finally, I think the final else-block should not be in the loop, but rather outside of it: If both loops have run and you have not returned yet, you can safely return 0, but you wouldn't want to return a 0 prematurely before you have checked all your verticals.
Here is the function with the changes to the indices and the diagonal checks and final else-block fished out of the second for-loop:
int control(char p[3][3]) {
int i;
/* Check horizontals */
for (i = 0; i < 3; i++)
if (p[i][0] == p[i][1] && p[i][1] == p[i][2])
return 1;
/* Check verticals */
for (i = 0; i < 3; i++)
if (p[0][i] == p[1][i] && p[1][i] == p[2][i])
return 1;
/* Check diagonals */
if (p[0][0] == p[1][1] && p[1][1] == p[2][2])
return 1;
if (p[2][0] == p[1][1] && p[1][1] == p[0][2])
return 1;
return 0;
}

Related

C: For-loop is executing despite ignoring initialization and increment expressions, therefore always true

CONTEXT:
Hello, I'm trying to print a 7x6 Connect Four board where each section is |___| with three underscores. I want to create each center underscore an element of a 2D array so I can later update it.
CONFLICT:
I am getting no errors or warnings, but my output is just |________ ... with an infinite amount of underscores. I have successfully rewritten the code where three underscores are printed without assigning the center into an array (however obviously this code is useless for the sake of making an actual game since I can't update the center underscores). All the loop declarations in my current code were used in that successful variation, so I'm pretty sure those are not my issue. I can provide that code as well if you think it can help you. What I do know is that colCnt (column count) is incrementing forever and undCnt (underscore count) is stuck at 2. Because of this, I suspect that this for-loop is the primary issue in my code, however I do not know where:
// Only print `_` three times as long as there have been 7 total or less vertical lines printed
for (int undCnt = 0; undCnt < 3 && vertCnt <= 6; undCnt++)
{
// Print left and right sections as `_`
if(undCnt != 1)
{
printf("_");
// If printing left section, increment column count
if(undCnt = 1){colCnt++;}
}
// Assign middle section to board array and prints it as `_`
else if(undCnt == 1)
{
arr[rowCnt][colCnt] = '_';
printf("%c", arr[rowCnt][colCnt]);
}
}
CODE:
#include <stdio.h>
void PrintBoard(char arr[6][7]);
int main()
{
// Declaration of 7x6 2D board array: board[row][col]
char board[6][7];
PrintBoard(board);
return 0;
}
void PrintBoard(char arr[6][7])
{
int vertCnt = 0; // Counts vertical lines (8 per row, separates sections)
int undCnt = 0; // Counts underscores (3 per section)
int rowCnt = 0; // Counts rows (6 total)
int colCnt = 0; // Count columns (7 total)
// Print game title
printf(" ~~ CONNECT FOUR ~~\n\n");
for (int rowCnt = 0; rowCnt <= 6; rowCnt++)
{
// If current row is not the first, start it on a new line
if (rowCnt > 0)
{
printf("\n");
}
// Creation of row: |___|___|___|___|___|___|___|
for (int vertCnt = 0; vertCnt < 8; vertCnt++)
{
printf("|");
// Only print `_` three times as long as there have been 7 total or less vertical lines printed
for (int undCnt = 0; undCnt < 3 && vertCnt <= 6; undCnt++)
{
// Print left and right sections as `_`
if(undCnt != 1)
{
printf("_");
// If printing left section, increment column count
if(undCnt = 1){colCnt++;}
}
// Assign middle section to board array and prints it as `_`
else if(undCnt == 1)
{
arr[rowCnt][colCnt] = '_';
printf("%c", arr[rowCnt][colCnt]);
}
}
}
}
// Print column numbers
printf("\n 1 2 3 4 5 6 7\n\n");
/* HOW THE BOARD SHOULD LOOK:
~~ CONNECT FOUR ~~ <--- GAME TITLE
|___|___|___|___|___|___|___|
|___|___|___|___|___|___|___|
|___|___|___|___|___|___|___| <--- BOARD
|___|___|___|___|___|___|___|
|___|___|___|___|___|___|___|
|___|___|___|___|___|___|___|
1 2 3 4 5 6 7 <--- COLUMN NUMBERS
*/
}
If you have any questions just let me know. Thanks!
Have you considered attempting to print "___|" all at once? Then all you have to do is check column count, if it is 0 print a '|' if it is the maximum column value add a newline character.
for(int row_count = 0; row_count<max_rows; rows++)
{
for ( int column_count = 0; column_count<max_columns; columns++)
{
if( column_count==0)
{
printf('|');
}
printf("___|");
}
printf('\n');
}
maybe something like this?

Replace a character with another character + Setting a tie game

This is for Homework
I have to create a game of TicTacToe for a project and I have two issues. Also I apologize if I'm violating a rule by having two questions within one post, If it's not allowed then I'd appreciate someone notifying me in the comments and I'll go ahead and break this into two separate posts. I'll post my code then ask my questions following the code.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char table[3][3];
void clear_table();
void player1_move();
void player2_move();
void the_matrix(); // Like the movie
char check_three();
int main() {
srand(time(NULL));
char win;
printf("This program plays the game of Tic Tac Toe.\n");
win = ' ';
clear_table();
do {
the_matrix(); // Like the movie
player1_move();
win = check_three(); // Check win for player 1
if (win != ' ')
break;
player2_move();
win = check_three(); // Check win for player 2
}
while (win == ' ');
the_matrix(); // Shows the final move+Like the movie
if (win == 'O')
printf("Congratulations, Player 1 wins!\n");
else
printf("Congratulations, Player 1 lost!\n");
// the_matrix (); //Shows the final move+Like the movie
return 0;
}
void clear_table() {
// Creates empty spaces for the user and computer to enter stuff in
int i, j, k;
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++)
// for(l = 0; k < 3; j++)
table[i][j] = ' ';
}
}
void player1_move() {
// Moves that player 1 can and can't make
int x, y, z;
printf("Player 1 enter your selection[row, col]: ");
scanf("%d, %d", &x, &y);
x--;
y--;
// z--;
if (table[x][y] != ' ') {
printf("Space already taken, please try again.\n");
player1_move();
}
else
table[x][y] = 'O'; // O goes first for some reason
}
void player2_move() {
// Needs work!!
// Call srand in the main
int a = rand() % 3;
int b = rand() % 3;
// Make it so the game would end in a tie when possible
for (a = rand() % 3; a < 3; a++) {
for (b = rand() % 3; b < 3;
b++) // For loops causing issues in randomization?
// for(c = 0; c < 3; c++)
if (table[a][b] == ' ')
break;
if (table[a][b] == ' ') // Checks the rows and columns
break;
}
if (a * b == 9)
**Kinda works ? ** {
printf("Game Over, No Player Wins\n");
exit(0);
}
else
table[a][b] = 'X';
}
void the_matrix() { // Like the movie
**Get rid of the underscores **
int m;
printf("The current state of the board:\n");
for (m = 0; m < 3; m++) {
printf("%c_ %c_ %c_\n", table[m][0], table[m][1], table[m][2]);
}
printf("\n");
}
char check_three() {
int w;
// char table[3][3];
for (w = 0; w < 3; w++) {
if (table[w][0] == table[w][2] && table[w][0] == table[w][1])
return table[w][0]; // Row Check
}
for (w = 0; w < 3; w++) {
if (table[0][w] == table[2][w] && table[0][w] == table[1][w])
return table[0][w]; // Col Check
}
if (table[0][0] == table[1][1] && table[1][1] == table[2][2])
return table[0][0];
if (table[0][2] == table[1][1] && table[1][1] == table[2][0])
return table[0][2]; // Diag Check
return ' ';
}
First Question
So my first question is with a draw game. On the player two function I have a snip of code set to determine a draw game. Initially I assumed that if the X's and O's were to multiply to 9 then that would mean that the board would be filled up then that would result in a draw game. [This is within my third function - player2_move near the end of the function] It kind of works, but sometimes the program just preemptively ends the game. It's a bit hard to test it because the computers moves are randomized and most of the times I've tried, I ended up winning accidentally. My question is what would I need to do to set up my program to essentially have a better way of determining a draw game.
Second Question
On my 4th function called the_matrix I need help with formatting. The assignment requires the format to be a little like this where if I were to enter in the coordinates 1,1 then the board would look like this:
O _ _ with the proceeding lines near the bottom to be blank. However as my program is right now, it looks like this:
O_ _ _
What I want to do is swap or replace the underscore with the user's input. Not entirely sure how to do that and any help would be appreciated.
I apologize if I violated any rules for stackoverflow by having two questions in one and I'm also sorry for this huge post.

Moving along a 1D Array

I came across this question in an online coding challenge recently, but I can't seem to make any head way.
There's a 1D array consisting of 0 and 1.
A player starts at index 0 and needs to go beyond the length of the array.
Once the length of the array is crossed the player wins.
The player can only go into indices that have a 0.
A player can move 1 step back, 1 step forward or m steps forward.
The question is how to find out if a game is winnable.
It all boils down to the following function signature:
boolean winnable(int[] arr, int m){
}
Can someone help me with an algorithm to get started.
Added Later
I can up with this algorithm, which of course doesn't pass most of the test cases.
public static boolean winnable(int[] arr, int m){
int currPos = 0;
for(int i=1; i< arr.length; i++){
if(currPos == arr.length -1 - m) return true;
else if(arr[i] == 0)currPos++;
else if(arr[i] == 1){
if(arr[currPos + m] == 0) currPos = currPos + m;
}
}
return false;
}
Iterate over the entire array. For each cell ->
If it is 1, mark it as unreachable. Else, check if it is reachable. A cell is reachable if either
A) the cell before it is reachable
B) the cell m cells before it is reachable.
Once a cell is marked as reachable, you must also mark all consecutive cells behind it which are all '0' as reachable. Once you have marked a cell less than m cells from the end as reachable, that means the end is reachable. If you've marked the last m cells as unreachable, the end is unreachable.
You're going to need a queue, or some other way to remember what indexes need to be checked. Each time you reach a zero that hasn't been seen before, you need to check 3 indexes: the one before, the one after, and the one at distance m.
The size of the queue is limited to the number of zeros in the input array. For example, if the input array has 10 zeros, then the queue can't possibly have more than 10 items in it. So you could implement the queue as a simple array that's the same size as the input array.
Here's some pseudo-code that shows how to solve the problem:
writeToQueue(0)
while ( queue is not empty )
{
index = readFromQueue
if ( index >= length-m )
the game is winnable
array[index] = 1 // mark this index as visited
if ( index > 0 && array[index-1] == 0 ) // 1 step back
writeToQueue(index-1)
if ( array[index+1] == 0 ) // 1 step forward
writeToQueue(index+1)
if ( array[index+m] == 0 ) // m steps forward
writeToQueue(index+m)
}
if the queue empties without reaching the end, the game is not winnable
Note that the input array is used to keep track of which indexes have been visited, i.e. each 0 that is found is changed to a 1, until either the game is won, or no more 0's are reachable.
I just added an accepted solution to this problem on HackerRank.
This is a recursive approach. I created a helper function that would take the currentIndx, array, jumpValue and a Set of visited indices as arguments.
Since currentIndx can't be < 0, I return false;
If currentIndx > arr.length - 1, we are done.
If the value at currentIndx is not 0, we again have to return false since it cannot be in the path.
Now, after these checks we add the visited index to the set. If the add operation returns false, that index must have been visited previously; so we return false.
Then, we recurse. We call the same function with currentIndx - 1, currentIndx + 1 and currentIndx + jumpValue to see what it returns. If any of these are true, we have found a path.
[Java source code]
It can be solved cleanly using BFS. Here goes my solution:
private static boolean isReachable(int[] array, int m) {
boolean[] visited = new boolean[array.length];
Queue<Integer> queue = new LinkedList<>();
queue.add(0);
visited[0] = true;
while (!queue.isEmpty()) {
Integer current = queue.poll();
if (current+m >= array.length) {
return true;
} else if (current+m < array.length && array[current+m] == 0 && !visited[current+m]) {
queue.add(current+m);
visited[current+m] = true;
}
if (current+1 >= array.length) {
return true;
} else if (current+1 < array.length && array[current+1] == 0 && !visited[current+1]) {
queue.add(current+1);
visited[current+1] = true;
}
if (current-1 >= 0 && array[current-1] == 0 && !visited[current-1]) {
queue.add(current-1);
visited[current-1] = true;
}
}
return false;
}

Out of bounds 2D array error in C

Im stuck on this one part and I was hoping to get some help. I have a project that is basically a word search. The program reads in a file that contains the Rows and columns followed by the word search puzzle itself. You are required to create possible combinations of strings from the word search and check those combinations with a dictionary that is provided as another text document.
Here's an example of the file read in 1st is Rows and 2nd is Cols followed by the word search puzzle:
4 4
syrt
gtrp
faaq
pmrc
So I have been able to get most of the code to work except for the function that creates strings for the above file. Basically It needs to search the wordsearch and create strings, each created string gets passed on to another function to check if it's in the dictionary. However my code keeps going out of bounds when creating the strings, and it's continuing to cause Seg faults which is really frustrating.
Theses are the constants that are declared, its every possible direction to go while searching the word search puzzle for possible string combinations
const int DX_SIZE = 8;
const int DX[] = {-1,-1,-1,0,0,1,1,1};
const int DY[] = {-1,0,1,-1,1,-1,0,1};
This is the function I have to create the strings:
int strCreate(char** puzzle, char** dictionary, int n, int rows, int col){
int x, y;
int nextX, nextY, i;
char str[20] = {0};
int length = 1;
for(x = 0; x < rows; x++)
{
for(y = 0; y < col; y++)
{
//Grabs the base letter
str[0] = puzzle[x][y];
length = 1;
for(i = 0; i < DX_SIZE; i++)
{
while(length < MAX_WORD_SIZE)
{
nextX = x + DX[i]*length;
nextY = y + DY[i]*length;
// Checking bounds of next array
//This is where I'm having trouble.
if((x + nextX) < 0 || (nextX + x) > (col-1)){
printf("Out of bounds\n");
break;
}
if((y + nextY) < 0 || (nextY + y) > (rows-1)){
printf("Out of bounds\n");
break;
}
str[length] = puzzle[nextX][nextY];
//search for str in dictionary
checkStr(str, dictionary, n);
length++;
}
memset(&str[1], '\0', 19);
}
}
}
return 0;
}
I know i'm not checking the bounds properly I just can't figure out how to. When X = 1 and nextX = -1, that passes the bounds check, however say the array is at puzzle[0][0] nextX would put puzzle[-1][0] which is out of bounds causing the seg fault.
Thank you for taking the time to read, and I appreciate any help at all.
nextX and nextY are the indices used to access the array puzzle. Then the array bound check should also include the same. But the array bound check includes for example x+nextX.
// Checking bounds of next array
//This is where I'm having trouble.
if((x + nextX) < 0 || (nextX + x) > (col-1)){
printf("Out of bounds\n");
break;
}
Example:
if( nextX < 0)
printf("Out of bounds...\n");

Comparing elements in a 2D array

I'm trying to compare elements being fed in from a text file into my 2D array. An example of the textfile is as follows:
ABCDE
FGHIK
LMNOP
I know I can read in the file fine and can print each element as well.
I'm trying to go through and compare each character with the next. In my head this is how it works:
If they match, move on to the next char, then compare that char with the next. If they do not match, then print "error" to the terminal and break out of the switch statement. Though when I run this in my program it only prints "Is this being accsessed?" "It sure is". Any help on what I could be doing wrong would be very helpful.
void match_char(char** array, int height, int width){
int a, i, j;
printf("Is this being accessed?");
a = 0;
i = 0;
j = 0;
switch(a){
case 1: if(a <1 ){
for(j = 0; j < width; j++){
if (array[i][j] != array[i][j+1]){
printf("error\n");
break;
} else if(j == width) {
a=1;
break;
}
}
}/* End of case 1*/
case 2: if (a > 0 && a < 2){
for(i = 0; i < height; i++){
if (array[i][j] != array[i+1][j]){
printf("error\n");
break;
}else if(i == height) {
printf("No error");
a=2;
break;
}
}
}/* End of case 2 */
case 3:
if (a > 2) {
a=0;
break;
}
}/*End of switch */
printf("It sure is");
}
What Case Means
Just to be clear, in case X, the X is not some label for that case, it's a check of whether the Y in switch(Y) equals X.
To help visualize this, let's rewrite the switch as an if... else statement.
a = 0;
if(a == 1){ // == case 1
// stuff
} else if(a == 2){ // == case 2
// stuff
} else { // == default
...
Those if statements you have in the switch right now have NO bearing on whether that case is executed.
How Switch works
Now, let's talk about how a switch works. When the code is compiled, depending on the range of values for each case, either a jump table or a something virtually identical to a if... else if... else statement is generated. Regardless, you have a list of instructions. The pseudo-assembly looks like this:
instruction n : multiply the value of a by some offset and jump to a*offset + n
n +a*offset_1 : do stuff
jump to m // break
n +a*offset_2 : do stuff
jump to m // break
n +a*offset_3 : do stuff
jump to m // break
n +a*offset_4 : do stuff
jump to m // break
instruction m : do more stuff
If you leave off the breaks,
instruction n : multiply the value of a by some offset and jump to a*offset + n
n +a*offset_1 : do stuff
n +a*offset_2 : do stuff
n +a*offset_3 : do stuff
n +a*offset_4 : do stuff
instruction m : do more stuff
So you can see why the breaks prevent the rest of the cases from being executed - and leaving them out makes that case and every one after it execute, regardless of whether or not you meet the case condition.
in the first case label you ask if a < 1 after getting there with a == 1 so the if is always false.
in the second case, a == 2, so it cannot be equal to 1 (the if checks for a > 0 and a < 2, so it can only be equal to 1 to get into the if)
in the third case you ask for a > 2 (always, as you get there when a == 3) so all the if conditions must be redefined properly.
I suppose you know that you initialize a = 0 and have no case for that value of a, so you are just skipping the switch without entering any of the cases.
You have also not used break; sentences, i suppose purposely, but as you don't have any case for a == 0, you'll never get into any of the switch cases.

Resources