Safe Haskell | Safe |
---|
Board
Description
This trusted module implements placing-phase and labeled boards. There are two types of placing-phase boards: placing boards, on which some ships have been properly placed, and complete placing boards, on which all ships have been properly placed.
A labeled cell of a player's labeled board is classified with the player's principal, endorsed by both the player and opponent, and includes the player's and opponent's principals and the cell's position in its contents. Thus it is safe to give the opponent possession of the labeled board, assuring that the player can't change its board during the shooting phase. To avoid confusion, we refer to the player as the *originating* player, and to the player's opponent as the *receiving* player. When the receiving player wants to shoot a cell of the originating player's board, it sends the corresponding labeled cell to the originating player, which declassifies it. The receiving player can then check that the declassified labeled cell still has its endorsement, that the receiving principal of the labeled cell is its own principal, and that its position is correct.
Because labeled cells contain the originating and receiving
principals, it is possible to tell a labeled cell originating from one
player from one originating from the other player. Also included in a
labeled cell is a DC
action for shooting the labeled cell, returning
that result of the shot. When a labeled cell is part of a ship, its
DC
action uses a hidden LMVar
-- shared with the other cells of
the same ship -- to keep track of which of the ship's cells have been
hit, so far. Running a cell's DC
action more than once is guaranteed
to produce the same shooting result as the one obtained the first time
it was run.
- size :: Int
- data Pos
- posToPair :: Pos -> (Int, Int)
- pairToPos :: (Int, Int) -> Maybe Pos
- posToStr :: Pos -> String
- strToPos :: String -> Maybe Pos
- data Orient
- orientToStr :: Orient -> String
- strToOrient :: String -> Maybe Orient
- data Placing
- empty :: Placing
- isComplete :: Placing -> Bool
- data PlaceResult a
- = PlacingSuccess a
- | DuplicateShip
- | OffBoard
- | OverlapsShip
- place :: Placing -> Ship -> Pos -> Orient -> PlaceResult Placing
- data Complete
- placingToComplete :: Placing -> Maybe Complete
- data Membership
- placingToMatrix :: Placing -> Matrix Membership
- completeToMatrix :: Complete -> Matrix Membership
- data LSR
- data LC = LC (DCLabeled (Principal, Principal, Pos, DC LSR))
- data LB
- sub :: LB -> Pos -> LC
- update :: LB -> Pos -> LC -> LB
- data LBC
- completeToLBC :: Complete -> Principal -> DCPriv -> DC (Maybe LBC)
- lbcToLB :: LBC -> Principal -> DCPriv -> DC (Maybe LB)
Positions and Orientations
The board size is 10. (This size must be between 1 and 26, inclusive. For the game to be playable, though, the size must be big enough to accomodate all the ships of the Ship module.)
data Pos
Abstract type of board positions, representing pairs (i, j)
,
where i
, j
are in the range 0
..
. size
- 1i
indexes
a row, and j
indexes a column.
Converts a position representing (i, j)
into the string RC
,
where R
is the i
th lowercase letter (counting from 0
), and
C
is the j
th lowercase letter.
data Orient
A ship's orientation.
orientToStr :: Orient -> String
strToOrient :: String -> Maybe Orient
Placing-phase Boards
data Placing
Abstract type consisting of a game board on which each ship has been placed at most once, but where there is no information about shooting.
isComplete :: Placing -> Bool
Tests whether a placing is complete, i.e., whether all ships have been placed on the placing.
data PlaceResult a
Result of placing a ship.
Constructors
PlacingSuccess a | Successful placing. |
DuplicateShip | Ship was already placed. |
OffBoard | Ship (partially) off the board. |
OverlapsShip | Ship overlaps another ship. |
place :: Placing -> Ship -> Pos -> Orient -> PlaceResult Placing
Attempt to place a ship on a placing at a given position and with
a given orientation. When successful, returns PlacingSuccess
of the
resulting placing. Otherwise, the constructor indicates why the
placing failed.
data Complete
Abstract type consisting of a complete placing.
placingToMatrix :: Placing -> Matrix Membership
Export a placing board to its membership matrix
completeToMatrix :: Complete -> Matrix Membership
Export a complete placing board to its membership matrix
Labeled Boards
data LSR
Result of shooting at a labeled cell -- a labeled shot result.
data LC
Datatype of labeled cells. A labeled cell has the form
,
where LC
lclc
is a DCLabel
ed value consisting of a 4-tuple
(origPrin, recvPrin, pos, shoot)
:
-
origPrin ::
is the originating player's principal;Principal
-
recvPrin ::
is the receiving player's principal;Principal
-
pos ::
is the cell's position; andPos
-
shoot ::
is aDC
LSR
DC
action for shooting the cell and reporting on the result (a value of typeLSR
).
Labeled cells are endorsed by both the originating and receiving players; initially they are classified by the originating player.
When a cell is not part of a ship, its DC
action returns MissLSR
.
When a cell is part of a ship, its DC
action uses a hidden
LMVar
, shared with the other cells of the same ship, to keep
track of which of the ship's cells have been hit, so far. When
such a DC
action is run, it returns HitLSR
unless the cell
is/was the last of the ship's cells to be shot. Running a cell's
DC
action more than once produces the same result as was produced
the first time it was run.
data LB
Abstract type of labeled boards, consisting of labeled cells. They have the same dimension as ordinary game boards.
update :: LB -> Pos -> LC -> LB
returns a labeled board that's identical
to update
lb pos lclb
except that the labeled cell at position pos
is lc
.
data LBC
Abstract type of labeled board closures. See completeToLBC
and
lbcToLB
.
completeToLBC :: Complete -> Principal -> DCPriv -> DC (Maybe LBC)
Turn a complete placing board into a labeled board closure, using the originating player's principal and privilege.
returns a completeToLBC
compl origPrin origPrivDC
action
that behaves as follows. First, it checks that
; if this isn't true, it returns toCNF
origPrin ==
toCNF
origPrivNothing
. Next,
it checks whether the current label can flow to dcPublic
, and
dcPublic
can flow to the current clearance. If this isn't the
case, it returns Nothing
. Otherwise, it returns Just
of a
labeled board closure lbc
.
returns a lbcToLB
lbc recvPrin recvPrivDC
action that
behaves as follows. First it checks that running
will succeed. If this isn't the case, it returns
guardWrite
dcPublic
Nothing
. Otherwise, it runs
, which may
raise the current label.
guardWrite
dcPublic
If running a DC
action of the form
(for some principal prin and privilege priv) has previously
gotten past this running of lbcToLB
lbc prin privguardWrite
, our DC
action
returns Nothing
. Otherwise, it continues, as follows.
(This check is performed atomically -- guaranteeing that
only one execution of a DC
action of the form
gets to this point.)
lbcToLB
lbc prin priv
Next, the DC
action checks that origPrin /= recvPrin
and
. If this is not true, the
toCNF
recvPrin == toCNF
recvPrivDC
action returns Nothing
. Next, the DC
action checks that
combination of origPriv
and recvPriv
is strong enough, given
the current label and clearance, to create labeled values with
label origPriv
. If this is not true,
the %%
origPriv /\
recvPrivDC
action returns Nothing
.
Next, the DC
action creates a list -- one for each ship -- of
new, private LMVar
s of type [
with label Pos
]dcPublic
and initial value []
. A ship's LMVar
records the positions of
the cells of the ship that have been hit -- listed in reverse order
of shooting, with no duplicates.
Next, it converts the complete placing compl
into a labeled
board lb
, transforming each cell of compl
into a 4-tuple as follows:
- A cell of ship
ship
at position(i, j)
is turned into(origPrin, recvPrin, (i, j), shoot)
, whereshoot
is aDC
action that knows about the privateLMVar
forship
. Whenshoot
is run (which means the cell is being shot at), the contents of theLMVar
is updated, if necessary, to include position(i, j)
. If the resulting number of positions in theLMVar
is equal to the number of cells ofship
, and if(i, j)
was the last position to be added to the list of shot positions, thenshoot
returns
; otherwise, it returnsSankLSR
shipHitLSR
. (Whenshoot
is run, the value of theLMVar
is taken, usingtakeLMVar
, and then put with a possibly updated list of shot positions, usingputLMVar
. These operations will result in
being run. Depending upon the current label and clearance, this may raise the current label or even raise an exception. Because of how theguardWrite
dcPublic
LMVar
is taken and then put, runningshoot
is thread safe.) - A vacant cell at position
(i, j)
is turned into(origPrin, recvPrin, (i, j),
.return
MissLSR
)
Each 4-tuple t
is then turned into a labeled cell
, where the labeled value LC
lclc
consists of value t
and
label origPriv
.
%%
origPriv /\
recvPriv
Finally,
is returned.
Just
lb