Remote agent/Simulation: Difference between revisions

From Rosetta Code
Content added Content deleted
(Simplified: Binary I/O not necessary)
(Added walls and debug display)
Line 2: Line 2:


=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
Here is my first attempt on the server part. It works, you can connect with 'telnet', type the commands, and see the responses.
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
responses.
<lang PicoLisp>(load "@lib/simul.l")
<lang PicoLisp>(load "@lib/simul.l")


Line 14: Line 16:


# The server port
# The server port
(setq *Port (port 6789))
(setq *Port (port 54545))


# Return a random Field
# Return a random Field
Line 20: Line 22:
(get *World (rand 1 DX) (rand 1 DY)) )
(get *World (rand 1 DX) (rand 1 DY)) )


# Create a world of size 'DX' * 'DY' with 'Percent' balls in it
# Create a world of size 'DX' * 'DY' with 'Balls' and 'Walls'
(de makeWorld (DX DY Percent)
(de makeWorld (DX DY Balls Walls)
(for Column (setq *World (grid DX DY))
(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
(for This Column
(let Color (get '(R G Y B) (rand 1 4))
(let Color (get '(R G Y B) (rand 1 4))
(=: field Color)
(=: field Color) # Set field color
(when (>= Percent (rand 1 100))
(when (ge0 (dec 'Balls))
(until
(until
(with (randomField DX DY)
(with (randomField DX DY) # Find a field without ball
(unless (=: ball)
(unless (: ball) # and set a ball
(=: ball Color) ) ) ) ) ) ) ) )
(=: 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) ) ) ) ) ) ) )

# 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)) ) )


# Test for ending condition
# Test for ending condition
Line 45: Line 78:


# Initialize for a new game
# Initialize for a new game
(de newGame (DX DY Percent)
(de newGame (DX DY Balls Walls)
(makeWorld DX DY Percent)
(makeWorld DX DY Balls Walls)
(setq
(setq
*Agent (randomField DX DY)
*Agent (randomField DX DY)
Line 61: Line 94:
(out *Sock (prin "A")) # Greeting
(out *Sock (prin "A")) # Greeting
(when (= "A" (char))
(when (= "A" (char))
(newGame 12 9 10)
(newGame 8 8 20 40)
(while (char)
(while (char)
(out *Sock
(out *Sock
Line 89: Line 122:
(T (=: ball *Ball) (off *Ball)) ) ) ) )
(T (=: ball *Ball) (off *Ball)) ) ) ) )
(prin ".") ) ) ) ) # Stop event
(prin ".") ) ) ) ) # Stop event
(bye) )</lang>
(bye) )

# Visualize (debug)
(de showWorld ()
(disp *World 0
'((This)
(pack
(if (== *Agent This) "*" " ")
(: field)
(if (: ball) (lowc @) " ") ) ) ) )</lang>
For testing, you can start also it interactively:
<pre>: (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</pre>
This displays the field colors in upper case letters, the balls in lower case
letters, and the position of the agent with an asterisk.

Revision as of 12:43, 17 December 2010

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

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 responses. <lang PicoLisp>(load "@lib/simul.l")

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

  (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))
        (newGame 8 8 20 40)
        (while (char)
           (out *Sock
              (case @  # Command character
                 ("F"  # 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))) ) ) )
                 ("!"  # Drop ball
                    (with *Agent
                       (cond
                          ((not *Ball) (prin "a"))  # No ball in agent
                          ((: ball) (prin "S"))     # Sector full
                          ((ending?) (prin "+"))    # Game over
                          (T (=: ball *Ball) (off *Ball)) ) ) ) )
              (prin ".") ) ) ) )  # Stop event
  (bye) )
  1. Visualize (debug)

(de showWorld ()

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

For testing, 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.