-
Notifications
You must be signed in to change notification settings - Fork 0
/
state.ml
72 lines (53 loc) · 2.23 KB
/
state.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
open Core
type t = {graph: Graph.t; pos: int; port: int; conn: int list}
[@@deriving yojson, fields]
let empty ~max_conn = {graph= Graph.empty ~max_conn; pos= 0; port= 0; conn= []}
let selected s = Option.map ~f:snd @@ Map.find s.graph.edges (s.pos, s.port)
let of_graph g = {graph= g; pos= 0; port= 0; conn= []}
let has_isolated s = Graph.n_components @@ graph s > 1
let has_conn s = not (List.is_empty @@ conn s)
let add_node s =
let nb, graph = Graph.add_node s.graph in
{s with graph; pos= nb}
module Operations = struct
let identity : t -> t = Fn.id
let next_port (f : t -> t) (s : t) : t =
f {s with port= (s.port + 1) mod s.graph.max_conn}
let prev_port (f : t -> t) (s : t) : t =
f {s with port= (if s.port = 0 then s.graph.max_conn - 1 else s.port - 1)}
let func (f : t -> t) (g : t -> t) (s : t) =
let graph' = graph @@ f s in
g {s with graph= (if Graph.n_components graph' > 1 then graph s else graph')}
let if_positions_equal (f : t -> t) (g : t -> t) (h : t -> t) (k : t -> t)
(l : t -> t) (s : t) : t =
l (if pos (f s) = pos (g s) then h s else k s)
let move (f : t -> t) (s : t) : t =
f {s with pos= Option.value_map (selected s) ~default:s.pos ~f:Fn.id}
let add (f : t -> t) (s : t) : t =
if has_conn s && not (has_isolated s) then f @@ add_node s else f s
let push (f : t -> t) (s : t) : t = f {s with conn= pos s :: conn s}
let pop (f : t -> t) (s : t) : t =
f
{ s with
conn=
( match (List.tl @@ conn s, conn s, has_isolated s) with
| rest, _, false ->
Option.value_map rest ~default:[] ~f:Fn.id
| _, [], true ->
failwith "pop: isolated node has no way to connect with neighbors"
| None, _, true ->
failwith "pop: impossible"
| Some rest, all, true ->
if List.exists rest ~f:(( <> ) (pos s)) then rest else all ) }
let connect (f : t -> t) (s : t) =
f
( match (selected s, List.hd @@ conn s) with
| Some _, _ | None, None ->
s
| None, Some nb ->
{s with graph= Graph.add_edge s.port s.graph s.pos nb} )
let last_found : Graph.t option ref = ref None
let save (s : t) : t =
last_found := Some s.graph ;
s
end