Skip to content

Commit 427325b

Browse files
author
Shati Patel
committed
QL etudes: Update with Robert's suggestions
1 parent 886b258 commit 427325b

File tree

3 files changed

+29
-35
lines changed

3 files changed

+29
-35
lines changed

docs/language/learn-ql/ql-etudes/river-crossing-1.ql

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,8 @@ class Shore extends string {
3333
/** A record of where everything is. */
3434
class State extends string {
3535
Shore manShore;
36-
3736
Shore goatShore;
38-
3937
Shore cabbageShore;
40-
4138
Shore wolfShore;
4239

4340
State() { this = manShore + "," + goatShore + "," + cabbageShore + "," + wolfShore }
@@ -57,16 +54,16 @@ class State extends string {
5754
}
5855

5956
/**
60-
* Holds if eating occurs. This happens when predator and prey are on the same shore
61-
* and the man is not present.
57+
* Holds if the state is safe. This occurs when neither the goat nor the cabbage
58+
* can get eaten.
6259
*/
63-
predicate eating(Shore predatorShore, Shore preyShore) {
64-
predatorShore = preyShore and manShore != predatorShore
60+
predicate isSafe() {
61+
// The goat can't eat the cabbage.
62+
(goatShore != cabbageShore or goatShore = manShore) and
63+
// The wolf can't eat the goat.
64+
(wolfShore != goatShore or wolfShore = manShore)
6565
}
6666

67-
/** Holds if nothing gets eaten in this state. */
68-
predicate isSafe() { not (eating(goatShore, cabbageShore) or eating(wolfShore, goatShore)) }
69-
7067
/** Returns the state that is reached after safely ferrying a cargo item. */
7168
State safeFerry(Cargo cargo) { result = this.ferry(cargo) and result.isSafe() }
7269

docs/language/learn-ql/ql-etudes/river-crossing.ql

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,8 @@ string renderState(Shore manShore, Shore goatShore, Shore cabbageShore, Shore wo
4545
/** A record of where everything is. */
4646
class State extends string {
4747
Shore manShore;
48-
4948
Shore goatShore;
50-
5149
Shore cabbageShore;
52-
5350
Shore wolfShore;
5451

5552
State() { this = renderState(manShore, goatShore, cabbageShore, wolfShore) }
@@ -70,16 +67,16 @@ class State extends string {
7067
}
7168

7269
/**
73-
* Holds if eating occurs. This happens when predator and prey are on the same shore
74-
* and the man is not present.
70+
* Holds if the state is safe. This occurs when neither the goat nor the cabbage
71+
* can get eaten.
7572
*/
76-
predicate eating(Shore predatorShore, Shore preyShore) {
77-
predatorShore = preyShore and manShore != predatorShore
73+
predicate isSafe() {
74+
// The goat can't eat the cabbage.
75+
(goatShore != cabbageShore or goatShore = manShore) and
76+
// The wolf can't eat the goat.
77+
(wolfShore != goatShore or wolfShore = manShore)
7878
}
7979

80-
/** Holds if nothing gets eaten in this state. */
81-
predicate isSafe() { not (eating(goatShore, cabbageShore) or eating(wolfShore, goatShore)) }
82-
8380
/** Returns the state that is reached after safely ferrying a cargo item. */
8481
State safeFerry(Cargo cargo) { result = this.ferry(cargo) and result.isSafe() }
8582

@@ -91,7 +88,7 @@ class State extends string {
9188
State reachesVia(string path, string visitedStates) {
9289
// Trivial case: a state is always reachable from itself.
9390
this = result and
94-
visitedStates = "" and
91+
visitedStates = this and
9592
path = ""
9693
or
9794
// A state is reachable using pathSoFar and then safely ferrying cargo.

docs/language/learn-ql/ql-etudes/river-crossing.rst

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ a piece of cargo.
4242
*Show/hide code*
4343

4444
.. literalinclude:: river-crossing.ql
45-
:lines: 15-22
45+
:lines: 15-23
4646

4747
Second, any item can be on one of two shores. Let's call these the "left shore" and the "right shore".
4848
Define a class ``Shore`` containing ``"Left"`` and ``"Right"``.
@@ -75,7 +75,7 @@ temporary variables in the body of a class are called `fields <https://help.semm
7575
*Show/hide code*
7676

7777
.. literalinclude:: river-crossing-1.ql
78-
:lines: 33-43,90
78+
:lines: 33-40,87
7979

8080
We are interested in two particular states, namely the initial state and the goal state,
8181
which we have to achieve to solve the puzzle.
@@ -89,7 +89,7 @@ Assuming that all items start on the left shore and end up on the right shore, d
8989
*Show/hide code*
9090

9191
.. literalinclude:: river-crossing-1.ql
92-
:lines: 92-100
92+
:lines: 89-97
9393

9494
.. pull-quote::
9595

@@ -107,7 +107,7 @@ Using the above note, the QL code so far looks like this:
107107
*Show/hide code*
108108

109109
.. literalinclude:: river-crossing.ql
110-
:lines: 14-55,105-115
110+
:lines: 15-52,103-113
111111

112112
Model the action of "ferrying"
113113
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -125,15 +125,14 @@ after ferrying a particular cargo. (Hint: Use the predicate ``other``.)
125125
*Show/hide code*
126126

127127
.. literalinclude:: river-crossing.ql
128-
:lines: 57-70
128+
:lines: 54-67
129129

130130
Of course, not all ferrying actions are possible. Add some extra conditions to describe when a ferrying
131131
action is "safe". That is, it doesn't lead to a state where the goat or the cabbage get eaten.
132132
For example, follow these steps:
133133

134-
#. Define a predicate ``eating`` that encodes the conditions for when a "predator" is able to eat an
135-
unguarded "prey".
136-
#. Define a predicate ``isSafe`` that holds when nothing gets eaten.
134+
#. Define a predicate ``isSafe`` that holds when the state itself is safe. Use this to encode the
135+
conditions for when nothing gets eaten.
137136
#. Define a predicate ``safeFerry`` that restricts ``ferry`` to only include safe ferrying actions.
138137

139138
.. container:: toggle
@@ -143,13 +142,14 @@ For example, follow these steps:
143142
*Show/hide code*
144143

145144
.. literalinclude:: river-crossing.ql
146-
:lines: 72-84
145+
:lines: 69-81
147146

148147
Find paths from one state to another
149148
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
150149

151150
The main aim of this query is to find a path, that is, a list of successive ferrying actions, to get
152-
from the initial state to the goal state.
151+
from the initial state to the goal state. You could write this "list" by separating each item by a
152+
newline (``"\n"``).
153153

154154
When finding the solution, you should be careful to avoid "infinite" paths. For example, the man
155155
could ferry the goat back and forth any number of times without ever reaching an unsafe state.
@@ -180,7 +180,7 @@ for example ``steps <= 7``.
180180
*Show/hide code*
181181

182182
.. literalinclude:: river-crossing-1.ql
183-
:lines: 73-89
183+
:lines: 70-86
184184

185185
However, although this ensures that the solution is finite, it can still contain loops if the upper bound
186186
for ``steps`` is large. In other words, you could get an inefficient solution by revisiting the same state
@@ -210,7 +210,7 @@ the given path without revisiting any previously visited states.
210210
*Show/hide code*
211211

212212
.. literalinclude:: river-crossing.ql
213-
:lines: 86-105
213+
:lines: 83-102
214214

215215
Display the results
216216
~~~~~~~~~~~~~~~~~~~
@@ -225,7 +225,7 @@ that returns the resulting path.
225225
*Show/hide code*
226226

227227
.. literalinclude:: river-crossing.ql
228-
:lines: 118-120
228+
:lines: 115-117
229229

230230
For now, the path defined in the above predicate ``reachesVia`` just lists the order of cargo items to ferry.
231231
You could tweak the predicates and the select clause to make the solution clearer. Here are some suggestions:
@@ -245,7 +245,7 @@ Here are some more example QL queries that solve the river crossing puzzle:
245245
#. This query uses a modified ``path`` variable to describe the resulting path in
246246
more detail.
247247

248-
➤ `See solution in the query console <https://lgtm.com/query/374739798559373721/>`__
248+
➤ `See solution in the query console <https://lgtm.com/query/659603593702729237/>`__
249249

250250
#. This query models the man and the cargo items in a different way, using an
251251
`abstract <https://help.semmle.com/QL/ql-handbook/annotations.html#abstract>`__

0 commit comments

Comments
 (0)