Hi everyone!
I’d like to suggest a new test case for the state-of-tic-tac-toe exercise.
Problem
There’s currently no test that captures the following invalid situation:
Player X has won the game,
but both players have made the same number of moves.
Since X always starts, this situation is impossible and should be treated as an invalid board.
{
"uuid": "to be generated",
"description": "Invalid board: X wins but X and O have the same number of moves",
"property": "gamestate",
"input": {
"board": [
"XXX",
"XOO",
"OO "
]
},
"expected": {
"error": "Impossible board: wrong turn order"
}
}
I’d love to hear what others think about this case. Is it something that makes sense to include in the tests?
That is slightly different, in that two players have won. We have three such canonical tests.
This thread is about where one player won, but then the other player played an additional (non-winning) move. The newly suggested “Impossible board” test case has X winning with 4 moves, but with O also having 4 moves, even though the game should have ended after 7 moves. We could also add a “Impossible board” test with O winning, but with X having made one more move than O, even though the game should have ended after an even number of moves (6 or 8).
Two players cannot win. The second player’s winning move is invalid because they played once the game should have already ended. Do we need separate tests when the invalid/additional move is a win vs non-win?
I’m not the original poster, but my own solutions would fail the new test(s). I checked for two players having won, instead of checking for an even number of moves with X having won, or an odd number of moves with O having won.
If we do add the test(s), I think the error message might need to be "Impossible board: game should have ended after the game was won"
Hi, sorry for the delay.
I think there’s a difference between:
A) continuing after the game was already won
B) a winning board where the move count doesn’t match the winner.
In this test, X wins but both players made 4 moves. That can’t happen, since X should have one more move than O. So the state is invalid, even if the board ends right at the win.
It’s not about extra moves after a win, but about reaching a winning state that’s logically impossible.
Still, I understand it might overlap conceptually with “O started” or similar, but I think the test is useful it breaks many solutions that don’t fully validate move counts.
Exactly!
They catch cases where the logic only checks for two winners, but not whether the move count actually fits with who won. It forces a more precise validation of the rules.
“O” never start so this part shouldn’t be a concern there.
I think I can see the slight difference now, in my solution I did the proper check so it would passes these cases regardless so I wasn’t sure what’s the difference at first.
{
"uuid": "4801cda2-f5b7-4c36-8317-3cdd167ac22c",
"description": "Invalid board: players kept playing after a win",
"property": "gamestate",
"input": {
"board": [
"XXX",
"OOO",
"XOX"
]
},
"expected": {
"error": "Impossible board: game should have ended after the game was won"
}
}
In the above final test, O should wins here and X final move is invalid, because if X won then the board would have been invalid since the 8th move (or earlier) from O similar to OP scenario. But since this board end up having 2 winners, you can just check that as a condition and pass because that will always be a wrong board.
That’s a different board actually
Try your code with this test
{
"uuid": "to be generated",
"description": "Invalid board: X wins but X and O have the same number of moves",
"property": "gamestate",
"input": {
"board": [
"XXX",
"XOO",
"OO "
]
},
"expected": {
"error": "Impossible board: wrong turn order"
}
}
I think you misunderstood, that one in my post is the final test in the problem spec (you can see the uuid there). I cited it to highlight how both invalid board tests can be bypassed by checking 2 winners, basically agreeing with your original post that it is not enough and support adding your test.
{
"uuid": "to be generated",
"description": "Invalid board: O wins but X has more moves than O",
"property": "gamestate",
"input": {
"board": [
"X X",
"OOO",
"X X"
]
},
"expected": {
"error": "Impossible board: game should have ended after the game was won"
}
}
If @Caminaur is not, I’d be willing to work on it, but I’d need some documentation on how to do this.
However, I would argue that the situation that Caminaur showed can also be interpreted as O playing after X already won, which is the same as the “Impossible board: game should have ended after the game was won”.
Quick update: PR #2667 has been merged into problem-specifications.
I’d be happy to try propagating this to the Python track — running configlet sync and the test generator locally against the updated canonical data, then opening a PR with the regenerated test file. Fair warning that I haven’t done this before, so it’d be a first attempt and I’d appreciate a careful review, but I’m happy to give it a go if that’s useful rather than waiting on a maintainer’s time. Also totally fine if someone would rather just handle the sync directly — just let me know either way.
Thanks for the offer, but i prefer to do the syncs on the Python track myself on a schedule.
It’s much easier to group changes than do them one-by-one as they come in.
With that said, the Julia track, as well as R and Fortran (and I think maybe bash??) also have Python-based test generators like the Python track. You might want to ask if the maintainers of those tracks would mind if you synced the exercise (if their track implements it) for them. I suspect that Julia and R in particular would be delighted.
awk, bash, jq all have more or less the same Python/Jinja generator. Go has a custom Go generator. I also co maintain sqlite but there’s no generator there yet. Feel free to PR this change to those tracks. If you’re not confident about the changes, it would be best to take them one at a time.
I’d be happy for you to PR these changes to the Julia track. @BethanyG wrote the test generator, so it should be pretty similar to the Python one.
We also have Jinja-based generators for R and Fortran, but that exercise is not yet implemented on those tracks. They’re on my to-do list, but so are about a million other things.