Remote agent/Agent interface: Difference between revisions
(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
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
<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>