diff --git a/config.json b/config.json index cf8b2ffe..3dd79d19 100644 --- a/config.json +++ b/config.json @@ -889,7 +889,15 @@ "practices": [], "prerequisites": [], "difficulty": 1 - } + }, + { + "slug": "connect", + "name": "Connect", + "uuid": "6cd9edb0-35ba-4f32-b51b-a734d98e3a88", + "practices": [], + "prerequisites": [], + "difficulty": 5 + } ] }, "concepts": [ diff --git a/exercises/practice/connect/.docs/instructions.md b/exercises/practice/connect/.docs/instructions.md new file mode 100644 index 00000000..7f34bfa8 --- /dev/null +++ b/exercises/practice/connect/.docs/instructions.md @@ -0,0 +1,27 @@ +# Instructions + +Compute the result for a game of Hex / Polygon. + +The abstract boardgame known as [Hex][hex] / Polygon / CON-TAC-TIX is quite simple in rules, though complex in practice. +Two players place stones on a parallelogram with hexagonal fields. +The player to connect his/her stones to the opposite side first wins. +The four sides of the parallelogram are divided between the two players (i.e. one player gets assigned a side and the side directly opposite it and the other player gets assigned the two other sides). + +Your goal is to build a program that given a simple representation of a board computes the winner (or lack thereof). +Note that all games need not be "fair". +(For example, players may have mismatched piece counts or the game's board might have a different width and height.) + +The boards look like this: + +```text +. O . X . + . X X O . + O O O X . + . X O X O + X O O O X +``` + +"Player `O`" plays from top to bottom, "Player `X`" plays from left to right. +In the above example `O` has made a connection from left to right but nobody has won since `O` didn't connect top and bottom. + +[hex]: https://en.wikipedia.org/wiki/Hex_%28board_game%29 diff --git a/exercises/practice/connect/.meta/config.json b/exercises/practice/connect/.meta/config.json new file mode 100644 index 00000000..8381b281 --- /dev/null +++ b/exercises/practice/connect/.meta/config.json @@ -0,0 +1,15 @@ +{ + "authors": [], + "files": { + "solution": [ + "connect.jl" + ], + "test": [ + "runtests.jl" + ], + "example": [ + ".meta/example.jl" + ] + }, + "blurb": "Compute the result for a game of Hex / Polygon." +} diff --git a/exercises/practice/connect/.meta/example.jl b/exercises/practice/connect/.meta/example.jl new file mode 100644 index 00000000..d94c9470 --- /dev/null +++ b/exercises/practice/connect/.meta/example.jl @@ -0,0 +1,35 @@ +#= +The approach below is essentially an implementation of bfs/floodfill. + - connector does the bfs, using the six possible steps and tracking which have been seen, returns true/false + depending on if there is a path is found connecting two edges of the board. + - wins finds starting points for connector, and returns true if the provided points results in a win. + - connect processes the board to separate points into coordinates for wins to filter through and then returns the winner, + if there is one. The coordinates have been transposed for O, so that wins and connector can work with X or O equally. +=# +function connector(unseen, points, dim, nextpoints=Set()) + for point in points, step in ((1,0),(-1,0),(0,1),(0,-1),(1,-1),(-1,1)) + nextpoint = point .+ step + if nextpoint ∈ unseen + first(nextpoint) == dim && return true + push!(nextpoints, nextpoint) + delete!(unseen, nextpoint) + end + end + !isempty(nextpoints) && connector(unseen, nextpoints, dim) +end + +function wins(points, dim) + for point in filter(isone ∘ first, points) + (isone(dim) || connector(setdiff(points, Set([point])), Set([point]), dim)) && return true + end + false +end + +function connect(board) + newboard, Xs, Os = hcat(split.(strip.(board), " ")...), Set(), Set() + for i in axes(newboard,1), j in axes(newboard,2) + newboard[i,j] == "X" && push!(Xs, (i,j)) + newboard[i,j] == "O" && push!(Os, (j,i)) + end + wins(Xs, first(size(newboard))) ? "X" : wins(Os, last(size(newboard))) ? "O" : "" +end diff --git a/exercises/practice/connect/.meta/tests.toml b/exercises/practice/connect/.meta/tests.toml new file mode 100644 index 00000000..6ada8773 --- /dev/null +++ b/exercises/practice/connect/.meta/tests.toml @@ -0,0 +1,40 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[6eff0df4-3e92-478d-9b54-d3e8b354db56] +description = "an empty board has no winner" + +[298b94c0-b46d-45d8-b34b-0fa2ea71f0a4] +description = "X can win on a 1x1 board" + +[763bbae0-cb8f-4f28-bc21-5be16a5722dc] +description = "O can win on a 1x1 board" + +[819fde60-9ae2-485e-a024-cbb8ea68751b] +description = "only edges does not make a winner" + +[2c56a0d5-9528-41e5-b92b-499dfe08506c] +description = "illegal diagonal does not make a winner" + +[41cce3ef-43ca-4963-970a-c05d39aa1cc1] +description = "nobody wins crossing adjacent angles" + +[cd61c143-92f6-4a8d-84d9-cb2b359e226b] +description = "X wins crossing from left to right" + +[73d1eda6-16ab-4460-9904-b5f5dd401d0b] +description = "O wins crossing from top to bottom" + +[c3a2a550-944a-4637-8b3f-1e1bf1340a3d] +description = "X wins using a convoluted path" + +[17e76fa8-f731-4db7-92ad-ed2a285d31f3] +description = "X wins using a spiral path" diff --git a/exercises/practice/connect/connect.jl b/exercises/practice/connect/connect.jl new file mode 100644 index 00000000..0a062396 --- /dev/null +++ b/exercises/practice/connect/connect.jl @@ -0,0 +1,3 @@ +function connect(board) + # Your code here +end \ No newline at end of file diff --git a/exercises/practice/connect/runtests.jl b/exercises/practice/connect/runtests.jl new file mode 100644 index 00000000..e96247b1 --- /dev/null +++ b/exercises/practice/connect/runtests.jl @@ -0,0 +1,115 @@ +using Test + +include("connect.jl") + +@testset "an empty board has no winner" begin + board = [ + ". . . . .", + " . . . . .", + " . . . . .", + " . . . . .", + " . . . . ." + ] + @test connect(board) == "" +end + +@testset "an empty 1x1 board has no winner" begin + board = [ + "." + ] + @test connect(board) == "" +end + +@testset "X can win on a 1x1 board" begin + board = [ + "X" + ] + @test connect(board) == "X" +end + +@testset "O can win on a 1x1 board" begin + board = [ + "O" + ] + @test connect(board) == "O" +end + +@testset "only edges does not make a winner" begin + board = [ + "O O O X", + " X . . X", + " X . . X", + " X O O O" + ] + @test connect(board) == "" +end + +@testset "illegal diagonal does not make a winner" begin + board = [ + "X O . .", + " O X X X", + " O X O .", + " . O X .", + " X X O O" + ] + @test connect(board) == "" +end + +@testset "nobody wins crossing adjacent angles" begin + board = [ + "X . . .", + " . X O .", + " O . X O", + " . O . X", + " . . O ." + ] + @test connect(board) == "" +end + +@testset "X wins crossing from left to right" begin + board = [ + ". O . .", + " O X X X", + " O X O .", + " X X O X", + " . O X ." + ] + @test connect(board) == "X" +end + +@testset "O wins crossing from top to bottom" begin + board = [ + ". O . .", + " O X X X", + " O O O .", + " X X O X", + " . O X ." + ] + @test connect(board) == "O" +end + +@testset "X wins using a convoluted path" begin + board = [ + ". X X . .", + " X . X . X", + " . X . X .", + " . X X . .", + " O O O O O" + ] + @test connect(board) == "X" +end + +@testset "X wins using a spiral path" begin + board = [ + "O X X X X X X X X", + " O X O O O O O O O", + " O X O X X X X X O", + " O X O X O O O X O", + " O X O X X X O X O", + " O X O O O X O X O", + " O X X X X X O X O", + " O O O O O O O X O", + " X X X X X X X X O" + ] + @test connect(board) == "X" +end