C
C#2mo ago
zoon_

✅ Tic tac toe

im trying to implement tic tac toe with DFS and im struggling to get it to work properly
No description
37 Replies
zoon_
zoon_OP2mo ago
$paste
MODiX
MODiX2mo ago
If your code is too long, you can post to https://paste.mod.gg/, save, and copy the link into chat for others to see your shared code!
zoon_
zoon_OP2mo ago
GitHub
TicTacToe/TicTacToe at master · ZoonAttack/TicTacToe
Contribute to ZoonAttack/TicTacToe development by creating an account on GitHub.
zoon_
zoon_OP2mo ago
My main issue is that, from what I've observed, the algorithm is correctly checking the states, which is typical of depth-first search (DFS). However, the major problem is that it continues to place an "O" on the buttons randomly, even when it should recognize that placing an "O" on a certain button would lead to a winning state. If that is the case, it should only place one "O" on that button and then allow me to take my turn by clicking on any other button. If you look closely, you'll see that it is just placing "O"s all over the board. "Once that winning path is found. it will recursively backtrack up the call stack. At the top of the call stack it will turn THAT next possible move which allowed the A.I to reach that winning state." i want THAT to happen.. i think my problem is with managing the backtracking it should backtrack to the very first step without making any change to the actual game.board once it backtracks to the very first step that led it to the winning state.. it performs the change to the real board instead of the copy board
zoon_
zoon_OP2mo ago
No description
Omnissiah
Omnissiah2mo ago
okay did you not debug this? step by step? also i would reorganize code a little extract a clear sequence of methods so that the solving logic is easier to follow and it's clear what the steps are doing for example:
public static bool DFS(char[,] currentBoard, bool isComputerTurn)
{
if (checkState(currentBoard, 'X')) return false; //Human wins
if (checkState(currentBoard, 'O')) { return true; } //Computer wins
if (isDraw()){ return false; }
public static bool DFS(char[,] currentBoard, bool isComputerTurn)
{
if (checkState(currentBoard, 'X')) return false; //Human wins
if (checkState(currentBoard, 'O')) { return true; } //Computer wins
if (isDraw()){ return false; }
this is the part that checks if an end condition is met, so i would move that stuff in an isolated method then you are searching for the first empty cell i would put that in an isolated method and so on, until everything is clear and you can debug this
zoon_
zoon_OP2mo ago
I debugged it I traced every single little output it works fine and backtracks But it just assigns to the real board when it shouldn't It should only assign once it backtracked all the way
Omnissiah
Omnissiah2mo ago
i should try this to be sure but how many times do you think this is called Game.board[i, j] = 'O'; or should be called, maybe
zoon_
zoon_OP2mo ago
So once the dfs has found a path and the checkstate finally returned true when it was passed an 'O' it should backtrack all the way without making changes again to the path. And at the very first step it took to reach that path it should assign it to game.board And send the row and col for that position of the board to update button so I can display the O on the ui I think my problem is I'm not isolating the backtracking and it keeps backtracking and adjusting even if it found a win. And that during backtracking it keeps assigning to the actual board
Omnissiah
Omnissiah2mo ago
yeah and there are two issues - again i should try this before being 100% sure - about this so first would be: which cell should be written on the game board? answer i believe it should be the first found right? (or first in the stack) and second: what happens after
Game.board[i, j] = 'O';
Game.UpdateButtons(i, j);
return true;
Game.board[i, j] = 'O';
Game.UpdateButtons(i, j);
return true;
the return true?
zoon_
zoon_OP2mo ago
Yes first found right Umm it should return true so while it backtracks it keeps the state "true" That's what I thought of
Omnissiah
Omnissiah2mo ago
i would think so too, so what happens next
zoon_
zoon_OP2mo ago
It exits out of the current stack call and returns to the precious turn it took and Same thing should happen Oh wait wait This is what's supposed to happen While it's still returning to the very first step it took But what happens is.. I have this return true after applying the winning move to the game board so once it returns true in the game.cs I can use that information with smth else The return true under the game.board should be the last return of the stack call of that method Since I'm currently not using that in the game.cs I think I just have it to stop the algorithm or smth
Omnissiah
Omnissiah2mo ago
we can put it in this way the last call to DFS recursion is the one that results in a win condition from there it always goes in that if and returns true
zoon_
zoon_OP2mo ago
But as a said. It should be already the last move though its not The last call should be the one determining the win condition indeed. If it found then it should keep returning while doing nothing and applying the very first turn it took to the original board
Omnissiah
Omnissiah2mo ago
yes but there is not the "do nothing" part
zoon_
zoon_OP2mo ago
I think my problem is it enters the if statement where the game.board is Yeah Is that what I'm missing ?
Omnissiah
Omnissiah2mo ago
yes but i would say the complicated part is that in there it's being shuffled a bunch of things together so it's difficult to keep track of what is happening and error occours that's to me what mainly is missing, isolating stuff so that you could have an easily followable sequence of events because it will be more difficult to have errors also because at this point to solve this you cannot have just two return states (true/false) you have to have at least one more, which is "ending was met, do nothing until i get to the first move and write that to the game board" which is a kinda complicated state, not impossible but not the simplest i guess and also maybe there are even more conditions but maybe it's taken care of by isDraw although you are not using the return value of DFS from game.cs
zoon_
zoon_OP2mo ago
I will make a boolean that tells me that and return it if a winning condition is met So it stays true all over the backtracking I don't quite understand how that would make a difference Since the logic is just what's under the checkstate
Omnissiah
Omnissiah2mo ago
i think an enum would be more explicit currentPlays++/-- is a logic currentBoard[i, j] = '\0'; is a logic too if (isComputerTurn && result) is a logic obv. and this for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) (currentBoard[i,j] == '\0') is a logic
zoon_
zoon_OP2mo ago
Yeah Okay I'll try it once possible and tell ya
Omnissiah
Omnissiah2mo ago
which would should roughly translate in - exit if ending condition is met (winning/losing, draw, no more cells left) - find first playable cell - set turn number - simulate play (pc/human) - clear - update real board with winning move which would be the "main" loop
zoon_
zoon_OP2mo ago
Wdym main loop Yeaah I think what I'm missing is the exit if win state is found So.. what do you exactly recommend me to do ?
Omnissiah
Omnissiah2mo ago
main loop as in algorithm loop, or like solution-finding loop if you already have some stuff going on and apparently the modification you need to make this work is relatively small, i would try that first eventually reorder code after
zoon_
zoon_OP2mo ago
What is "that" :d sorry got a bit confused Make an enum or boolean that tells me "ending was met" ? Is the point of that boolean to make dfs backtrack and reach the very first step?
Omnissiah
Omnissiah2mo ago
yes yes, to tell that the move was valid i guess you could see it in this way the first move is the move that will eventually be done the rest of the moves are a simulation to prove that the move is worthy
zoon_
zoon_OP2mo ago
yeah thats right can i just make an enum with the states COMPUTERWON, HUMANWON, DRAW, VALIDMOVE or something hey if youre awake could you check my code now ? i did some changes i think the logic seems promising now it doesnt put Os all over the place but it gives up in the middle 💀
zoon_
zoon_OP2mo ago
No description
zoon_
zoon_OP2mo ago
it reached a winning state
zoon_
zoon_OP2mo ago
No description
zoon_
zoon_OP2mo ago
but the first move it made was supposed to be the one ontop top middle
zoon_
zoon_OP2mo ago
it played in the middle.. you can see the "first move" variable being (1,1)
No description
zoon_
zoon_OP2mo ago
there is a problem it works well and but it loses track of the actual first move it made.. the firstMove tuple values change when they shouldnt since the algorithm did not backtrack to the very first move yet and theres something else.. firstMove tuple sometimes is null after a set of moves are made.. it reaches null for some reason i managed to fix this problem now i have THIS problem I updated my github u can see the updated code there
Omnissiah
Omnissiah2mo ago
i still think you have to learn to debug better, how many cycles will this algorithm make, like few tens?
zoon_
zoon_OP2mo ago
i fixed the code u can check the latest modified code now it works way better than i expected i still need to handle some end-game cases but thats all in the game logic not the algorithms $solved #close
Omnissiah
Omnissiah2mo ago
you could int.Parse also the remaining Convert.ToInt32(button.Tag.ToString()); and instead of Tuple<int,int> you can use like (int Column, int Row) it would be nice to have at least names for various strings like
const char Player1Symbol = 'O';
const char Player2Symbol = 'X';
const char Player1Symbol = 'O';
const char Player2Symbol = 'X';
better tactic would be to not use ui stuff in the algorithm at all
zoon_
zoon_OP2mo ago
yeah youre right trying to make it fancy 😂
Want results from more Discord servers?
Add your server