-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgw_froglet.frg
97 lines (81 loc) · 2.8 KB
/
gw_froglet.frg
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#lang forge/bsl
option verbose 2
abstract sig Position {}
one sig Near extends Position {}
one sig Far extends Position {}
abstract sig GWAnimal {}
sig Goat extends GWAnimal {}
sig Wolf extends GWAnimal {}
sig GWState {
gwnext: lone GWState,
gwshore: pfunc GWAnimal -> Position, -- where is every animal?
gwboat: one Position -- where is the boat?
}
pred GWValidStates {
// All states must assign a position to every animal and to the boat.
all s: GWState, a: GWAnimal | {
s.gwshore[a] = Near or s.gwshore[a] = Far
}
all s: GWState {
s.gwboat = Near or s.gwboat = Far
}
}
// each of the predicates below should ASSUME valid states
// they should NOT ENFORCE valid states
// (the `run` command below will enforce it!)
pred GWinitState[s: GWState] {
// The boat and all animals start on the near side
s.gwboat = Near
all a: GWAnimal | { s.gwshore[a] = Near }
}
pred GWfinalState[s: GWState] {
// All animals and the boat must end on the far side
s.gwboat = Far
all a: GWAnimal | { s.gwshore[a] = Far }
}
pred GWcanTransition[pre: GWState, post: GWState] {
// - the boat must move
pre.gwboat != post.gwboat
// - the boat can carry 1-2 animals (not zero!)
let animals_with_boat = #{a: GWAnimal | pre.gwshore[a] = pre.gwboat} |
let animals_left_behind = #{a: GWAnimal | post.gwshore[a] = pre.gwboat} |
let animals_taken = subtract[animals_with_boat, animals_left_behind] |
(animals_taken = 1 or animals_taken = 2)
// - every other animal stays in the same place
all a: GWAnimal | pre.gwshore[a] != pre.gwboat => pre.gwshore[a] = post.gwshore[a]
}
pred GWTransitionStates {
some init, final: GWState {
GWinitState[init]
GWfinalState[final]
// - must be no state before the init state
no s: GWState { s.gwnext = init }
// - must be no state after the final state
no s: GWState { final.gwnext = s }
// - every state must be reachable from the initial
reachable[final, init, gwnext]
// - all state transitions must be valid
all pre: GWState | all post: pre.gwnext { GWcanTransition[pre, post] }
}
}
pred GWNeverEating {
// Never have goats outnumbered by wolves on either side.
all s: GWState {
let num_near_wolfs = #{a: Wolf | s.gwshore[a] = Near} |
let num_near_goats = #{a: Goat | s.gwshore[a] = Near} |
num_near_goats != 0 => num_near_goats >= num_near_wolfs
let num_far_wolfs = #{a: Wolf | s.gwshore[a] = Far} |
let num_far_goats = #{a: Goat | s.gwshore[a] = Far} |
num_far_goats != 0 => num_far_goats >= num_far_wolfs
}
}
run {
GWValidStates
GWTransitionStates
GWNeverEating
} for exactly 12 GWState,
exactly 6 GWAnimal,
exactly 3 Goat,
exactly 3 Wolf,
5 Int
for {gwnext is linear}