Hello I'm trying to code a tic-tac-toe game and wanted to create an AI that plays randomly, except when the human player is about to win. However, I've run into a small issue here. Suppose the index(?) of the 3x3 grid goes like this:
123
456
789
If a and b are filled by the opponent's shape, then I want to check if:
a) the two numbers are in a row/column/diagonal
then,
b) the winning position (that the AI will block) is empty or filled already
def preventOwin(start): #win conditions
#rows
if start[1] == start[2] == 'O':
a = 3
if checkfree(a) == True:
print(start.update({a:'X'}))
return True
elif start[1] == start[3] == 'O':
a = 2
if checkfree(a) == True:
print(start.update({a:'X'}))
return True
etc.
So I want the AI to check if there are two O's in a row (eg in position 1 and 2), and see if the third position is filled already. If no, then I just continue with my game by updating the 3rd position's dictionary value to O. If yes, then there's a problem because then I want to check the rest of the elif statements and see if they're true or not.
eg:
board is:
-|x|o
-|o|-
x|o|-
the human plays:
o|x|o
-|o|-
x|o|-
The AI sees 1 and 3 are O's, but 2 is filled. I want to check the rest of the conditions after this because, in this case, 1 and 5 are also O's and 9 is empty.
Is this question contradictory to the nature of if-else statements?
Related
TLDR: I am making a tic tac toe game in c++. My win condition checking if statements are failing and I don't know why :(
The board state is maintained by a global 2D board array
int board[3][3]{ {0,0,0}, {0,0,0}, {0,0,0}};
As the game plays on, a 1 or 2 is inserted to represent an X or O. Periodically I check for a winner with a function that uses 8 if statements to check for win conditions (3 horizontals, 3 verticals, or 2 diagonals).
int winCheck()
{
int winner = 0;
// check horizontal 1
if ((board[0][0] == board[0][1] == board[0][2]) && (board[0][2] > 0))
{
winner = board[0][0];
}
// check horizontal 2
...
return winner;
}
Any ideas? I think the logic is fine but my syntax is off.
Sigh. After pulling my brain out for 4 hours. It appears that you can't logically compare 3 things in an if statement ie:
if (A == B == C)
You must instead do 2 comparisons...
if (A == B && B == C)
Maybe this will help someone someday...
I am currently learning C++ at my school, and am making a word sleuth as part of a project that I have to submit. For this, I have already made the grid of alphabets and other necessary things (clues, rules, etc.). I am taking the input in the form of coordinates in an integer array whereby the user enters 4 values in the array, signifying the initial row and column number and the final row and column number, corresponding to which are the first and last alphabets of a particular word.
After doing this, I am now comparing the array input by the user with the array I have already defined that has the coordinates of that particular word. This is shown here :
cout<<"Enter the coordinates of starting and final characters : row1 col1 row2 col2 "<<endl;
for (z = 0; z < 4; z++) //first for loop
cin>>p[z]; //taking the input as an array 'p'
for (b = 0; b < 4; b++) //second for loop
{
if (p[b] == messi[b])
b+=0;
}
if (b == 4)
cout<<"Great!!!! You have answered the question correctly"<<"\n\n";
else
cout<<"You got this one wrong mate! Try again :)"<<"\n\n";
Here, messi[b] is the array which has the coordinates corresponding to the word 'MESSI' in the grid. Now, to my mind, the 'if' statement after the second for loop must contain the condition to check if b = 3. However, when I do that, the output always comes out to be what the 'else' statement says i.e. "You got this..." for every input. However, when I impose the condition to check if b = 4, the output comes out to be what the 'if' statement says i.e. "Great!!..." for every input.
What wrong am I doing? I hope I am clear enough in explaining the problem to you. I am using CodeBlocks 16.01.
It's a bit unclear what you are doing, as the program stands, b will always be equal to 4 after the second for-loop since the last time to condition was true, b < 4. So after the increment, it will be 4.
Inside the second for-loop you also have the NOP code b += 0; which does absolutely nothing to the code. What is the intention here?
I'm just a beginner in C++ and while making a code to create the TicTacToe game I got stuck at the while statement that will push the game to keep going until winning conditions are fulfilled :
while(((table[0][0]!='X')&&(table[1][1]!='X')&&(table[2][2]!='X')))
This is just the diagonal condition (Putting all the conditions will give you eyesore...).
THE PROBLEM IS that this is not working even if the conditions are fulfilled (I'm sure because I use a cout at the end), however when I change && with || the condition work !
I thought maybe because of the != that affect everything ??
EDIT: Minimal Example (I removed the floating point !) :
#include <iostream>
using namespace std;
int main()
{
int tailleX(3),tailleY(3); //The Size of the table.
char table[tailleX][tailleY]; //TictacToe table.
table[0][0]='N';
table[0][1]='N';
table[0][2]='N';
table[1][0]='N';
table[1][1]='N'; //Randomly filling the array to avoid an error
table[1][2]='N';
table[2][0]='N';
table[2][1]='N';
table[2][2]='N';
int coorP1; //The Coordinate of the square (Exp: x=1 , y=2 will be 1.2)
while(((table[0][0]!='X')&&(table[1][1]!='X')&&(table[2][2]!='X'))) //For the minimal example I made just the diagonal condition
{
cout<<"PLAYER1: Enter the coordination to score: (Exemple: 1, 2, 3..) "<<endl;
cin>>coorP1;
switch(coorP1) //Filling the square depending on the coordinates.//I used If because Switch does not work.
{
case 1:
table[0][0]='X';
break;
case 2:
table[0][1]='X';
break;
case 3:
table[0][2]='X';
break;
case 4:
table[1][0]='X';
break;
case 5:
table[1][1]='X';
break;
case 6:
table[1][2]='X';
break;
case 7:
table[2][0]='X';
break;
case 8:
table[2][1]='X';
break;
case 9:
table[2][2]='X';
break;
}
}
cout<<"You won"<<endl;
return 0;
}
The problem here is your test condition. Your loop repeats if you enter 2, 3, 4, 6, 7, or 8. As soon as you enter 1, 5, or 9, the loop exits. If you enter 1, 5, or 9, then one of the diagonal values is set to 'X'. while loops while the condition is true. As soon as the condition evaluates to false, it exits. When you enter 1, 5, or 9, you cause the condition to be false.
Imagine, for a second, that table[0][0] is 'X', table[1][1] is 'N', and table[2][2] is 'N'. In other words, the board looks like this:
X | N | N
--+---+---
N | N | N
--+---+---
N | N | N
Then your test condition is:
table[0][0] != 'X' && table[1][1] != 'X' && table[2][2] != 'X'
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
false true true
If you logically AND these together (as you are with &&), this evaluates to false (which makes sense: false AND true should evaluate to false; only true AND true should evaluate to true).
So what should your test condition be?
What you really want is to do is loop only if the user doesn't have 3 in a row. In other words, check if the user has 3 in a row; if he does not have 3 in a row, then proceed.
We can construct that logical statement as:
// This checks if the user has 3 in a row
table[0][0] == 'X' && table[1][1] == 'X' && table[2][2] == 'X'
// We want to check if the user does NOT have 3 in a row,
// so we can negate the above with !
!(table[0][0] == 'X' && table[1][1] == 'X' && table[2][2] == 'X')
// With De Morgan's laws, we can simplify this to:
table[0][0] != 'X' || table[1][1] != 'X' || table[2][2] != 'X'
Thus, your looping condition should be one of (they're both equivalent; pick whichever one makes more sense to you):
!(table[0][0] == 'X' && table[1][1] == 'X' && table[2][2] == 'X')
This checks if the user does not have 3 in a row
table[0][0] != 'X' || table[1][1] != 'X' || table[2][2] != 'X'
This checks if the user does not have an 'X' any one of the needed positions. It logically follows that if the user is missing an 'X' in one of these positions, the user cannot have 3 in a row. This is just an application of De Morgan's laws to the previous logical statement.
A critical part of learning to program is learning to avoid doing similar things over and over in your source code. You need to abstract the similar behaviors so they can share one chunk of code. So the computer does all that work, but when writing the source code, you don't do all that work.
Your attempt to build up a giant boolean expression of the game state is an extreme example of how not to program. It is a common beginner mistake (and far from the only example of that beginner mistake in your code). Fixing that giant boolean expression is possible, but it would be terribly counter productive along your path of learning to program. Instead you should take that as an example to learn how to combine and abstract work:
First understand the game concepts: A game state is one of wonX, wonY, draw, inProgress. You could define an enum for those possibilities. Each of the eight lines through the board has the same four possible states, where the game state is wonX or wonY if any line has that state, and the game state is inProgress is no line is wonX or wonY and some line is inProgress.
Because draw combines from individual rline up to board level in the opposite way that wonX or wonY does, the combination operation would be tricky at a high level and easier in the code that also determines line state.
So I suggest writing a function that takes the three values of one line as input and also takes game state accumulator as input, and returns an updated game state. In each round, you would start computing the game state as draw, then call the function for each of 8 lines to update it. If the line is a win for X or Y, then the state would unconditionally change to that. If the line is inProgress, the state would change to that only if the state was draw. If the line is draw, that doesn't change the state (one line in a draw state says nothing about the game state).
Good design would further abstract and combine several more aspects of your code, but the one that is the big problem from your failure to abstract and combine, is as I indicated the step that looks at one line and computes its impact on the state of the whole board.
In general you will find your most powerful tool for abstracting and combining work is to move that chunk of the work into a function (as I described above). Trying to do too much not split out into seperate functions is a major beginner mistake.
I'm working on an assignment in Visual Studio Express 2012, and the challenge asks me to create an app that allows a user to enter three runners' names and finishing times. I'm working on the flowchart for the If...Then...Else portion for the first, second and third place winners. Can anyone help me or steer me in the right direction for creating the conditional statement portion?
Here's what I have:
If intRunner1 < intRunner2 And intRunner1 < intRunner3 Then
lblDisplay.Text = "First Place"
End If
If intRunner2 < intRunner1 And intRunner2 < intRunner3 Then
lblDisplay.Text = "First Place"
End If
If intRunner3 < intRunner1 And intRunner3 < intRunner2 Then
lblDisplay.Text = "First Place"
I also have this:
If intFinish1 < intFinish2 Then
If intFinish1 < intFinish3 Then
lblFirstPlace.Text = "Runner 1 finished in first place."
Else
lblSecondPlace.Text = "Runner 1 finished in second place."
Else
If intFinish1 < intFinish3 Then
lblFirstPlace.Text = "Runner 1 finished in second place."
Else
lblThirdPlace.Text = "Runner 1 finished in thirdplace"
End If
End If
If all data is input at the same time :
You should make 2d array of size equal to the number of runners. Insert the name of the runner in the first dimension, and runner time in the second. Then sort this array on the 2nd dimension to get winners. As the scope is very small and just for demonstration, you can just use a if then else condition to check for the sorting.
If you input the runner one at a time
Just insert the runners in the 2d array in the correct order and out put the array after all data has been inserted to get list of winners.
For example pseudocode for second method :
create 2d array A
repeat for each runner
input runner name
input runner time
if A has runners
check runner against each runner in A
insert runner at the correct position
else
insert runner in A
end repeat
If you are only using variables and not arrays : Let us assume u have runners A B & C
These are the possible scenarios : ABC, ACB, BAC, BCA, CAB, CBA
You have to check for each of them.
Take A
if A beats B (then he is definately second or first)
if A beats C (then he is definately first)
A is first
if B beats C
B is second, C is third
else
C is second, B is third
else
A is second
if B beats C
B is first, C is third
else
C is first, B is third
else ... if A beat C.... and so on
Project this to check for every possible scenario.
I have a django list as below: the hotess1 is a database result set.
for hotel in hotels1:
if models.CalendarDay.objects.filter(hotel=hotel, date=date).count() == 0:
similar_venues.append(hotel)
The list size is dynamic but i want to return only first three values
I can do as below:
for hotel in hotels:
if models.CalendarDay.objects.filter(hotel=hotel, date=date).count() == 0:
similar_venues.append(hotel)
counter += 1
if counter == 3: break
but i want to do it in a better way.. any help
You can use the slice operator: my_list[:3] will return a list containg the first three values of my_list.
(unless there are less than three values, in which case you get everything back).