Skip to content

Commit

Permalink
Add connect practice exercise (#498)
Browse files Browse the repository at this point in the history
* Add connect exercise

* Fix difficulty for connect
  • Loading branch information
ryanplusplus authored Aug 27, 2024
1 parent 3855e4d commit 0544c0c
Show file tree
Hide file tree
Showing 8 changed files with 336 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -1327,6 +1327,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 6
},
{
"slug": "connect",
"name": "Connect",
"uuid": "650a57ad-9a43-4338-a1ec-55a7c842d842",
"practices": [],
"prerequisites": [],
"difficulty": 5
}
]
},
Expand Down
5 changes: 5 additions & 0 deletions exercises/practice/connect/.busted
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
return {
default = {
ROOT = { '.' }
}
}
27 changes: 27 additions & 0 deletions exercises/practice/connect/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions exercises/practice/connect/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"authors": [
"ryanplusplus"
],
"files": {
"solution": [
"connect.lua"
],
"test": [
"connect_spec.lua"
],
"example": [
".meta/example.lua"
]
},
"blurb": "Compute the result for a game of Hex / Polygon."
}
124 changes: 124 additions & 0 deletions exercises/practice/connect/.meta/example.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
local function Board(board)
local function at(x, y)
return board[y + 1]:sub(x + 1, x + 1)
end

local function put(x, y, v)
board[y + 1] = board[y + 1]:sub(1, x) .. v .. board[y + 1]:sub(x + 2)
end

local function on_board(x, y)
return x >= 0 and x <= #board[1] - 1 and y >= 0 and y <= #board - 1
end

local function max_x()
return #board[1] - 1
end

local function max_y()
return #board - 1
end

local function each_position(f)
for x = 0, max_x() do
for y = 0, max_y() do
f(x, y)
end
end
end

local function each_neighbor(x, y, f)
local neighbors = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 }, { -1, 1 }, { 1, -1 } }
for _, neighbor in ipairs(neighbors) do
local dx, dy = neighbor[1], neighbor[2]
local xx, yy = x + dx, y + dy
if on_board(xx, yy) then
f(xx, yy)
end
end
end

local function mark_xs_at_left()
for y = 0, max_y() do
if at(0, y) == 'X' then
put(0, y, 'x')
end
end
end

local function mark_os_at_top()
for x = 0, max_x() do
if at(x, 0) == 'O' then
put(x, 0, 'o')
end
end
end

local function traverse(player)
local marked = false

each_position(function(x, y)
if at(x, y) == player then
each_neighbor(x, y, function(nx, ny)
if at(nx, ny) == player:lower() then
put(x, y, player:lower())
marked = true
end
end)
end
end)

return marked
end

local function mark()
mark_xs_at_left()
while traverse('X') do
end

mark_os_at_top()
while traverse('O') do
end
end

local function x_at_right()
for i = 0, max_y() do
if at(max_x(), i) == 'x' then
return true
end
end
return false
end

local function o_at_bottom()
for i = 0, max_x() do
if at(i, max_y()) == 'o' then
return true
end
end
end

for i = 1, #board do
board[i] = board[i]:gsub(' ', '')
end

mark()

return {
winner = function()
if x_at_right() then
return 'X'
elseif o_at_bottom() then
return 'O'
else
return ''
end
end
}
end

return {
winner = function(board)
return Board(board).winner()
end
}
40 changes: 40 additions & 0 deletions exercises/practice/connect/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -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"
5 changes: 5 additions & 0 deletions exercises/practice/connect/connect.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
return {
winner = function(board)

end
}
110 changes: 110 additions & 0 deletions exercises/practice/connect/connect_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
local connect = require('connect')

-- LuaFormatter off
describe('connect', function()
it('an empty board has no winner', function()
local board = {
'. . . . .',
' . . . . .',
' . . . . .',
' . . . . .',
' . . . . .'
}
assert.are.same('', connect.winner(board))
end)

it('X can win on a 1x1 board', function()
local board = {
'X'
}
assert.are.same('X', connect.winner(board))
end)

it('O can win on a 1x1 board', function()
local board = {
'O'
}
assert.are.same('O', connect.winner(board))
end)

it('only edges does not make a winner', function()
local board = {
'O O O X',
' X . . X',
' X . . X',
' X O O O'
}
assert.are.same('', connect.winner(board))
end)

it('illegal diagonal does not make a winner', function()
local board = {
'X O . .',
' O X X X',
' O X O .',
' . O X .',
' X X O O'
}
assert.are.same('', connect.winner(board))
end)

it('nobody wins crossing adjacent angles', function()
local board = {
'X . . .',
' . X O .',
' O . X O',
' . O . X',
' . . O .'
}
assert.are.same('', connect.winner(board))
end)

it('X wins crossing from left to right', function()
local board = {
'. O . .',
' O X X X',
' O X O .',
' X X O X',
' . O X .'
}
assert.are.same('X', connect.winner(board))
end)

it('O wins crossing from top to bottom', function()
local board = {
'. O . .',
' O X X X',
' O O O .',
' X X O X',
' . O X .'
}
assert.are.same('O', connect.winner(board))
end)

it('X wins using a convoluted path', function()
local board = {
'. X X . .',
' X . X . X',
' . X . X .',
' . X X . .',
' O O O O O'
}
assert.are.same('X', connect.winner(board))
end)

it('X wins using a spiral path', function()
local 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'
}
assert.are.same('X', connect.winner(board))
end)
end)
-- LuaFormatter on

0 comments on commit 0544c0c

Please sign in to comment.