|
| 1 | +import "../../lib/github.com/diku-dk/containers/unionfind" |
| 2 | + |
| 3 | +-- Start with some utility definitions for handling directions and positions. |
| 4 | + |
| 5 | +-- | A cardinal direction, with `#c` being current location ("centre"). |
| 6 | +type dir = #n | #w | #e | #s |
| 7 | + |
| 8 | +-- | Position in a grid. |
| 9 | +type pos = (i64, i64) |
| 10 | + |
| 11 | +-- | Move along direction. |
| 12 | +def move (d: dir) ((i, j): pos) = |
| 13 | + match d |
| 14 | + case #n -> (i - 1, j) |
| 15 | + case #w -> (i, j - 1) |
| 16 | + case #e -> (i, j + 1) |
| 17 | + case #s -> (i + 1, j) |
| 18 | + |
| 19 | +-- | Turn a position into a flat index, given a grid width. |
| 20 | +def flat_pos (w: i64) ((x, y): pos) : i64 = x * w + y |
| 21 | + |
| 22 | +-- | Is this position in bounds in some grid? |
| 23 | +def in_bounds [h] [w] 'a (_: [h][w]a) ((i, j): pos) = |
| 24 | + i >= 0 && i < h && j >= 0 && j < w |
| 25 | + |
| 26 | +-- | Get element at position in grid. |
| 27 | +def get 'a ((i, j): pos) (g: [][]a) = |
| 28 | + g[i, j] |
| 29 | + |
| 30 | +-- | Could be improved. This is unlikely to produce something very legible. |
| 31 | +def colourise_regions [h] [w] (labels: [h][w]i64) : [h][w]u32 = |
| 32 | + let f l = u32.i64 l |
| 33 | + in map (map f) labels |
| 34 | + |
| 35 | +def mk_nasty (w: i64) : [w][w]u32 = |
| 36 | + tabulate_2d w w \i j -> |
| 37 | + if (j % 2 == 0) || (i == 0 && (j / 2) % 2 == 0) |
| 38 | + || (i == w - 1 && (j / 2) % 2 == 1) |
| 39 | + then 0 |
| 40 | + else 0xffffff |
| 41 | + |
| 42 | +def mk_equivalences [h] [w] (img: [h][w]u32) : ?[n].[n](i64, i64) = |
| 43 | + tabulate_2d h |
| 44 | + w |
| 45 | + (\i j -> |
| 46 | + let p = (i, j) |
| 47 | + let flat_p = flat_pos w p |
| 48 | + in map (\n -> |
| 49 | + let p' = move n p |
| 50 | + in if in_bounds img p' && get p img == get p' img |
| 51 | + then (flat_p, flat_pos w p') |
| 52 | + else (flat_p, -1)) |
| 53 | + [#n, #w, #e, #s]) |
| 54 | + |> flatten_3d |
| 55 | + |> filter ((>= 0) <-< (.1)) |
| 56 | + |
| 57 | +module u = unionfind |
| 58 | + |
| 59 | +def region_label_unionfind [h] [w] (img: [h][w]u32) = |
| 60 | + let uf = u.create (h * w) |
| 61 | + let eqs = |
| 62 | + copy (mk_equivalences img |
| 63 | + |> map (\(i, j) -> |
| 64 | + ( u.from_i64 uf i |
| 65 | + , u.from_i64 uf j |
| 66 | + ))) |
| 67 | + let uf = u.union uf eqs |
| 68 | + let labels = u.find' uf (u.handles uf) |
| 69 | + in unflatten (map (u.to_i64 uf) labels :> [h * w]i64) |
| 70 | + |
| 71 | +-- > :img (colourise_regions (region_label_unionfind ($loadimg "regions-hard.png"))) |
| 72 | + |
| 73 | +-- > :img mk_nasty 128 |
| 74 | + |
| 75 | +-- > :img colourise_regions (region_label_unionfind (mk_nasty 128)) |
0 commit comments