Remote agent/Simulation: Difference between revisions

From Rosetta Code
Content added Content deleted
(Revert to binary 'rd')
(Cleaned up)
Line 2: Line 2:


=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
This is the server. For the client, see [[Remote agent/Agent logic#PicoLisp]].
Here is my first attempt on the server part. It works. After starting
(gameServer), you can connect with 'telnet', type the commands, and see the
After starting (gameServer), you might for testing purposesalso connect with 'telnet', type the commands, and see the responses.
responses.
<lang PicoLisp># Global variables:
<lang PicoLisp># Global variables:
# '*Port' is the port where the server is listening
# '*Port' is the port where the server is listening
Line 85: Line 84:


# Start the game server
# Start the game server
(de gameServer ()
(de gameServer (DX DY Balls Walls)
(loop
(loop
(setq *Sock (listen *Port))
(setq *Sock (listen *Port))
Line 93: Line 92:
(in *Sock
(in *Sock
(out *Sock (prin "A")) # Greeting
(out *Sock (prin "A")) # Greeting
(when (= `(char "A") (rd 1))
(when (= "A" (char (rd 1)))
(newGame 8 8 20 40)
(newGame DX DY Balls Walls)
(and *Dbg (showWorld))
(while (rd 1)
(while (rd 1)
(out *Sock
(out *Sock
(case @ # Command character
(case (char @) # Command character
(`(char "\^") # Forward
("\^" # Forward
(ifn ((car *Dir) *Agent) # Hit wall?
(ifn ((car *Dir) *Agent) # Hit wall?
(prin "|") # Yes: Bump event
(prin "|") # Yes: Bump event
Line 104: Line 104:
(prin (: field))
(prin (: field))
(and (: ball) (prin (lowc @))) ) ) )
(and (: ball) (prin (lowc @))) ) ) )
(`(char ">") # Turn right
(">" # Turn right
(pop '*Dir) )
(pop '*Dir) )
(`(char "<") # Turn left
("<" # Turn left
(do 3 (pop '*Dir)) )
(do 3 (pop '*Dir)) )
(`(char "@") # Get ball
("@" # Get ball
(with *Agent
(with *Agent
(cond
(cond
Line 116: Line 116:
(setq *Ball (: ball))
(setq *Ball (: ball))
(=: ball) ) ) ) )
(=: ball) ) ) ) )
(`(char "!") # Drop ball
("!" # Drop ball
(with *Agent
(with *Agent
(cond
(cond
((not *Ball) (prin "a")) # No ball in agent
((not *Ball) (prin "a")) # No ball in agent
((: ball) (prin "S")) # Sector full
((: ball) (prin "S")) # Sector full
((ending?) (prin "+")) # Game over
(T (=: ball *Ball)
(T (=: ball *Ball) (off *Ball)) ) ) ) )
(off *Ball)
(and (ending?) (prin "+")) ) ) ) ) ) # Game over
(prin ".") ) ) ) ) # Stop event
(prin ".") ) ) ) ) # Stop event
(bye) )
(bye) )
Line 137: Line 138:


For local tests, you can start also it interactively:
For local tests, you can start also it interactively:
<pre>: (newGame 8 8 20 40) (showWorld)
<pre>: (newGame 8 8 20 40) (showWorld)
+---+---+---+---+---+---+---+---+
+---+---+---+---+---+---+---+---+
8 | R Y | B | R R Br| Rb Br|
8 | R Y | B | R R Br| Rb Br|
Line 156: Line 157:
+---+---+---+---+---+---+---+---+
+---+---+---+---+---+---+---+---+
a b c d e f g h</pre>
a b c d e f g h</pre>
This displays the field colors in upper case letters, the balls in lower case
This displays the field colors in upper case letters, the balls in lower case letters, and the position of the agent with an asterisk.
letters, and the position of the agent with an asterisk.

Revision as of 18:26, 3 January 2011

Remote agent/Simulation is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

As described in Remote agent, generate a map, accept and respond to commands from an agent using an unbuffered stream.

PicoLisp

This is the server. For the client, see Remote agent/Agent logic#PicoLisp. After starting (gameServer), you might for testing purposesalso connect with 'telnet', type the commands, and see the responses. <lang PicoLisp># Global variables:

  1. '*Port' is the port where the server is listening
  2. '*Sock' is the TCP socket after a client connected
  3. '*World' holds the current world
  4. '*Agent' is the field where the agent is in
  5. '*Ball' is the ball the agent is holding
  6. '*Dir' is a circular list of directions (north east south west .)

(load "@lib/simul.l")

  1. The server port

(setq *Port (port 54545))

  1. Return a random Field

(de randomField ()

  (get *World (rand 1 DX) (rand 1 DY)) )
  1. Create a world of size 'DX' * 'DY' with 'Balls' and 'Walls'

(de makeWorld (DX DY Balls Walls)

  (when (>= Balls (* DX DY))
     (quit "Too many balls") )
  (when (>= Walls (* (dec DX) (dec DY)))
     (quit "Too many walls") )
  (for Column (setq *World (grid DX DY))          # Initialize fields
     (for This Column
        (let Color (get '(R G Y B) (rand 1 4))
           (=: field Color)                       # Set field color
           (when (ge0 (dec 'Balls))
              (until
                 (with (randomField DX DY)        # Find a field without ball
                    (unless (: ball)              # and set a ball
                       (=: ball Color) ) ) ) ) ) ) )
  (do Walls                              # Create walls
     (until
        (let
           (Field (randomField DX DY)    # Try random field
              F (if (rand T) car cdr)    # and random side
              G (if (rand T) '(car set . con) '(cdr con . set))
              Old ((car G) (F (val Field))) )
           (when Old
              ((cadr G) (F (val Field)) NIL)  # Remove connections to neighbor
              ((cddr G) (F (val Old)) NIL)
              (or
                 (reachable? Field (* DX DY))  # Field still reachable?
                 (nil                          # No: Restore connections
                    ((cadr G) (F (val Field)) Old)
                    ((cddr G) (F (val Old)) Field) ) ) ) ) ) ) )
  1. Test whether a field is reachable

(de reachable? (Field Fields)

  (let Visited NIL
     (recur (Field)
        (when (and Field (not (memq Field Visited)))
           (push 'Visited Field)
           (recurse (west Field))
           (recurse (east Field))
           (recurse (south Field))
           (recurse (north Field)) ) )
     (= Fields (length Visited)) ) )
  1. Test for ending condition

(de ending? ()

  (nor
     *Ball
     (find
        '((Column)
           (find
              '((This)
                 (and (: ball) (n== (: field) (: ball))) )
              Column ) )
        *World ) ) )
  1. Initialize for a new game

(de newGame (DX DY Balls Walls)

  (makeWorld DX DY Balls Walls)
  (setq
     *Agent (randomField DX DY)
     *Dir (do (rand 1 4) (rot '(north east south west .))) ) )
  1. Start the game server

(de gameServer (DX DY Balls Walls)

  (loop
     (setq *Sock (listen *Port))
     (NIL (fork) (close *Port))
     (close *Sock) )
  (seed *Pid)  # Ensure private random sequence
  (in *Sock
     (out *Sock (prin "A"))  # Greeting
     (when (= "A" (char (rd 1)))
        (newGame DX DY Balls Walls)
        (and *Dbg (showWorld))
        (while (rd 1)
           (out *Sock
              (case (char @)  # Command character
                 ("\^"  # Forward
                    (ifn ((car *Dir) *Agent)  # Hit wall?
                       (prin "|")             # Yes: Bump event
                       (with (setq *Agent @)  # Else go to new position
                          (prin (: field))
                          (and (: ball) (prin (lowc @))) ) ) )
                 (">"  # Turn right
                    (pop '*Dir) )
                 ("<"  # Turn left
                    (do 3 (pop '*Dir)) )
                 ("@"  # Get ball
                    (with *Agent
                       (cond
                          ((not (: ball)) (prin "s"))  # No ball in sector
                          (*Ball (prin "A"))           # Agent full
                          (T
                             (setq *Ball (: ball))
                             (=: ball) ) ) ) )
                 ("!"  # Drop ball
                    (with *Agent
                       (cond
                          ((not *Ball) (prin "a"))  # No ball in agent
                          ((: ball) (prin "S"))     # Sector full
                          (T (=: ball *Ball)
                             (off *Ball)
                             (and (ending?) (prin "+")) ) ) ) ) )  # Game over
              (prin ".") ) ) ) )  # Stop event
  (bye) )
  1. Visualize (debug)

(de showWorld ()

  (disp *World 0
     '((This)
        (pack
           (if (== *Agent This) "*" " ")
           (: field)
           (if (: ball) (lowc @) " ") ) ) ) )</lang>

An online demo version of this server runs on port 54545 of "picolisp.com". It can be used for testing.

For local tests, you can start also it interactively:

: (newGame 8 8 20 40) (showWorld)
   +---+---+---+---+---+---+---+---+
 8 | R   Y | B | R   R   Br| Rb  Br|
   +   +   +   +   +   +---+---+   +
 7 | Yy  G   G   Gb| Y   Gg  Rr| Y |
   +---+   +   +   +---+   +---+   +
 6 | R   Y   B   Rr *G   Y | Y   Br|
   +---+---+   +   +---+---+   +---+
 5 | B   Ry  G   R | Yy  Yy  Y | B |
   +   +---+---+   +---+   +---+   +
 4 | R | R   R   Gg  B   G   B   Y |
   +   +---+---+   +---+---+   +   +
 3 | R   Rr| Y   B   G | Yr  B | R |
   +   +   +---+---+---+   +   +---+
 2 | Y | B | B   Bb  Gr  B   B   Yy|
   +   +   +   +   +---+   +---+   +
 1 | Rr| R   G   Gr  R   G   R | G |
   +---+---+---+---+---+---+---+---+
     a   b   c   d   e   f   g   h

This displays the field colors in upper case letters, the balls in lower case letters, and the position of the agent with an asterisk.