CS195Y Lecture 3

1/30/17


Announcements: Oracle is due Thursday (2/2/17), Join piazza if you haven't already

Tic Tac Toe

Rules of Tic Tac Toe:

We could write a program to play tic tac toe, but what if we wanted to be able to reason about the space of possible tic tac toe games?

Wouldn't it be nice to be able to exhaustively search all of the possible games, up to a certain size?

Introduction to Alloy

The idea of Alloy is not to analyze code, as written, but rather to analyze the design of a system, before
you even write the code. It can be used to look at instances of a model and see if certain behavior is possible.

Tic Tac Toe in Alloy

How would you model Tic Tac Toe? How do you represent the game to the computer, without just implementing the game itself?

Instead of enumerating the possible states, can we somehow describe the rules themselves?

abstract sig Player {} -- There is a type called Player, abstract means we are going to give
subtypes of Player, and every instance is one of these subtypes
one sig X extends Player {} -- X is a type of Player, one means there can only be exactly one
instance of X. That is, all Xs are the same.
run {} -- Tells Alloy, "given the constraints I just gave you, find me an example"

The players are looking good. Now what do we need?
We need some way of talking about the structure of the board.

sig Board {
  places : (Index -> Index) -> Player
}

This says that every Board has a mapping from (row, column) locations on the board to pieces that are played.
What if we said one sig Board? Then, there could only be one possible arrangement of pieces on the board.
Alloy is showing you samples from all of the possible boards, not necessarily boards that should be part
of the same game.

All we've defined is a field that takes two indices and forms a relation. Thus we can get instances with more than 9 tokens
or such that there are more Os than Xs.

Let's fix these bugs.

fact atMostOneMark{
   all b : Board |
      all r, c : Index |
         #b.places[r][c] <= 1}

This would prevent any cell from having more than one token in it. But can we do this in a better way?
Yes! We can add the lone keyword to the relation which provides the same constraint much more concisely.

sig Board {
  places : (Index -> Index) -> lone Player
}

The lone keyword means that at every pair of indices, there is either 0 or 1 Player at that place.

Now we see a board with one token placed an it's an O. Is this our expected behavior? No.

Is it good that Alloy shows us this instance? Yes, because it shows us what we said rather than what we meant. Oftentimes we think we've created a system that behaves in a given way but that is not actually the case. Alloy can help us find these oversights.

Now we can go back and add in the constraint that we forgot.
How do we describe to Alloy what it means for it to be O's turn?
It is O's turn if there is one more X than Os on the board.

We want a predicate pred xturn[b: Board] which will be true if it is X's turn for the given board, false otherwise.
#{r, c : Index | b.places[r][c] = O} -- this is a set comprehension that includes all the pairs of indices such that the given board has an O at the pair of indices.

pred xturn[b: Board] {
   #{r, c : Index | b.places[r][c] = O} = #{r, c : Index | b.places[r][c] = X}
}
run xturn

This predicate tells us if it's X's turn based on how many Xs and Os are on the board.

pred oturn[b: Board] {
  not xturn[b]
}
run oturn

Will oturn work?
If I had more O's than X's xturn would return false and then oturn would be true. This is bad!

How can we fix it?

pred oturn[b: Board] {
   #{r, c : Index | b.places[r][c] = O} = sub[#{r, c : Index | b.places[r][c] = X}, 1]
}
run oturn

How can we represent a valid board?

pred validBoard[b : Board]{
   oturn[b] or xturn[b]
}

On Wednesday, we'll talk about how to model a full game of tic tac toe.