Remote agent/Agent interface: Difference between revisions

→‎Tcl: Added implementation + demonstration of how to use the interface
(Agent interface task part.)
 
(→‎Tcl: Added implementation + demonstration of how to use the interface)
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.
 
=={{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>
Anonymous user