Skip to content
This repository was archived by the owner on May 30, 2023. It is now read-only.

Commit f74acae

Browse files
Add go-counting exercise (#126)
1 parent 83a3b17 commit f74acae

File tree

8 files changed

+197
-0
lines changed

8 files changed

+197
-0
lines changed

config.json

+10
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,16 @@
585585
],
586586
"difficulty": 2
587587
},
588+
{
589+
"slug": "go-counting",
590+
"name": "Go Counting",
591+
"uuid": "f3fac096-43b6-4106-a111-780991d64c4f",
592+
"practices": [],
593+
"prerequisites": [
594+
"strings"
595+
],
596+
"difficulty": 9
597+
},
588598
{
589599
"slug": "nth-prime",
590600
"name": "Nth Prime",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Instructions
2+
3+
Count the scored points on a Go board.
4+
5+
In the game of go (also known as baduk, igo, cờ vây and wéiqí) points are gained by completely encircling empty intersections with your stones.
6+
The encircled intersections of a player are known as its territory.
7+
8+
Write a function that determines the territory of each player.
9+
You may assume that any stones that have been stranded in enemy territory have already been taken off the board.
10+
11+
Write a function that determines the territory which includes a specified coordinate.
12+
13+
Multiple empty intersections may be encircled at once and for encircling only horizontal and vertical neighbors count.
14+
In the following diagram the stones which matter are marked "O" and the stones that don't are marked "I" (ignored).
15+
Empty spaces represent empty intersections.
16+
17+
```text
18+
+----+
19+
|IOOI|
20+
|O O|
21+
|O OI|
22+
|IOI |
23+
+----+
24+
```
25+
26+
To be more precise an empty intersection is part of a player's territory if all of its neighbors are either stones of that player or empty intersections that are part of that player's territory.
27+
28+
For more information see [wikipedia][go-wikipedia] or [Sensei's Library][go-sensei].
29+
30+
[go-wikipedia]: https://en.wikipedia.org/wiki/Go_%28game%29
31+
[go-sensei]: https://senseis.xmp.net/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"authors": [
3+
"ErikSchierboom"
4+
],
5+
"files": {
6+
"solution": [
7+
"src/go_counting.cljs"
8+
],
9+
"test": [
10+
"test/go_counting_test.cljs"
11+
],
12+
"example": [
13+
".meta/src/example.cljs"
14+
]
15+
},
16+
"blurb": "Count the scored points on a Go board."
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
(ns go-counting)
2+
3+
(defn grid->graph [xs]
4+
(->> (for [x (-> xs count range), y (-> xs first count range)]
5+
(case (get-in xs [x y])
6+
\W [[y x] :white]
7+
\B [[y x] :black]
8+
\space [[y x] :free]))
9+
(into {})))
10+
11+
(defn neighbors [pred stones [x y]]
12+
(->> [[0 1] [0 -1] [1 0] [-1 0]]
13+
(map (fn [[j k]] [(+ x j) (+ y k)]))
14+
(filter (comp pred stones))))
15+
16+
(defn territory-of [stones [x y]]
17+
(if (= :free (stones [x y]))
18+
(letfn [(f [[seen frontier]]
19+
(let [nseen (reduce conj seen frontier)]
20+
[nseen (->> frontier
21+
(mapcat #(neighbors #{:free} stones %))
22+
(filter (complement nseen)))]))]
23+
(->> [#{} [[x y]]]
24+
(iterate f)
25+
(drop-while (comp seq second))
26+
(ffirst)))
27+
#{}))
28+
29+
(defn territory-owner [stones territory]
30+
(->> territory
31+
(mapcat (partial neighbors #{:black :white} stones))
32+
(map stones)
33+
(#(cond (empty? %) nil
34+
(every? (partial = :black) %) :black
35+
(every? (partial = :white) %) :white
36+
:else nil))))
37+
38+
(defn territory [grid [x y]]
39+
(let [stones (grid->graph grid)
40+
territory (territory-of stones [x y])]
41+
(if (nil? (stones [x y]))
42+
(throw (new js/Error "Invalid coordinate!"))
43+
{:stones territory :owner (territory-owner stones territory)})))
44+
45+
(defn territories [grid]
46+
(let [territories (->> grid grid->graph keys (map (partial territory grid)))
47+
territory-for #(->> territories (filter (comp % :owner)) (map :stones) (reduce concat) set)]
48+
{:black-territory (territory-for (partial = :black))
49+
:white-territory (territory-for (partial = :white))
50+
:null-territory (territory-for nil?)}))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# This is an auto-generated file. Regular comments will be removed when this
2+
# file is regenerated. Regenerating will not touch any manually added keys,
3+
# so comments can be added in a "comment" key.
4+
5+
[94d0c01a-17d0-424c-aab5-2736d0da3939]
6+
description = "Black corner territory on 5x5 board"
7+
8+
[b33bec54-356a-485c-9c71-1142a9403213]
9+
description = "White center territory on 5x5 board"
10+
11+
[def7d124-422e-44ae-90e5-ceda09399bda]
12+
description = "Open corner territory on 5x5 board"
13+
14+
[57d79036-2618-47f4-aa87-56c06d362e3d]
15+
description = "A stone and not a territory on 5x5 board"
16+
17+
[0c84f852-e032-4762-9010-99f6a001da96]
18+
description = "Invalid because X is too low for 5x5 board"
19+
20+
[6f867945-9b2c-4bdd-b23e-b55fe2069a68]
21+
description = "Invalid because X is too high for 5x5 board"
22+
23+
[d67aaffd-fdf1-4e7f-b9e9-79897402b64a]
24+
description = "Invalid because Y is too low for 5x5 board"
25+
26+
[14f23c25-799e-4371-b3e5-777a2c30357a]
27+
description = "Invalid because Y is too high for 5x5 board"
28+
29+
[37fb04b5-98c1-4b96-8c16-af2d13624afd]
30+
description = "One territory is the whole board"
31+
32+
[9a1c59b7-234b-495a-8d60-638489f0fc0a]
33+
description = "Two territory rectangular board"
34+
35+
[d1645953-1cd5-4221-af6f-8164f96249e1]
36+
description = "Two region rectangular board"
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{:deps
2+
{org.clojure/clojure {:mvn/version "1.10.1"}
3+
org.clojure/clojurescript {:mvn/version "1.10.773"}}
4+
5+
:aliases
6+
{:test
7+
{:extra-paths ["test"]
8+
:extra-deps
9+
{olical/cljs-test-runner {:mvn/version "3.8.0"}}
10+
:main-opts ["-m" "cljs-test-runner.main"]}}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
(ns go-counting)
2+
3+
(defn territory [grid [x y]])
4+
5+
(defn territories [grid])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
(ns go-counting-test
2+
(:require [clojure.test :refer [deftest is]]
3+
[go-counting :as g]))
4+
5+
(def example
6+
[" B "
7+
" B B "
8+
"B W B"
9+
" W W "
10+
" W "])
11+
12+
(deftest territory
13+
(is (= (g/territory example [0 1])
14+
{:stones #{[0 0] [0 1] [1 0]} :owner :black}))
15+
(is (= (g/territory example [2 3])
16+
{:stones #{[2 3]} :owner :white}))
17+
(is (= (g/territory example [1 4])
18+
{:stones #{[0 3] [0 4] [1 4]} :owner nil}))
19+
(is (= (g/territory example [1 1])
20+
{:stones #{} :owner nil}))
21+
(is (thrown? js/Error (g/territory example [-1 1])))
22+
(is (thrown? js/Error (g/territory example [5 1])))
23+
(is (thrown? js/Error (g/territory example [1 -1])))
24+
(is (thrown? js/Error (g/territory example [1 5]))))
25+
26+
(deftest territories
27+
(is (= (g/territories [" "])
28+
{:black-territory #{}
29+
:white-territory #{}
30+
:null-territory #{[0 0]}}))
31+
(is (= (g/territories [" BW " " BW "])
32+
{:black-territory #{[0 0] [0 1]}
33+
:white-territory #{[3 0] [3 1]}
34+
:null-territory #{}}))
35+
(is (= (g/territories [" B "])
36+
{:black-territory #{[0 0] [2 0]}
37+
:white-territory #{}
38+
:null-territory #{}})))

0 commit comments

Comments
 (0)