Is it possible to have two statements in an if statement? - artificial-intelligence

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:
i) the two numbers are in a row/column/diagonal
ii) the winning position (that the AI will block) is empty or filled already
in ONE if statement.
I tried splitting these questions into two if statements, but because there are so many cases, if I only do one then I can only really check for one throughout. The 'or' action also doesn't work because only one statement is a boolean.
def preventXwin(start): #win conditions
#rows alone
if start[1] == start[2] == 'X' and checkfree(a) == True:
a = 3
print(start.update({a:'O'}))
return True
elif start[1] == start[3] == 'X' and checkfree(a) == True:
a = 2
print(start.update({a:'O'}))
return True
elif start[2] == start[3] == 'X' and checkfree(a) == True:
a = 1
print(start.update({a:'O'}))
return True
etc.
I want it to perform what the above would in theory, and I tried this but it didn't work.
If anyone has any solutions that would be incredibly helpful :)

Related

Compact way to index from x to y in 2D list

I am doing the tictactoe project from the Cisco NetAkad course : https://www.youtube.com/watch?v=7GDtI9SpGgU
I did the game disregarding the stated project requirements.
I used for the board a normal list: board = [1, 2, 3, 4, 5, 6, 7, 8, 9]
The programm works and and the output is the same as the project asks for.
The project requirements state however specifically to use a 2D list: board = [[1, 2, 3], [4, 5, 6], [7, 8, 9]. As I wanted to practise using 2D lists I rewrote the programm and found it requires more lines and more complex indexing.
My 1st question is: in the function, which checks whether there is a winner, is it possible with a 2D list to just use indexing to check whether there are 3 consecutive "X" or "O" for all directions? If yes, how?
(I don't think writing the massive amount of 'if' combined with many 'and', like in the video, is efficient and using indexing works well with a normal list)
As a beginner my wording might be unclear, so here is the section checking whether "X" has won and below what I expect it to do:
if board[0][0:3].count("X") == 3 or board[1][0:3].count("X") == 3 \
or board[2][0:3].count("X") == 3 or board[0:3][0].count("X") == 3 \
or board[0:3][1].count("X") == 3 or board[0:3][2].count("X") == 3 \
or board[0:3][0:3].count("X") == 3 or board[0:3][3::-1].count("X") == 3:
print("I won: you lost.")
The index [0][0:3], [1][0:3] and [2][0:3] work as expected (rows), it recognises the win.
However [0:3][0] is being read as [0][0:3] when the programm is run. (checking colums doesn't work)
[0:3][0:3] and [0:3][3::-1] obviously doesn't work (diagonal).
2nd question: What better way is there to check for a winner?
Last question: Is there an advantage of using a 2D list over a normal list in this case?
I am thankful in advance for any feedback.
You can do something like below:
for key in ['X', 'O']:
temp = []
count = 0
for row in board:
if row.count(key) == 3:
count = 3
break
if key in row:
temp.append(row.index(key))
if count == 3 or (len(list(set(temp))) == 1 and len(temp) == 3) or temp in ([0,1,2], [2,1,0]):
print("I won: you lost. " + key + " wins")
The idea of the solution is to get the indexes of the positions of 'X' in the inner lists (the usage of indexes justifies the reason to go for a '2D list' [list of lists] per your last question). This is done by looping over the list per 'row' of the tic-tac-toe. We store the indexes in the variable 'temp'.
The first condition checks whether a row has 3 'X's and if yes, it breaks the execution of the for loop saving a count=3. The second condition is the most interesting because it stores the index of 'X' in the row. For example, when you have X in the middle column, at the end of the loop, temp will be equal to:
[2,2,2] if the tic-tac-toe was
O-X-
O-X-O
-X-O
Consequently, if there is a single unique number in the 'temp' list ([1,1,1] unique is 1, [2,2,2] unique is 2 etc), then there is a winner. This is done by:
len(list(set(temp))) # (inside) Get unique values / Make it a list / Measure its length
If the length is 1, then there is a unique position. In addition to that, and to account for the code running while the tic-tac-toe is not entirely filled, we check for len(temp) == 3. Finally, we check for a diagonal match using the 'temp in ([0,1,2], [2,1,0])' part of the condition
The reason why the 'index [0:3][0]' does not work as you expect it to, is because the first slice points to the entire list for which you are taking the value at position 0 which is [1,2,3]. In other words board[0:3] is equal to board
Since there are so few potential states and only 8 winning states, I might just go directly with evaluating them all:
gameboard = [
["x","-","-"],
["x","-","-"],
["x","-","-"]
]
possilbe_winning_states = [
[(0,0), (0,1), (0,2)],
[(1,0), (1,1), (1,2)],
[(2,0), (2,1), (2,2)],
[(0,0), (1,0), (2,0)],
[(0,1), (1,1), (2,1)],
[(0,2), (1,2), (2,2)],
[(0,0), (1,1), (2,2)],
[(0,2), (1,1), (2,0)]
]
for possilbe_winning_state in possilbe_winning_states:
squares = [gameboard[square[0]][square[1]] for square in possilbe_winning_state]
if squares.count("x") == 3:
print("X Win")
break
elif squares.count("o") == 3:
print("O Win")
break
else:
print("no winner yet")

my nested if statement, need to make an uninterruptible condition

I've been trying to program an Radio Control car to follow a line depending on the readings of five line-following sensors.
The line-following sensors give 1 when they are on the line and 0 when they are not.
For example: If the sensors reads 00100, the car will go forward.
I faced a problem, when the sensors read 11111 (dead end).
The car should make a uturn. While it is doing the uturn the condition of the sensors change.
Say it becomes 11000.
That new value takes me to another if statement which is if 11000 turn left and the uturn order is lost.
Question: How can I make the if statement for uturn uninterruptible by other if statements when the condition changes?
Use a boolean.
if (sensors == "11111") makingUturn = true
then
if (sensors == "00100") makingUturn = false
Now for all other conditions, check if makingUturn is false before continuing with the code for that condition
Note
In case it wasn't obvious, this wasn't meant as actual code to compile and execute. What I mean by if (sensors == "ddddd"), is to check that all 5 sensors have the value at each position of the string. And when I say makingUturn = bool is to replace the bool with a 1 or 0 depending on if you want true or false

x and y lengths differ in an apply

So I'm trying to run an apply function over an array. The idea is to look at the value in the risk factor column and if this is 1, use "OnsetFunction" and if it's a zero to use the HighOnsetFunction. The would then produce a column of values which populates another column in array.
> apply(OutComes, 1, function(x) { if(x["Risk_Factor"] == 1)
> + {OnsetFunction()}
> + else{ HighOnsetFunction()}})
I'm having trouble with the apply function above and keep getting this message.
>Error in xy.coords(x, y) : 'x' and 'y' lengths differ
There are only five rows in the array at the moment as I'm trying to make sure the code works on a small group before I extend it to be many people, but I'm not sure what the x and y are. I've seen this message with graphs, but never with this before.
I think you are trying to use ifelse but using apply and an if
Try:
ifelse(OutComes$Risk_Factor==1, OnsetFunction(), HighOnsetFunction())

Fastest way to search through a CSV and return specific array of values (Ruby)

Basically, I would like to search through a CSV that I read in. It will be read in as an array of arrays. I want to extract only the rows where the first element of the row is equal to a certain value. If this is true, I want to then extract the row as a unit and add it to an array for further data processing.
Right now, I am using
CSV.foreach(filepath) do |row|
if (row[0] == experiment)
exp1 = true && (row[0] == experiment) && row[7] == data)
if exp1
exp1_array.push(row)
end
end
end
What is currently happening is that it is way too slow, because the CSV is a huge file. I was wondering if anyone had a really quick way to read through a CSV, check for conditions, and add to a specific array if those conditions are true.
Also, I need to add to exp1_array if the first row says the name of experiment1, and then add to exp2_array if the first row says the name of experiment2, so that is why the first if conditional check exists.
If anyone could help I would be immensely grateful!!
If you want to avoid using a NoSQL database like suggested in comments, you can speed this up by avoiding duplicate checks.
Honestly this sounds more like a homework question than engineering question so I don't think NoSQL is appropriate.
Here is how you speed it up.
If loop is way too complicated & contains several unnecessary checks.
True is always true so there is no reason to check if it's true.
if (row[0] == experiment)
exp1 = (row[0] == experiment) && row[7] == data)
if exp1
exp1_array.push(row)
end
end
You are checking row[0] twice for same condition. When you remove that you get:
if (row[0] == experiment)
exp1 = (row[7] == data)
if exp1
exp1_array.push(row)
end
end
This can be further simplified into
if (row[0] == experiment)
if row[7] == data
exp1_array.push(row)
end
end
and this into
if row[0] == experiment && row[7] == data
exp1_array.push(row)
end
or make it a one-liner
exp1_array.push(row) if row[0] == experiment && row[7] == data
End result is
CSV.foreach(filepath) do |row|
exp1_array.push(row) if row[0] == experiment && row[7] == data
end
This will be faster because comparing every string to experiment twice is not cheap when repeated large enough number of times.
Now you can use select function to select rows you need for you. This might make it significantly faster because select is (I assume) written in C and thus very fast.
exp1_array = CSV.foreach(filepath)
.select { |row| row[0] == experiment && row[7] == data }

AS3 newbie "match 3" issue - matching types

I'm trying to make a "match 3" game. Instead of just having one type of each jewel that matches, I want to have 2 different types of each jewel that will then match. I've set up my movieclip with 12 frames, comprised of 6 pairs of different jewels, and randomizing which frame will play. I'm using Gary Rosenzweig's code (Actionscript Game Programming University) as a base.
I have 6 different arrays to hold the matching combinations (eg, m1 = [1,2], m2 = [3,4] ... m6 = [11,12]). I've set up my match conditions like this:
Standard match where frame numbers match directly:
if (mc1.currentFrame == mc2.currentFrame) {
match.push(mc2);
Match where frame numbers are different, but they're part of the same pair and should match:
} else if (mc1.currentFrame in m1 && mc2.currentFrame in m1) {
match.push(mc2);
The problem is that I'm not getting any matches from the 2nd condition. I've set traces up for each condition that show the two frame numbers being compared, but pairs that should be matching aren't.
Help!!!! As a complete AS3 newbie, I've tried to figure this out every which way I can, but no luck so far. Any assistance would be greatly appreciated.
Uh, I've never used "in", so there might be some weirdness with that.
Instead of
} else if (mc1.currentFrame in m1 && mc2.currentFrame in m1) {
You might try
} else if (m1.indexOf(mc1.currentFrame)>-1 && m1.indexOf(mc2.currentFrame)>-1) {
Oh, you are also checking mc2 current frame against m1 and not m2. Did you want to do that?

Resources