Remote agent/Agent interface: Difference between revisions

From Rosetta Code
Content added Content deleted
(Agent interface task part.)
 
(→‎Tcl: Added implementation + demonstration of how to use the interface)
Line 1: Line 1:
{{draft task}}In [[Remote agent]], a component is described that marshals commands and events between a stream and a program that issues commands and processes the resulting events. Using the protocol definition described there, build this component in a fashion idiomatic and natural to your language.
{{draft task}}In [[Remote agent]], a component is described that marshals commands and events between a stream and a program that issues commands and processes the resulting events. Using the protocol definition described there, build this component in a fashion idiomatic and natural to your language.

=={{header|Tcl}}==
{{works with|Tcl|8.6}}
<lang tcl>package require Tcl 8.6

oo::class create AgentAPI {
variable sock events sectorColor ballColor
constructor {host port} {
set sock [socket $host $port]
fconfigure $sock -buffering none -translation binary -encoding ascii \
-blocking 0
# Temporary hack
interp alias {} yieldto {} ::tcl::unsupported::yieldTo
coroutine ReaderCoroutine my ReadLoop
}
destructor {
if {[llength [info command ReaderCoroutine]]} {
rename ReaderCoroutine {}
}
if {[llength [info command AgentCoroutine]]} {
rename AgentCoroutine {}
}
if {$sock ne ""} {
catch {close $sock}
}
}
method Log message {
}

# Commands
method ForwardStep {} {
my Log "action: forward"
puts -nonewline $sock "^"
my ProcessEvents [yield]
}
method TurnRight {} {
my Log "action: turn right"
puts -nonewline $sock ">"
my ProcessEvents [yield]
}
method TurnLeft {} {
my Log "action: turn left"
puts -nonewline $sock "<"
my ProcessEvents [yield]
}
method GetBall {} {
my Log "action: get ball"
puts -nonewline $sock "@"
my ProcessEvents [yield]
}
method DropBall {} {
my Log "action: drop ball"
puts -nonewline $sock "!"
my ProcessEvents [yield]
}
method ProcessEvents {events} {
set sectorColor {}
set ballColor {}
set err {}
set done 0
foreach e $events {
my Log "event: $e"
switch [lindex $e 0] {
sector {set sectorColor [lindex $e 1]}
ball {set ballColor [lindex $e 1]}
error {set err [lindex $e 1]}
gameOver {set done 1}
}
}
if {$err ne ""} {throw $err "can't do that: $err"}
return $done
}

# Event demux
method ReadLoop {} {
puts -nonewline $sock "A"
fileevent $sock readable [info coroutine]
while 1 {
yield
if {[read $sock 1] eq "A"} break
}
try {
coroutine AgentCoroutine my Behavior
while 1 {
yield
set ch [read $sock 1]
switch $ch {
"." {
# Stop - end of events from move
set e $events
set events {}
yieldto AgentCoroutine $e
if {"gameOver" in $e} break
}
"+" {lappend events gameOver}
"R" {lappend events {sector red}}
"G" {lappend events {sector green}}
"Y" {lappend events {sector yellow}}
"B" {lappend events {sector blue}}
"r" {lappend events {ball red}}
"g" {lappend events {ball green}}
"y" {lappend events {ball yellow}}
"b" {lappend events {ball blue}}
"|" {lappend events {error bumpedWall}}
"S" {lappend events {error sectorFull}}
"A" {lappend events {error agentFull}}
"s" {lappend events {error sectorEmpty}}
"a" {lappend events {error agentEmpty}}
}
}
} finally {
close $sock
set sock ""
}
}

method Behavior {} {
error "method not implemented"
}
}</lang>
Sample agent (''not'' a good player of the game; just to show how to program to the interface):
<lang tcl>oo::class create Agent {
superclass AgentAPI
variable sectorColor ballColor
method Behavior {} {
set ball ""
while 1 {
try {
while {rand() < 0.5} {
my ForwardStep
if {
$ball eq ""
&& $ballColor ne ""
&& $ballColor ne $sectorColor
} then {
set ball [set ballTarget $ballColor]
my GetBall
} elseif {$ball ne "" && $ballTarget eq $sectorColor} {
try {
if {[my DropBall]} {
break
}
set ball ""
} trap sectorFull {} {
# Target square full; drop this ball anywhere
set ballTarget ""
}
}
}
if {rand() < 0.5} {
my TurnLeft
} else {
my TurnRight
}
} trap bumpedWall {} {}
}
set ::wonGame ok
}
}

Agent new
vwait wonGame</lang>

Revision as of 18:36, 27 December 2010

Remote agent/Agent interface 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.

In Remote agent, a component is described that marshals commands and events between a stream and a program that issues commands and processes the resulting events. Using the protocol definition described there, build this component in a fashion idiomatic and natural to your language.

Tcl

Works with: Tcl version 8.6

<lang tcl>package require Tcl 8.6

oo::class create AgentAPI {

   variable sock events sectorColor ballColor
   constructor {host port} {

set sock [socket $host $port] fconfigure $sock -buffering none -translation binary -encoding ascii \ -blocking 0 # Temporary hack interp alias {} yieldto {} ::tcl::unsupported::yieldTo coroutine ReaderCoroutine my ReadLoop

   }
   destructor {

if {[llength [info command ReaderCoroutine]]} { rename ReaderCoroutine {} } if {[llength [info command AgentCoroutine]]} { rename AgentCoroutine {} } if {$sock ne ""} { catch {close $sock} }

   }
   method Log message {
   }
   # Commands
   method ForwardStep {} {

my Log "action: forward" puts -nonewline $sock "^" my ProcessEvents [yield]

   }
   method TurnRight {} {

my Log "action: turn right" puts -nonewline $sock ">" my ProcessEvents [yield]

   }
   method TurnLeft {} {

my Log "action: turn left" puts -nonewline $sock "<" my ProcessEvents [yield]

   }
   method GetBall {} {

my Log "action: get ball" puts -nonewline $sock "@" my ProcessEvents [yield]

   }
   method DropBall {} {

my Log "action: drop ball" puts -nonewline $sock "!" my ProcessEvents [yield]

   }
   method ProcessEvents {events} {

set sectorColor {} set ballColor {} set err {} set done 0 foreach e $events { my Log "event: $e" switch [lindex $e 0] { sector {set sectorColor [lindex $e 1]} ball {set ballColor [lindex $e 1]} error {set err [lindex $e 1]} gameOver {set done 1} } } if {$err ne ""} {throw $err "can't do that: $err"} return $done

   }
   # Event demux
   method ReadLoop {} {

puts -nonewline $sock "A" fileevent $sock readable [info coroutine] while 1 { yield if {[read $sock 1] eq "A"} break } try { coroutine AgentCoroutine my Behavior while 1 { yield set ch [read $sock 1] switch $ch { "." { # Stop - end of events from move set e $events set events {} yieldto AgentCoroutine $e if {"gameOver" in $e} break } "+" {lappend events gameOver} "R" {lappend events {sector red}} "G" {lappend events {sector green}} "Y" {lappend events {sector yellow}} "B" {lappend events {sector blue}} "r" {lappend events {ball red}} "g" {lappend events {ball green}} "y" {lappend events {ball yellow}} "b" {lappend events {ball blue}} "|" {lappend events {error bumpedWall}} "S" {lappend events {error sectorFull}} "A" {lappend events {error agentFull}} "s" {lappend events {error sectorEmpty}} "a" {lappend events {error agentEmpty}} } } } finally { close $sock set sock "" }

   }
   method Behavior {} {

error "method not implemented"

   }

}</lang> Sample agent (not a good player of the game; just to show how to program to the interface): <lang tcl>oo::class create Agent {

   superclass AgentAPI
   variable sectorColor ballColor
   method Behavior {} {

set ball "" while 1 { try { while {rand() < 0.5} { my ForwardStep if { $ball eq "" && $ballColor ne "" && $ballColor ne $sectorColor } then { set ball [set ballTarget $ballColor] my GetBall } elseif {$ball ne "" && $ballTarget eq $sectorColor} { try { if {[my DropBall]} { break } set ball "" } trap sectorFull {} { # Target square full; drop this ball anywhere set ballTarget "" } } } if {rand() < 0.5} { my TurnLeft } else { my TurnRight } } trap bumpedWall {} {} } set ::wonGame ok

   }

}

Agent new vwait wonGame</lang>