/*
LEARNING BY PLAYING WITH THE RIVER MICROWORLD

An 'unscripted' tutorial
Presenter: Aaron Sloman
School of Computer Science, University of Birmingham
http://www.cs.bham.ac.uk/research/projects/poplog/cas-ai/video-tutorials.html
Recorded: 9 Jan 2012

Based on a program originally by Max Clowes,
University of Sussex, around 1978

Available as part of Poplog and here:
    http://www.cs.bham.ac.uk/research/projects/poplog/teach/riverworld

A Youtube video tutorial based on this will be available.

A previous tutorial explained how a teacher could set up a microworld based on
the 'River Crossing' puzzle: the RiverWorld, as described in

    TEACH RIVERWORLD

This tutorial, also for teachers, shows how a learner can make use of the
microworld after it has been created, using a Pop11 library that is included in
in Poplog, and a teach file to go with it: TEACH RIVER

This microworld deals with a world in which processes occur, like a boat
crossing a river.

We shall not simulate the detailed processes of crossing the river, which would
be required for a system to demonstrate fine-grained "online" control of
actions. Some programming teaching environments (e.g. the MIT Scratch system)
emphasise such control of motion.

So this is not about how to generate impressive or entertaining interactive
displays.

Instead we focus on how an intelligent individual works out a plan of action
without considering all the details -- only the major transitions. Learning how
to divide up continuous changes into sequences of discrete states is a major
aspect of human intelligence, and probably also intelligence in some animals.

This is a small step towards 'Thinky Programming', defined in more detail in
this web site:

    http://www.cs.bham.ac.uk/research/projects/poplog/examples

*/

/*

CONTENTS

 -- Introduction: Setting up a microworld for teaching
 -- Procedure start is used to initialise everything.
 -- Procedure view() shows the current state diagrammatically
 -- Test start();
 -- Action procedures which check preconditions then change the world
 -- putin(item)
 -- LIB rIVER removes the need to type word quotes
 -- Procedure takeout(item)
 -- Procedure getin()
 -- Procedures getout(), crossriver(), takeout(item)
 -- Test a sequence of commands
 -- Things a student can go on to learn
 -- Defining a procedure that solves the puzzle
 -- The long solution can be shortened by defining procedures
 -- Defining new sub-procedures
 -- Testing cross
 -- Exercise: shorten the solve procedure
 -- Moving up to a higher level of structure
 -- Procedure opposite(side)
 -- Further Reading

-- Introduction: Setting up a microworld for teaching -----------------

This tutorial (with video on Youtube) explains how to use the Pop11 language
including its pattern matcher and simple database mechanism to create a
micro-world for teaching some aspect of general programming, or AI (artificial
intelligence) programming.

An earlier tutorial TEACH RIVER
    http://www.cs.bham.ac.uk/research/projects/poplog/teach/river
with Youtube video showing how it works:
    http://youtu.be/xfGv9xfqDxU

made use of a microworld of the sort described here. The original program
providing the microworld (available as LIB RIVER in Pop11) is several decades
old. The version presented below makes less use of general programming
constructs (e.g. using global variables) and more use of a database in which
knowledge about the world, including both its general features and its current
state, can be stored.

It is useful to distinguish:
o Internal semantics of the program.
    Which entities and operations of the computer, or the virtual machine
    running on the computer are referred to by structures and commands in the
    program code.
    E.g. the program can refer to lists, strings, number representations,
    variables, their values, procedures, and operations on those items.

o External semantics of the program.
    Which entities, states, events and processes in the world being modelled
    (e.g. a boat, a man, a river, and processes of getting in and out of the
    boat, or moving the boat from one side of the river to the other) are
    referred to by structures and commands in the program code. The external
    semantics can also include causal relationships (what causes what, and what
    constraints what) in the world represented.

The external semantics may or may not include some portion of the actual world.
In this tutorial it is a mythical rather simple world, which is an abstraction
from things that can exist in our actual world, containing real rivers, boats,
animals, eatings, river crossings, and so on.

The external causal relationships will be represented by constraints on what the
program allows, or what side effects running portions of the program can have.

In this tutorial, intended for teachers learning to set up a microworld for
students to use, we employ the pop11 database and associated mechanisms, in
addition to conventional programming constructs, e.g. procedures,
variables, conditionals, loops, etc.

The pop11 database is one of a number of related libraries of varying
sophistication available in pop11 based in the Pop11 pattern matcher, introduced
in

    TEACH MATCHES
and summarised in
    HELP MATCHES

with an enhanced version described in
    HELP DOESMATCH

The database is explained in these files

    TEACH DATABASE
    HELP DATABASE
    TEACH FOREACH
    HELP FOREVERY
    HELP WHICH

and other files referenced in those.
    TEACH

Previous video tutorials in this collection introduced the use of the matcher.
This one shows how to use the matcher with Pop11's most elementary database
mechanisms to design a microworld.

The microworld is the puzzle world of man, fox, chicken, grain, boat and river,
illustrated in TEACH RIVER.

*/

;;; We use the pop11 river package, described in TEACH RIVER

uses river

/*
-- Procedure start is used to initialise everything. ------------------

*/

start();

database ==>

/*

-- Procedure view() shows the current state diagrammatically ----------

view();

As the databse representing the state of the world changes, the view() procedure
can inspect the current contents of the database, and show states of the world
in one-dimensional diagrams like these:

    ** [man grain chicken fox ---\ \_ _/ _________________ /---]

    ** [man grain chicken fox ---\ _________________ \_ _/ /---]

    ** [man grain chicken fox ---\ \_ _/ _________________ /---]

    ** [man grain chicken ---\ \_ fox _/ _________________ /---]

    ** [grain chicken ---\ \_ man fox _/ _________________ /---]

    ** [grain chicken ---\ _________________ \_ man fox _/ /---]

    ** [grain chicken ---\ _________________ \_ fox _/ /--- man]

    ** [grain chicken ---\ _________________ \_ _/ /--- fox man]

    ** [chicken ---\ _________________ \_ _/ /--- fox man]


NB: the laws of our microworld should not allow some of these states to exist!

*/


/*

-- Test start(); ------------------------------------------------------

start();

;;; Print out the database:

database ==>

;;; That should print out

** [[boat isat left]
    [chicken isat left]
    [fox isat left]
    [grain isat left]
    [man isat left]]

;;; display the world using text-graphics (for now)

view();

;;; That should print out:

    ** [man grain chicken fox ---\ \_ _/ _________________ /---]

remove([boat isat left]);
add([boat isat right]);


;;; the database has now changed -- boat now at right:
database ==>

;;; should print out
** [[boat isat right]
    [chicken isat left]
    [fox isat left]
    [grain isat left]
    [man isat left]]

;;; How does that look graphically
view();

;;; the boat is now shown at the right (moved by magic):

    ** [man grain chicken fox ---\ _________________ \_ _/ /---]

;;; We can create a simulated world in which things happen that would be
;;; impossible in the real world, or in the world defined by the puzzle.

*/

/*



/*
-- Action procedures which check preconditions then change the world --

-- putin(item) --------------------------------------------------------
*/


/*
;;; test putin

start();

view();

putin("elephant");

putin("man");

getin();

view();
database ==>

/*

-- LIB rIVER removes the need to type word quotes ---------------------

The river library defines several global variables to refer to the words "man"
"fox" etc., so that we don't need to type the word quotes in al our commands.

This is how it is done:

vars man, fox, chicken, grain, boat;

"man" -> man;

"fox" -> fox;

"chicken" -> chicken;

"grain"-> grain;

"boat" -> boat;

The TEACH RIVER file, intended for beginners, hides this detail, and just tells
learners to type:

    putin(fox);

not

    putin("fox");

*/

/*
-- Procedure takeout(item) --------------------------------------------

*/

start();

view();

putin(fox);

view();

database ==>

takeout(fox);

takeout(chicken);
takeout(grain);

takeout(man);

takeout(boat);


*/
/*

-- Procedure getin() --------------------------------------------------

*/

start();

view();

getin();

view();

Notice the disaster!


*/

/*

-- Procedures getout(), crossriver(), takeout(item) -------------------

*/

start();

view();

putin(chicken);

getin();

view();

crossriver();

view();

getout();

view();

;;; we can now use 'takeout'

takeout(chicken);

view();

database ==>

/*
-- Test a sequence of commands ----------------------------------------

start();
getin();
checkeat();
crossriver();
getout();

*/


/*

-- Things a student can go on to learn --------------------------------

*/

A full solution is quite long and repetitive

    start();
    putin(chicken);
    getin();
    crossriver();
    getout();
    takeout(chicken);
    getin();
    crossriver();
    getout();
    putin(fox);
    getin();
    crossriver();
    getout();
    takeout(fox);
    putin(chicken);
    getin();
    crossriver();
    getout();
    takeout(chicken);
    putin(grain);
    getin();
    crossriver();
    getout();
    takeout(grain);
    getin();
    crossriver();
    getout();
    putin(chicken);
    getin();
    crossriver();
    getout();
    takeout(chicken);

-- Defining a procedure that solves the puzzle ------------------------

You can now combine all your instructions into one big procedure
called "solve" by putting the following at the beginning
of the set of commands in your file solve.p

    define solve();

and putting the following at the end

    enddefine;


define solve();

    start();
    putin(chicken);
    getin();
    crossriver();
    getout();
    takeout(chicken);
    getin();
    crossriver();
    getout();
    putin(fox);
    getin();
    crossriver();
    getout();
    takeout(fox);
    putin(chicken);
    getin();
    crossriver();
    getout();
    takeout(chicken);
    putin(grain);
    getin();
    crossriver();
    getout();
    takeout(grain);
    getin();
    crossriver();
    getout();
    putin(chicken);
    getin();
    crossriver();
    getout();
    takeout(chicken);

enddefine;

;;; then instead of running all those instructions, we can run
;;; one instruction

solve();



/*
-- The long solution can be shortened by defining procedures

The long solution is very clumsy, and has much repetition.

We can shorten it by defining sub-procedures.

-- Defining new sub-procedures ----------------------------------------

The sequence of successful commands in the definition of "solve" is long
and repetitive. You can abbreviate it by replacing some of the repeated
sub-sequences by commands to obey your own procedures.

;;; One of the repeated sub-sequences consists of the sequence of actions

       getin();
       crossriver();
       getout();

This sequence can be replaced by a single command

        cross();

PROVIDED that you first define a procedure called "cross".

E.g.
*/

define cross();
   getin();
   crossriver();
   getout();
enddefine;

/*

-- Testing cross ------------------------------------------------------

*/

    start();
    putin(chicken);
    cross();

    database ==>
    view();

    cross();

/*
-- Exercise: shorten the solve procedure ------------------------------

*/

define shortsolve();
    start();
    putin(chicken);

    ;;; previous instructions:
    ;;; getin();
    ;;; crossriver();
    ;;; getout();

    cross();

    takeout(chicken);
    cross();

    putin(fox);
    getin();
    crossriver();
    getout();
    takeout(fox);
    putin(chicken);
    getin();
    crossriver();
    getout();
    takeout(chicken);
    putin(grain);
    getin();
    crossriver();
    getout();
    takeout(grain);
    getin();
    crossriver();
    getout();
    putin(chicken);
    getin();
    crossriver();
    getout();
    takeout(chicken);

enddefine;

;;; test shortsolve

shortsolve();

/*
Of course

-- Moving up to a higher level of structure ---------------------------

There is still another repetition of more or less the same form -

    putin(thing);
    cross();
    takeout(thing);

Define a new procedure called move(thing);
*/

define move (thing);
    putin(thing);
    cross();
    takeout(thing);
enddefine;

/*
This a procedure with an "input variable", namely "thing".

It is called a variable because it can be given different values, e.g. fox,
river, or grain, when the procedure MOVE is run.

Sometimes the name "argument" is used instead of "input variable".

NOTE:
Pop11 also allows procedures to have output variables, if the create something
to be printed out or used by other procedures.

See TEACH DEFINE


Now test the procedure:
*/


    start();
    move(fox);

;;; or
    move(chicken);

;;; or

    move(grain);

/*

TEACH RIVER introduces some relatively small fragments.

There is lots more to be said about how we can talk about procedures,
algorithms, functions, complete programs, and large systems assembled from many
programs.

But not now.

*/


/*


-- Procedure opposite(side) -------------------------------------------

There are many more details in the library that have not been shown here.

A learner might invent them spontaneously to save repetition or might be given a
hint.

For example the procedure for crossing the river has to go from left to right,
or from right to left. By defining an auxilliary procedure (or subroutine)
called opposite, it can complex a clumsy conditional command into a single
elegant command that covers both cases.

*/


opposite("left") =>
opposite("right") =>

;;; This can be used in a sequence of commands like:

    lookup([boat isat ?place]);

    opposite(place) -> newplace;

    remove([boat isat ^place]);

    add([boat isat ^newplace]);

;;; That is nice because the same code will move things from left to right
;;; and from right to left.

;;; There's lots more that can be learnt in this microworld.


/*

-- Further Reading ----------------------------------------------------

TEACH RIVER

TEACH DATABASE

TEACH LISTS

TEACH FOREACH

TEACH RIVERCHAT


TEACH PRBRIVER
    Shows how a program using poprulebase can search for a plan to cross
    the river, using either depth first or breadth first searching.

And there's lots, lots more.

*/