Skip to content

Add exercise: state-of-tic-tac-toe #1991

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 9, 2022
Merged

Add exercise: state-of-tic-tac-toe #1991

merged 9 commits into from
Apr 9, 2022

Conversation

SaschaMann
Copy link
Contributor

This is based on the research exercise julia-1-a

Extensions of this might be possible in the future, hence tic-tac-toe may not be ideal as a slug, so I'm going with state-of-tic-tac-toe.

@SaschaMann
Copy link
Contributor Author

@ErikSchierboom the order of this is all wrong but I think you have a script to fix that, guessing based on #1960? (perhaps that should be part of /format, too)

@SaschaMann SaschaMann marked this pull request as ready for review March 25, 2022 18:32
@SaschaMann
Copy link
Contributor Author

SaschaMann commented Mar 25, 2022

These arrays should be multi-line as in #1968.

@SaschaMann
Copy link
Contributor Author

SaschaMann commented Mar 25, 2022

Some example solutions in Julia
function gamestate(bs)
    # Parse to Matrix
    b = hcat(split.(split(bs, "\n"), "")...)

    # Invalid boards
    nₒ = count(x -> x == "O", b)
    nₓ = count(x -> x == "X", b)
    # Not taking turns in order 
    if nₒ > nₓ || abs(nₒ - nₓ) > 1
        throw(DomainError(b, "Invalid board: did not take turns in order"))
    end

    wins = 0

    for i in 1:3
        # Row victory
        wins += b[i, 1] != " " && (b[i, 1] == b[i, 2] == b[i, 3]) ? 1 : 0
        
        # Col victory
        wins += b[1, i] != " " && (b[1, i] == b[2, i] == b[3, i]) ? 1 : 0
    end

    # Diagonal victories
    wins += b[1, 1] != " " && (b[1, 1] == b[2, 2] == b[3, 3]) ? 1 : 0
    wins += b[1, 3] != " " && (b[1, 3] == b[2, 2] == b[3, 1]) ? 1 : 0

    if wins == 1
        return :win
    elseif wins > 1
        throw(DomainError(b, "Invalid board: more than one win"))
    end

    # Draw
    " "  b && return :draw

    :ongoing
end
using LinearAlgebra

function gamestate(bs)
    # Parse to Int Matrix
    b_str = hcat(split.(split(bs, "\n"), "")...)
    replace!(b_str, "X" => "1")
    replace!(b_str, " " => "0")
    replace!(b_str, "O" => "-1")
    b = parse.(Int, b_str)

    # It's a win if any of the rows, columns, or diagonals add up to ±3
    wins = count(sum(row) in (-3, 3) for row in eachrow(b)) + count(sum(col) in (-3, 3) for col in eachcol(b)) + (sum(diag(b)) in (-3, 3) ? 1 : 0) + (sum(diag(rotr90(b))) in (-3, 3) ? 1 : 0)
    if wins == 1
        :win
    elseif wins > 1
        error("Too many wins!")
    elseif sum(b) == 1 && !any(x == 0 for x in b)
        :draw
    elseif sum(b)  (0, 1)
        error("Must take turns in order")
    else
        :ongoing
    end
end

@glennj
Copy link
Contributor

glennj commented Mar 25, 2022

Do we want a test with an empty board? Would that state be ongoing?

Do we want to group the cases into scenarios?

@SaschaMann
Copy link
Contributor Author

Do we want a test with an empty board? Would that state be ongoing?

I'm happy to add it as ongoing or leave it as undefined. I don't think it really makes a difference for any solutions.

Do we want to group the cases into scenarios?

What grouping do you have in mind? Groups based on game state?

@glennj
Copy link
Contributor

glennj commented Mar 25, 2022

Yes, that's what I was thinking.

SaschaMann and others added 5 commits April 6, 2022 10:07
This is based on the research exercise julia-1-a

Extensions of this might be possible in the future, hence tic-tac-toe may not be ideal as a slug, so I'm going with state-of-tic-tac-toe
@SaschaMann
Copy link
Contributor Author

SaschaMann commented Apr 6, 2022

@glennj I've grouped them based on game state now.

@petertseng Could you please confirm that I've configured the array formatter correctly?

@SaschaMann
Copy link
Contributor Author

@exercism/reviewers

Copy link
Member

@petertseng petertseng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I confirm that this is the correct configuration for the array formatter.

The reason I haven't Approved, in the GitHub sense of the word, is just that I haven't reviewed the other contents, but you don't need to wait for me to do that if there are others who are doing that. I just wanted to quickly get a confirmation to you that that configuration was correct.

@SaschaMann
Copy link
Contributor Author

That's a really good point, I missed that you could win "twice" with one move. Fixed in de82efb, I moved them into wins because I think they could be interesting edge cases.

Copy link
Member

@petertseng petertseng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while I'm making Suggestions (in the GitHub sense of the word) to remove trailing whitespace, they're not required. If we really want to avoid that we should probably have something that automatically checks for it.

Co-authored-by: Peter Tseng <petertseng@users.noreply.github.com>
@SaschaMann
Copy link
Contributor Author

If we really want to avoid that we should probably have something that automatically checks for it.

I thought prettier did it but perhaps it's ignored in code blocks or something 🤷

"cases": [
{
"uuid": "b42ed767-194c-4364-b36e-efbfb3de8788",
"description": "Draw",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the descriptions be unique? Is this being used for test functionality (function names, etc?) when generated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not part of the spec and therefore would be an issue the generators would have to fix.

That said, the descriptions don't describe why the test exists all that well, so if someone wants to improve those, a follow-up PR would be appreciated. The description is mutable and I'd rather get this merged and improved later on according to the usual optimistic merging strategy.

Comment on lines 24 to 26
- The players took turns out of order (remember that `X` starts).
- The game was played after it already ended.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we test for out of order? Are there tests for out of order? I only noticed snapshots and any snapshot that has equal or one less "O" than "X" can not indicate play order on its own. I also do not see an example in "Examples" that shows what this might look like.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only noticed snapshots and any snapshot that has equal or one less "O" than "X" can not indicate play order on its own.

A board that has more Os than Xs is impossible to reach when the right turn order is followed. We only care if the snapshot is a valid board, i.e. reachable through legal turns.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So nothing to clarify about this in the description? Line 24 mentions it, and I looked through and did not notice an example of an "out of order" state. But does this matter? Are we testing for this? (Yes, a board that has more than 2 less "O"'s than "X" would an invalid state, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two tests for it towards the end of the file. I'll add an example.

Copy link
Contributor Author

@SaschaMann SaschaMann Apr 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kotp does 2f1e126 clear things up?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, that works.

@SaschaMann SaschaMann requested a review from kotp April 9, 2022 07:23
@SaschaMann
Copy link
Contributor Author

Thanks for the reviews :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants