Part II. C++ Case Studies
In this part
-
we are going to simplify the communication protocol of the 2D RCSS
-
then we will develop our own client agent that uses this simplified protocol and is based on the rcssserver (15.1.0) and its sample client.
-
finally, the modifications of rcssserver and rcsslogplayer will be shown that allow us to draw equipotential surfaces of the Brillinger potential.
Chapter 5. A simplified protocol of 2D RCSS
1. Emasculation of the AI-based simulation model of RCSS
In the FerSML (Footballer and Football Simulation Markup Language) project, at first our interest was only to develop a simulation based decision making support expert system for professional football (soccer). But of course such a development is not possible without supporting the real football teams and using suitable analytical tools to observe players of these cooperative teams. The organisation of this work is already under way in the framework of an industrial research and development project.
Our motivation comes from our former experience in mobile soccer gaming [FERSML] then we have concentrated only on the football played in reality. At that time, using the robocup simulation environment hadn't even occurred to us, because the robot soccer is purely artificial intelligence. And because in our case, in contrast a player or in the FerSML's terminology an avatar was considered to be a given and finished entity as a complete and perfect footballer in the simulation, accordingly we didn't want to build the abstraction of the players from scratch and step by step to develop their cognitive skills required for playing football. For example, to illustrate our approach, in the FerSML simulations a player knows its own position with any degree of accuracy. The avatars are (trivially) fully aware of the meaning of the position of themselves and of all other players or the parts of the field of play. By contrast, in RCSS simulations an agent has to build positioning information for itself.
But meanwhile, waiting for the start of the mentioned research and development project, the question arose whether RCSS tools may be applied to sport science purposes of FerSML platform, or more exactly, whether the rcssserver could possibly be used for support the FerSML simulations. However, even in that case, the classical RCSS client agents would not be required because the rcssserver would be modified in order to enable working with clients defined at a higher abstraction level. That is, for example, the FerSML clients would be able to access the all data of the rcssserver directly and they could communicate with each other without any restrictions during simulation. At this moment, the usage of RCSS software tools for purposes of the FerSML project is an open question.
1.1. Introducing a new positioning command for RCSS client protocol
In this case study we investigate the possibility of modifying RCSS protocol to be able to be used for sport scientific purposes [SRCSS].
We introduce a new client command (pos X Y power) to control the agents. Here (X, Y) is the position on the field where the player will move. The parameter power is the same as the parameter of the original (dash power) command. With this lucky choice therefore the implementation of the new pos command may be built on the implementation of the dash command.
1.1.1. Testing of the newly introduced command
For testing we modify the team called Debreceni Hivatásos FC++. The newly added beforeKickOffwithPos function will be called from the control POSIX thread:
static void * prog1Thread(void *
client) { Client * thisclient = (Client *) client; char buf[1024];
usleep(100*1000); for (;;) { usleep(100*1000); switch
(thisclient->bl.get_play_mode()) { case before_kick_off:
beforeKickOff(thisclient); break; case play_on: case kick_off_l:
case kick_off_r: //playOn(thisclient);
beforeKickOffwithPos(thisclient); break; } } // for (;;) return 0;
}
The beforeKickOffwithPos defines a line-up and the players will move towards the positions defined in this line-up.
static void
beforeKickOffwithPos(Client * thisclient) { char buf[1024]; //
középkezdési felállás static int formation[][2] = { // Goalie,
kapus {-51, 0}, // Attackers, támadók {-4, 10}, {-1, 1}, {-3,
-11}, // Midfielders, középpályások {-18, -16}, {-17, 2}, {-18,
17}, // Defenders, védők {-35, -19}, {-33, -10}, {-34, 12}, {-35,
24} }; int squad_number = thisclient->bl.get_squad_number() -1;
std::snprintf(buf, 64, "(pos %d %d 40)\0",
formation[squad_number][0], formation[squad_number][1]);
thisclient->sndCmd(buf);
In parallel we modified the original beforeKickOff line-up in order to allow easier interpretation: now players stand in a line.
static void beforeKickOff(Client *
thisclient) { char buf[1024]; // középkezdési felállás static int
formation[][2] = { // Goalie, kapus {-10, 0}, // Attackers,
támadók {-12, 0}, {-14, 0}, {-16, 0}, // Midfielders,
középpályások {-18, 0}, {-20, 0}, {-22, 0}, // Defenders, védők
{-24, 0}, {-26, 0}, {-28, 0}, {-30, 0} }; // minden játékos a
saját pozíciójába a középkezdéskor int squad_number =
thisclient->bl.get_squad_number() -1; std::snprintf(buf, 64,
"(move %d %d)\0", formation[squad_number][0],
formation[squad_number][1]);
thisclient->sndCmd(buf);
In the source code of rcssserver, the newly introduced pos command is developed by using the existing implementation of dash command. First, we simply calculate the angle of target position then the agent will be dashed to the calculated direction. Making this modification on the server side will not affect the existing client agents because the pos command will be received by the server. However, we have weaved the agent position into the server's response. In most cases it does not cause any problems, but to be on the safe side, this behavior can be switched on using the server's command line argument rcssserver server::light_response=true and it is switched off in default:
[norbert@matrica rcssserver-15.1.0.light1]$ src/rcssserver
rcssserver-15.1.0.light1 Copyright (C) 1995, 1996, 1997, 1998,
1999 Electrotechnical Laboratory. 2000 - 2012 RoboCup Soccer
Simulator Maintenance Group. Simulator Random Seed: 1341319832
CSVSaver: Ready STDOutSaver: Ready Using simulator's random seed
as Hetero Player Seed: 1341319832 wind factor: rand: 0.000000,
vector: (0.000000, 0.000000) Hit CTRL-C to exit Light response:
false
Figure 5.1. The LightFC++ team assembles before kick off using the move command.
Figure 5.2. After kick off the players move using the pos command.
The continuous movement of the players is well observed in the video playback at URL http://youtu.be/ZoANLujlt1A, (
)
Download of the simplified rcssserver and the team Light FC++
http://www.inf.unideb.hu/~nbatfai/rcssserver-15.1.0.light4.tar.bz2.
1.1.2. The response of the simplified server
We have already mentioned that modified server's response can be switched on or switched off by using the server::light_response parameter. If it is set to true then sendLight function will print the agent's own position to the beginning of the see command. This function is a newly added one to src/visualsenderplayer.cpp source in the rcssserver's package.
// light if
(ServerParam::instance().lightResponse()) sendLight();
sendFlags(); sendBalls(); sendPlayers(); sendLines();
serializer().serializeVisualEnd( transport() ); transport()
<< std::ends << std::flush; } void
VisualSenderPlayerV1::sendLight() {
serializer().serializeVisualObject( transport(), "light",
self().pos().x, self().pos().y); }
Now let's see how the see sent to clients looks.
(see 667 (light -35.0361 -19.0086) ((f c) 40 28) ((f c t)
38.1 -23) ((f r t) 89.1 -10) ((f r b) 102.5 31) ((f g r b) 90.9
17) ((g r) 90 12) ((f g r t) 88.2 8) ((f p r b) 81.5 29) ((f p r
c) 73.7 15) ((f p r t) 70.8 -1) ((F) 1.5 -130) ((f t 0) 40.4 -30)
((f t r 10) 49.4 -24) ((f t r 20) 58.6 -20) ((f t r 30) 68 -17)
((f t r 40) 77.5 -15) ((f t r 50) 87.4 -13) ((f t l 10) 32.1 -39 0
0.1) ((f b r 30) 87.4 42) ((f b r 40) 94.6 38) ((f b r 50) 102.5
34) ((f r 0) 94.6 12) ((f r t 10) 92.8 6) ((f r t 20) 92.8 -1) ((f
r t 30) 92.8 -7) ((f r b 10) 96.5 17) ((f r b 20) 100.5 23) ((f r
b 30) 104.6 28) ((b) 40.4 28) ((p "LightFC++") 40.4 43) ((p
"LightFC++") 40.4 30) ((p "LightFC++") 33.1 14) ((p "LightFC++" 5)
18.2 10 0 0 0 0) ((l r) 87.4 90))
2. The team called Debrecen Great Forest FC++
The team Debrecen Great Forest FC++ is further developed from the team Debreceni Hivatásos FC++ that was developed in the book [PARP]. The interesting thing about Debrecen Great Forest FC++ is that it has already used the newly introduced pos command.
Let's get started with robot soccer
http://youtu.be/U_9G6BAgKr0,
.
If we compare the lobogofcpp.h source files of Debrecen Great Forest FC++ and Debreceni Hivatásos FC++ we will see the that the former one is shorter than the latter one. Accordingly, the lexer has also changed as it is shown in the next code snippet from the point of view of the ball:
{BALL}{WS}{FLOAT}{WS}{FLOAT} {
std::sscanf(yytext, "((b) %f %f", &dist_buffer, &ang_buffer);
ball.setDistAng(time, dist_buffer, ang_buffer); }
The lexer had to be extended with further player modes, for example the following referee's messages are received by the clients:
enum RefereePlayMode { before_kick_off,
play_on, half_time, drop_ball, kick_off_r, kick_off_l, corner_kick_r,
corner_kick_l, free_kick_l, free_kick_r, kick_in_l, kick_in_r, goal_l,
goal_r, free_kick_fault_l, free_kick_fault_r, offside_l, offside_r
};
Our lecture notes focus on the corner kick and the throw-in play modes. The kick off and the ball in play modes have already been processed in the previous versions of the teams, see the book [PROP]. The kick off is handled by the beforeKickOff, the ball in play and the newly handled modes are processed by the function playOn:
switch
(thisclient->bl.get_play_mode()) { case half_time: case goal_l:
case goal_r: case before_kick_off: beforeKickOff(thisclient);
//beforeKickOff_light_testing(thisclient); break; case play_on: case
kick_off_l: case kick_off_r: thisclient->bl.nof_kickin_quantums =
0; playOn(thisclient); //playOn_light_testing(thisclient); break; case
kick_in_l: if (thisclient->bl.get_lr() == 'l') kickIn(thisclient);
else playOn(thisclient); break; case kick_in_r: if
(thisclient->bl.get_lr() == 'r') kickIn(thisclient); else
playOn(thisclient); break; case corner_kick_r: if
(thisclient->bl.get_lr() == 'r') cornerKickAtt(thisclient); else
cornerKickDef(thisclient); break; case corner_kick_l: if
(thisclient->bl.get_lr() == 'l') cornerKickAtt(thisclient); else
cornerKickDef(thisclient); break; case free_kick_l: case free_kick_r:
case free_kick_fault_l: case free_kick_fault_r: case offside_l: case
offside_r: case drop_ball: playOn(thisclient); break;
}
In this snippet, the commented out beforeKickOff_light_testing was used only to test the simplification. At taking a throw-in (in the case of kick_in_l and kick_in_r) we distinguish the team which throws in the ball. And finally the attacker and defender teams are treated separately at corner kicks.
2.1. The implementation of the throw-in
We follow the solution shown in the book [MIRC], where we distiguished the moving into the position to make the throw-in and the throw-in itself. The latter activity includes the looking out for teammates to whom the ball can be passed. These activities are not divided into various functions but we use the following kickIn function:
static void kickIn(Client *
thisclient) { // http://youtu.be/HiaPWqSzYxk char buf[1024]; int
time = thisclient->bl.get_time(); int squad_number =
thisclient->bl.get_squad_number() -1; int lr =
thisclient->bl.get_lr(); // ha látja a lasztit if
(thisclient->bl.get_see_ball()) { // kinek kell majd dobni int
to; thisclient->coach.set_formation(Formations::F_4_4_2_F); int
tx =
thisclient->coach.get_formation().get_formation_x(squad_number,
lr); int ty =
thisclient->coach.get_formation().get_formation_y(squad_number);
if (thisclient->bl.get_ball_dist() < .8) { if ((1)(to =
thisclient->bl.pass_to_farthes(3)) != -1) { std::snprintf(buf,
64, "(kick %d %f)\0",
thisclient->bl.tavhozEro(thisclient->bl.get_own_player(to).getDist()),
thisclient->bl.get_own_player(to).getAng());
thisclient->sndCmd(buf); std::cout << time << " "
<< thisclient->bl.get_squad_number()<< " passz
(bedobas) " << to+1 << std::endl; } else { // ha nem
lát társat if (++thisclient->bl.nof_kickin_quantums > 10) {
// ha többen fogognak éppen nem látva egymást, (2)akkor ne a
játékvezetői beavatkozásig tegyék std::snprintf(2)(buf, 64, "(kick %d
%f)\0", 20, thisclient->bl.get_ball().getAng());
thisclient->sndCmd(buf); std::cout <<
thisclient->bl.get_squad_number()<< " vissza pocc a
palyara " << std::endl; } else {
thisclient->sndCmd("(turn 25)\0"); std::cout <<
thisclient->bl.get_squad_number()<< " kinek kene dobni?
..." << thisclient->bl.nof_kickin_quantums << (2)
std::endl; } } // megy a labdára innen } else if
(std::abs(thisclient->bl.get_ball_ang()) > 20.0) {
std::snprintf(buf, 64, "(turn %f)\0",
thisclient->bl.get_ball_ang()); thisclient->sndCmd(buf);
std::cout << thisclient->bl.get_squad_number()<<
"turn" << thisclient->bl.get_ball_ang() <<
std::endl; } else if (thisclient->bl.get_ball_dist() < 30.0
&& thisclient->bl.pass_to_farthes(2)==-1) { // 30-ról
is sprintel bedobni, ha nincs közelebbi társ
thisclient->sndCmd("(dash 100)"); std::cout <<
thisclient->bl.get_squad_number()<< " megyek dobni 100"
<< std::endl; } else if (thisclient->bl.get_ball_dist()
< 40.0 && ((to=thisclient->bl.nof_seen_teammates())
< 3)) { // 40-ról is jön bedobni, ha esetleg lá(2)t is társakat
(mert az előző ág nem teljesült) std::snprintf(buf, 64, "(dash
%f)\0", 100.0/(to + 1.0)); thisclient->sndCmd(buf); std::cout
<< thisclient->bl.get_squad_number()<< " megyUNK
dobni " << std::endl; } else { std::snprintf(buf, 64, "(pos
%d %d 30)\0", tx, ty); thisclient->sndCmd(buf); } } else { //
ha nem látja a lasztit thisclient->sndCmd("(tur(2)n 40)\0");
std::cout << thisclient->bl.get_squad_number()<<
"meccs van? ... (dobas)" << std::endl; } }
-
If an agent can see the ball we will investigate its distance from the ball
-
then the following situations will be investigated:
-
Is the ball close enough to kick it?
-
If yes, then, using the pass_to_farthes function, the agent will ask: whom should be passed to?
-
If there are no suitable teammates, the thrower will kick the ball or turn 25 degrees to look for suitable teammates depending on whether this situation has already happened more than 10 times.
-
Returning to the investigation of the distance of the ball, if the agent can see the ball under an angle smaller than 20 degrees, it will turn in order to try to correct the angle to 0.
-
In the same indentation level if the ball's distance is less than 30 meters and the player is nearest to the ball, the player will sprint to take the throw-in.
-
If none of the above conditions are met, the agent will move towards its tactical position (tx, ty).
-
And finally, if the agent cannot see the ball, it will search the ball, to be more precise, it will make a 40 degrees turn.
2.1.1. Testing the throw-in
We have made a video on testing that can be seen at http://youtu.be/HiaPWqSzYxk,
.
Using screenshots we emphasize some moments in order to better understand how the previous code snippet works. (These pictures are made independently from the video.)
Figure 5.3. Testing the throw-in: player 11 kicks the ball across the touch line.
The next code snippet moves the player towards the ball .
} else if
(thisclient->bl.get_ball_dist() < 40.0 &&
((to=thisclient->bl.nof_seen_teammates()) < 3)) { // 40-ról
is jön bedobni, ha esetleg lát is társakat (mert az előző ág nem
teljesült) std::snprintf(buf, 64, "(dash %f)\0", 100.0/(to +
1.0)); thisclient->sndCmd(buf); std::cout <<
thisclient->bl.get_squad_number()<< " megyUNK dobni "
<< std::endl;
Figure 5.4. Testing of the throw-in: player 4 starts to move towards the ball.
After some simulation cycles the player 4 will be closer to the ball than 30 meters.
} else if
(thisclient->bl.get_ball_dist() < 30.0 &&
thisclient->bl.pass_to_farthes(2)==-1) { // 30-ról is sprintel
bedobni, ha nincs közelebbi társ thisclient->sndCmd("(dash
100)"); std::cout <<
thisclient->bl.get_squad_number()<< " megyek dobni 100"
<< std::endl;
Figure 5.5. Testing the throw-in: player 4 is closer than 30 meters.
When the player agent reaches the ball, it will turn in order to see teammates who are available for receiving the ball.
Figure 5.6. Testing of the throw-in: player 4 has just arrived to the ball.
The player 4 has found player 3 who is available for receiving the ball.
if
(thisclient->bl.get_ball_dist() < .8) { if ((to =
thisclient->bl.pass_to_farthes(3)) != -1) { std::snprintf(buf,
64, "(kick %d %f)\0",
thisclient->bl.tavhozEro(thisclient->bl.get_own_player(to).getDist()),
thisclient->bl.get_own_player(to).getAng());
thisclient->sndCmd(buf); std::cout << time << " "
<< thisclient->bl.get_squad_number()<< " passz
(bedobas) " << to+1 << std::endl;
Figure 5.7. Testing of the throw-in: player 4 passes the ball to player 3.
Figure 5.8. Testing the throw-in: the ball is moving towards player 3.
2.2. The introduction of the tactical lineups
The Debrecen Great Forest FC++'s main new feature is the introduction of the tactical lineups into the agents. The lineups are embedded in the Coach class.
class Coach { public: Coach(int formi
= 0):formi(formi) { if (formi >= Formations::NOF || formi <0)
formi = 0; formations = new Formation[Formations::NOF] { // (a +--os
megadásokkal már tisztára FerSML feeling) // 4_3_3 h {-51, 0, // att
-4, 10, -1, 0, -3, -11, // mid -18, -16, -17, 2, -18, 17, // def
-35, -19, -33, -10, -34, 12, -35, 24},
For illustrative purposes we use two lineups, these are the 4-4-2 and 4-3-3 soccer formations.
class Formations { public: static int
const F_4_3_3_H = 0; static int const F_4_3_3_F = 1; static int
const F_4_4_2_H = 2; static int const F_4_4_2_F = 3; static int
const F_CORNER_ATT = 4; static int const F_CORNER_DEF = 5; // number
of all formations static int const NOF = F_CORNER_DEF+1;
};
Figure 5.9. The 4-4-2 formation.
The other two formations control the positioning of the players at corner kicks.
Figure 5.10. Corner kick formations.
Example 5.1. Placing a player beside a goalpost
Modify the defensive formation F_CORNER_DEF so that a player will stand beside a goalpost.
2.2.1. The implementation of the corner kick
Taking and defending a corner have been implemented in two different ways. The organization of the attackers' source code is similar to what was used in the implementation of the throw-in. But in the case of the corner kicking there is a distinguished player who will be taking the corner kick. This player will be player 4 in default:
static void cornerKickAtt(Client *
thisclient) { // http://youtu.be/93F43ppEQ2g char buf[1024]; int
time = thisclient->bl.get_time(); int squad_number =
thisclient->bl.get_squad_number() -1; int lr =
thisclient->bl.get_lr();
thisclient->coach.set_formation(Formations::F_CORNER_ATT); int
tx =
thisclient->coach.get_formation().get_formation_x(squad_number,
lr); int ty =
thisclient->coach.get_formation().get_formation_y(squad_number);
SeenFlag & sf_opp_gt =
(lr=='l')?thisclient->bl.get_flag(Flag::GRT):thisclient->bl.get_flag(Flag::GLT);
SeenFlag & sf_opp_gb =
(lr=='l')?thisclient->bl.get_flag(Flag::GRB):thisclient->bl.get_flag(Flag::GLB);
// ha látja a lasztit if (thisclient->bl.get_see_ball()) { if
(thisclient->bl.get_ball_dist() < .8) { // ha már ott van a
lasztinál, ha látja a kaput, elvégzi a szögletet: if (time -
sf_opp_gt.get_time_stamp() < 2) { std::snprintf(buf, 64, "(kick
%d %f)\0", 100, sf_opp_gt.getAng()); thisclient->sndCmd(buf);
std::cout << time << " " <<
thisclient->bl.get_squad_number()<< " berug (szoglet) "
<< std::endl; } else if (time - sf_opp_gb.get_time_stamp()
< 2) { std::snprintf(buf, 64, "(kick %d %f)\0", 100,
sf_opp_gb.getAng()); thisclient->sndCmd(buf); std::cout
<< time << " " <<
thisclient->bl.get_squad_number()<< " berug (szoglet) "
<< std::endl; } else { // ha nem látja a kaput
thisclient->sndCmd("(turn 25)\0"); std::cout <<
thisclient->bl.get_squad_number()<< " hol a kapu? ..."
<< std::endl; } // megy a labdára innen } else if
(std::abs(thisclient->bl.get_ball_ang()) > 20.0) {
std::snprintf(buf, 64, "(turn %f)\0",
thisclient->bl.get_ball_ang()); thisclient->sndCmd(buf);
std::cout << thisclient->bl.get_squad_number()<<
"turn" << thisclient->bl.get_ball_ang() <<
std::endl; } else if (thisclient->bl.get_ball_dist() < 30.0
&& thisclient->bl.pass_to_farthes(2)==-1) { // 30-ról
is sprintel bedobni, ha nincs közelebbi társ
thisclient->sndCmd("(dash 100)"); std::cout <<
thisclient->bl.get_squad_number()<< " megyek dobni 100"
<< std::endl; } else if (squad_number == 3) { // a kijelölt
játékos (ez tk. a 4-es player) megy elvégezni
thisclient->sndCmd("(dash 100)"); std::cout <<
thisclient->bl.get_squad_number()<< " kijeloltkent megyek
dobni 100" << std::endl; } else { // többiek (akik nem
mennek a labdára elvégezni) helyezkednek a szöglethez adott
felállás szerint std::snprintf(buf, 64, "(pos %d %d 90)\0", tx,
ty); thisclient->sndCmd(buf); } } else { // ha nem látja a
lasztit thisclient->sndCmd("(turn 40)\0"); std::cout <<
thisclient->bl.get_squad_number()<< "meccs van? ...
(szoglet)" << std::endl; } }
The defending is organized much more simply:
static void cornerKickDef(Client *
thisclient) { // http://youtu.be/93F43ppEQ2g char buf[1024]; int
time = thisclient->bl.get_time(); int squad_number =
thisclient->bl.get_squad_number() -1; int lr =
thisclient->bl.get_lr();
thisclient->coach.set_formation(Formations::F_CORNER_DEF); int
tx =
thisclient->coach.get_formation().get_formation_x(squad_number,
lr); int ty =
thisclient->coach.get_formation().get_formation_y(squad_number);
// ha látja a lasztit if (thisclient->bl.get_see_ball()) {
std::snprintf(buf, 64, "(pos %d %d 85)\0", tx, ty);
thisclient->sndCmd(buf); } else { // ha nem látja a lasztit
thisclient->sndCmd("(turn 40)\0"); std::cout <<
thisclient->bl.get_squad_number()<< "meccs van? ...
(szoglet)" << std::endl; } }
2.2.1.1. Testing the corner kick
We have made a video on testing that can be seen at http://youtu.be/93F43ppEQ2g,
.
2.2.1.2. The evaluation of the team Debrecen Great Forest FC++
We cannot say that this team is able to play the soccer game itself. However the Debrecen Great Forest FC++ has already handled most of the play modes. The role of this team is merely to be used as an important step in developing the next team called Debrecen Deep Forest FC++ that will win agains Debrecen Great Forest FC++.
Downloading the Debrecen Great Forest
rcssserver-15.1.0.light4.gf.tar.bz2.
Example 5.2. Free kicks
Following the implementations of the throw-in or the corner kick, develop your own implementation for the missing play modes like the free kick.
3. The team called Debrecen Deep Forest FC++
The team Debrecen Deep Forest FC++ is further developed from the team Debrecen Great Forest FC++. We focus on the implementation of the playOn function.
We do not make major changes, but make fine-tuning adjustments in the code of Debrecen Great Forest FC++:
-
The goals scored by the Debrecen Great Forest FC++ are typically own goals or accidental goals due to the fact that this team cannon play organized attacking or defending football. The players should be positioned higher up on the pitch in order to improve the team's play. Therefore we introduce that the players are able to pass only forward.
-
The main cause of the own goals is a slide tackle that is done in the wrong direction. Therefore we impove the angle for slide tackles.
-
We modify the method of gaining the ball.
For example, as the following two figures show, player 3 and player 6 should go to the ball, but they do not do it because we use the method introduced above for the throw-in and the corner kick: the player agent will only go to the ball if it cannot see the teammates.
Figure 5.11. Player 3 and player 6 should go to the ball.
Now an opposing player gains possession of the ball, therefore we will modify the agent: if the ball can be seen closer than the teammates, the agent will also go to the ball.
Figure 5.12. An opposing player gains possession of the ball.
-
Like in the cases of the throw-in and the corner kick, the player possessing the ball will turn around in a circle to see where the teammates are.
-
We have also made further small improvements, for example the goalkeeper agent does not run out to a distance of 30 meters from its goal.
The source code of the improvements are the following:
static void playOn(Client * thisclient)
{ char buf[1024]; int time = thisclient->bl.get_time(); int
squad_number = thisclient->bl.get_squad_number() -1; int lr =
thisclient->bl.get_lr(); // egész pályás felállásba kapcsol
(középkezdéskor még fél pályás volt, most átmegy "támadásba")
thisclient->coach.set_formation(Formations::F_4_3_3_F); // mint a
FerSML-ben a (celx, cely) ennek felel meg most intuíciusan a
t(arget)x, t(arget)x int tx =
thisclient->coach.get_formation().get_formation_x(squad_number,
lr); int ty =
thisclient->coach.get_formation().get_formation_y(squad_number); //
ha látja a lasztit if (thisclient->bl.get_see_ball()) { int to =
thisclient->bl.pass_to_nearest(2); int pd =
(to!=-1)?thisclient->bl.get_own_player(to).getDist():0; // és olyan
közel, hogy meg tudja rúgni if (squad_number == 0 &&
thisclient->bl.get_ball_dist() < 1.2) { std::snprintf(buf, 64,
"(catch %f)\0", thisclient->bl.get_ball_ang());
thisclient->sndCmd(buf); // std::cout << " kapus bravur "
<< std::endl; } else if (thisclient->bl.get_ball_dist() <
.8) { //std::cout <<
thisclient->bl.get_squad_number()<< " < .8 " <<
std::endl; // akkor // esetleg ide passzol majd int pass_to; // az
ellen kapuját SeenFlag & sf_opp =
(lr=='l')?thisclient->bl.get_flag(Flag::GR):thisclient->bl.get_flag(Flag::GL);
// a sajátját SeenFlag & sf_own =
(lr=='l')?thisclient->bl.get_flag(Flag::GL):thisclient->bl.get_flag(Flag::GR);
// látta mostanság if (time - sf_opp.get_time_stamp() < 2 // és
elég közel van (30m) && sf_opp.getDist() < 30.0) { // felé
rúgja ha látja kick(thisclient, 100, sf_opp.getAng()); std::cout
<< thisclient->bl.get_squad_number()<< " kapura lo "
<< std::endl; // ha nincs elég közel, akkor próbál passzolni }
else if ((pass_to = thisclient->bl.pass_to_farthest_fwd()) != -1
&& (time - sf_own.get_time_stamp() > 3)) { kick(thisclient,
thisclient->bl.tavhozEro(thisclient->bl.get_own_player(pass_to).getDist()),
thisclient->bl.get_own_player(pass_to).getAng() ); // ha nem tud
passzolni és közel a saját kapu, akkor (feltéve, hogy bal oldali a
saját kapu) } else if (time - sf_own.get_time_stamp() < 1 // és
elég közel van (25m) && sf_own.getDist() < 16.0) { // ha
azt nem látja, akkor becsúszik kick(thisclient, 100, 180 +
sf_own.getAng()); std::cout <<
thisclient->bl.get_squad_number()<< " becsuszik " <<
std::endl; } else { if (++thisclient->bl.nof_possessing_quantums
< 7) { thisclient->sndCmd("(turn 30)\0"); std::cout <<
thisclient->bl.get_squad_number()<< " turn for finding
targets " << std::endl; } else { kick(thisclient, 10, 20);
std::cout << thisclient->bl.get_squad_number()<< " kis
kick " << std::endl; } } } else if
(std::abs(thisclient->bl.get_ball_ang()) > 20.0) {
std::snprintf(buf, 64, "(turn %f)\0",
thisclient->bl.get_ball_ang()); thisclient->sndCmd(buf); //
std::cout << thisclient->bl.get_squad_number()<< "turn"
<< thisclient->bl.get_ball_ang() << std::endl; } else
if (squad_number != 0 && thisclient->bl.get_ball_dist()
< 40.0 && to == -1) { // legyen agresszívabb a
labdaszerzés: 40-ről is sprintel bedobni, ha nincs közelebbi társ
dash_to_ball_100(thisclient, thisclient->bl.get_ball_dist());
//std::cout << thisclient->bl.get_squad_number()<< "
egyedul megyek labdara 100" << std::endl; } else if
(squad_number > 4 && thisclient->bl.get_ball_dist() <
30 && thisclient->bl.get_ball_dist() < pd && to
!= -1) { // legyen agresszívabb a labdaszerzés: 40-ről is sprintel
bedobni, ha nincs közelebbi társ dash_to_ball_100(thisclient,
thisclient->bl.get_ball_dist()); //std::cout <<
thisclient->bl.get_squad_number()<< " megyunk a labdara 100"
<< std::endl; } else if (squad_number != 0 &&
thisclient->bl.get_ball_dist() < 16.0 &&
(thisclient->bl.nof_seen_teammates()) < 1) { // 40-ról is jön
bedobni, ha esetleg lát is társakat (mert az előző ág nem teljesült)
dash_to_ball_100(thisclient, thisclient->bl.get_ball_dist());
//std::cout << thisclient->bl.get_squad_number()<< "
megyUNK a labdara " << std::endl; } else if
(thisclient->bl.get_ball_dist() < 9.0) {
dash_to_ball_100(thisclient, thisclient->bl.get_ball_dist());
//std::cout << thisclient->bl.get_squad_number()<< "
megyUNK a labdara, aki csak latja " << std::endl; } else if
(thisclient->bl.get_ball_dist() < 30.0) { std::snprintf(buf, 64,
"(pos %d %d 50)\0", tx, ty); thisclient->sndCmd(buf); //std::cout
<< thisclient->bl.get_squad_number()<< " helyezkedik
"<< "(" << tx << ", " << ty << ")"
<< std::endl; } else { std::snprintf(buf, 64, "(pos %d %d
30)\0", tx, ty); thisclient->sndCmd(buf); //std::cout <<
thisclient->bl.get_squad_number()<< " helyezkedik "<<
"(" << tx << ", " << ty << ")" <<
std::endl; } } else { // ha nem látja a labdát // visszamegy
"védekezésbe"
thisclient->coach.set_formation(Formations::F_4_3_3_H);
thisclient->sndCmd("(turn 40)\0"); //std::cout <<
thisclient->bl.get_squad_number()<< "meccs van? ..." <<
std::endl; } }
3.1. The evaluation of the team Debrecen Deep Forest FC++
Unfortunately the above improvements do not reach the anticipated level, but the Debrecen Deep Forest FC++ can typically defeat the Debrecen Great Forest FC++ as it is shown by the next match results:
201208191102-DForestFC++_13-vs-GForestFC++_2.rcg
201208191116-GForestFC++_1-vs-DForestFC++_5.rcg
201208191128-DForestFC++_4-vs-GForestFC++_3.rcg
201208191200-DForestFC++_4-vs-GForestFC++_6.rcg
201208191212-GForestFC++_2-vs-DForestFC++_3.rcg
201208191223-DForestFC++_9-vs-GForestFC++_1.rcg
201208191235-DForestFC++_6-vs-GForestFC++_2.rcg
201208191247-GForestFC++_2-vs-DForestFC++_4.rcg
201208191301-DForestFC++_10-vs-GForestFC++_8.rcg
201208191318-DForestFC++_5-vs-GForestFC++_3.rcg
-
But then a test match was played so well that we have recorded it to a video 201208191102-DForestFCpp_13-vs-GForestFCpp_2.rcg13:2 that can be found at http://youtu.be/FOb8IQ0AF5w,
.
-
GForestFC++ - DForestFC++ 1:5
-
DForestFC++ - GForestFC++ 4:3
-
DForestFC++ - GForestFC++ 4:6
-
GForestFC++ - DForestFC++ 2:3
-
DForestFC++ - GForestFC++ 9:1
-
DForestFC++ - GForestFC++ 6:2
-
GForestFC++ - DForestFC++ 2:4
-
DForestFC++ - GForestFC++ 10:8
-
DForestFC++ - GForestFC++ 5:3
The Debrecen Deep Forest FC++ also produces unintelligible errors. For example, the players pass backward in some given situations, due to the fact that the estimated position of the seen player is so wrong that it impairs the work of the function pass_to_farthest_fwd.
Debrecen Deep Forest - HELIOS_base, 0:
Debrecen Deep Forest - HELIOS2011, 0:
Downloading the Debrecen Deep Forest FC++
rcssserver-15.1.0.light5.df.tar.bz2.
Example 5.3. Do not pass backward
Improve the code so that the passing backward should occurs as rarely as possible. But for now do not use the advantages of the simplification.
bool fwd(char
lr, float fromx) const { if (lr == 'l') { if (fromx <
this->x) return true; else return false; } else { if (fromx
> this->x) return true; else return false; } }
Example 5.4. A good starting
At kick off the positions of all players are well known. Therefore it is not too hard to program a good kick-off, do it now yourself.
Extending the simplification of the RCSS server
The Debrecen Deep Forest FC++ runs with defaults
It may be noted that the Debrecen Deep Forest FC++ uses the pos command, but neither the client agent nor the server use the light response data. To be more precise, the client agent does not use and the server does not send the light response data, the latter case can be seen in the next screen snippet:
$ src/rcssserver
rcssserver-15.1.0.light4.df Copyright (C) 1995, 1996, 1997, 1998,
1999 Electrotechnical Laboratory. 2000 - 2012 RoboCup Soccer
Simulator Maintenance Group. Simulator Random Seed: 1345375129
CSVSaver: Ready STDOutSaver: Ready Using simulator's random seed
as Hetero Player Seed: 1345375129 wind factor: rand: 0.000000,
vector: (0.000000, 0.000000) Hit CTRL-C to exit Light response:
false Light response with angle: false Light response with angles:
false
4. The team called Debrecen Round Forest FC++
Finally, to close the robot soccer examples, the Debrecen Deep Forest FC++ is further developed. The Debrecen Round Forest FC++ has already used the light response data from the simplified server. In addition, we improve the positioning of the players and introduce the usage of the online coach for this team to be developed.
4.1. The additional command line arguments of the simplified server
If it is switched on, the simplified server will send back the player agent's own position.
-
server::light_response_with_angle
If it is switched on, the simplified server will send back the player agent's own position and its own body angle.
-
server::light_response_with_angles
If it is switched on, the simplified server will send back the player agent's own position and its own body and head angles.
4.1.1. The response of the simplified server
To test the response give the commands turn_neck 20 and turn 30.
thisclient->sndCmd("(turn_neck
20)\0"); thisclient->sndCmd("(turn 30)\0"); ... std::cout
<< std::setw (6) << "squad " <<
thisclient->bl.get_squad_number() << std::setw (10)
<< " time " << thisclient->bl.get_time() <<
std::setw (5) << " x " << thisclient->bl.estx
<< std::setw (5) << " y " <<
thisclient->bl.esty << std::setw (13) << " ang
(body) " << thisclient->bl.esta * (180.0 / 3.14159265359)
<< std::setw (13) << " ang (neck) " <<
thisclient->bl.estn * (180.0 / 3.14159265359) <<
std::setw (13) << " ang (head) " <<
thisclient->bl.head_angle << std::endl;
then investigate the output:
squad 4 time 0 x -12 y -37 ang (body) 31.5529 ang (neck)
20 ang (head) 20 squad 4 time 0 x -12 y -37 ang (body) 31.5529 ang
(neck) 20 ang (head) 20 squad 4 time 0 x -12 y -37 ang (body)
31.5529 ang (neck) 20 ang (head) 20 squad 4 time 0 x -12 y -37 ang
(body) 31.5529 ang (neck) 20 ang (head) 20 squad 4 time 0 x -12 y
-37 ang (body) 31.5529 ang (neck) 20 ang (head) 20
and finally compare it to the soccerwindow2's debug information.
Figure 5.13. A portion of the soccerwindow2's log file.
4.1.2. Receiving the response of the simplified server
The light response data and the estimated data are already handled separately in the lexer class:
// from light response float x;
float y; float head_angle; // neck angle (rad) float body_angle;
// (rad) // from classical estimations float estx; // x float
esty; // y float esta; // body_angle (deg) float estn; //
head_angle (deg) (from body_sense/head_angle)
4.2. Introducing the usage of the online coach
The Debrecen Round Forest FC++ has already used the online coach. To enable this feature we need to connect the default 6002 port and communicate using the online coach's protocol [RCSSMANUAL]. Now we are going to send the Debrecen Round Forest FC++'s XPM team logo as shown by the next code snippet:
std::snprintf(buf, 512,
"(team_graphic (%d %d %s))", 0, 0, " \"8 8 1 1\" \" c None\" \" \"
\" \" \" \" \" \" \" \" \" \" \" \" \" \" ");
thisclient->sndCmd(buf); std::snprintf(buf, 512, "(team_graphic
(%d %d %s))", 1, 0, " \"8 8 5 1\" \" c None\" \". c #1F1F1A\" \"+ c
#2A2A24\" \"@ c #36362F\" \"# c #434239\" \" \" \" \" \" \" \" \" \"
\" \" @#\" \" @@@\" \" ++..\" "); thisclient->sndCmd(buf);
std::snprintf(buf, 512, "(team_graphic (%d %d %s))", 2, 0, " \"8 8 8
1\" \" c None\" \". c #2A2A24\" \"+ c #36362F\" \"@ c #434239\" \"#
c #504E44\" \"$ c #5C594E\" \"% c #666457\" \"& c #767365\" \"
\" \" $\" \" $$$\" \" @##$%\" \"+@#$$%%$\" \"@#@@##$%\"
\".@$###%&\" \"@%$$$$%&\" "); thisclient->sndCmd(buf);
std::snprintf(buf, 512, "(team_graphic (%d %d %s))", 3, 0, " \"8 8 6
1\"\" c None\"\". c #5C594E\"\"+ c #666457\"\"@ c #767365\"\"# c
#8B8778\"\"$ c #9F9B89\"\"
+@@##\"\".++@@@@@\"\"..++++@@\"\"@@@@####\"\"..++@@@@\"\"++@@####\"\"@###$$$$\"\"@###$$$$\"
"); thisclient->sndCmd(buf); std::snprintf(buf, 512,
"(team_graphic (%d %d %s))", 4, 0, " \"8 8 12 1\" \" c None\" \". c
#2A2A24\" \"+ c #36362F\" \"@ c #434239\" \"# c #504E44\" \"$ c
#5C594E\" \"% c #666457\" \"& c #767365\" \"* c #8B8778\" \"= c
#9F9B89\" \"- c #B5B29E\" \"; c #C8C6B2\" \"$# * \" \"%$@%=-**\"
\"&&&&****\" \"**======\" \"%%%%%&&*\"
\"%$#.#&*=\" \"&%%+$&=;\" \"&%%+#%*;\" ");
thisclient->sndCmd(buf); std::snprintf(buf, 512, "(team_graphic
(%d %d %s))", 5, 0, " \"8 8 5 1\" \" c None\" \". c #8B8778\" \"+ c
#9F9B89\" \"@ c #B5B29E\" \"# c #C8C6B2\" \" \" \". \" \"...+ \"
\"+...++ \" \".++@+++.\" \"+.....++\" \"@..++++.\" \"#+.+@@@@\" ");
thisclient->sndCmd(buf); std::snprintf(buf, 512, "(team_graphic
(%d %d %s))", 6, 0, " \"8 8 4 1\" \" c None\" \". c #8B8778\" \"+ c
#9F9B89\" \"@ c #B5B29E\" \" \" \" \" \" \" \" \" \" \" \"+ \" \"+++
\" \"@+.+ \" "); thisclient->sndCmd(buf); std::snprintf(buf, 512,
"(team_graphic (%d %d %s))", 7, 0, " \"8 8 1 1\" \" c None\" \" \"
\" \" \" \" \" \" \" \" \" \" \" \" \" \" ");
thisclient->sndCmd(buf);
The protocol supports only the png image format and can handle a maximum image size of 256x64. The team logo must be divided into tiles because the team_graphic command uses tiles of the size 8x8. The first two parameters of the command gives the coordinates of the given tile in the range of (0-31)x(0-7) then the third parameter is followed that gives the rows of the tile.
Example 5.5. Create the your own XPM team logo
This exercise is fully solved in Java in the book [MIRC]. All you have to do is to rewrite it into C++.
GIMP, GIMP, GIMP
Use the GIMP, it can save to XPM.
To connect the online coach we need to modify the starting script:
#!/bin/bash host=${1-localhost} portp=${2-6000}
portc=${3-6002} team=${4-RForestFC++} for ((i=1;i<12;++i)) do
src/rcsslightclient -host $host -port $portp -team $team -squad
$i& sleep 1 done src/rcsslightclient -host $host -port $portc
-team $team -squad 0& exit 0
In the window of the server we can see that the online coach has connected:
$ src/rcssserver server::light_response_with_angles=true
rcssserver-15.1.0.light5.rf Copyright (C) 1995, 1996, 1997, 1998,
1999 Electrotechnical Laboratory. 2000 - 2012 RoboCup Soccer
Simulator Maintenance Group. Simulator Random Seed: 1345710410
CSVSaver: Ready STDOutSaver: Ready Using simulator's random seed as
Hetero Player Seed: 1345710410 wind factor: rand: 0.000000, vector:
(0.000000, 0.000000) Hit CTRL-C to exit Light response: false Light
response with angle: false Light response with angles: true A new
(v15) player (RForestFC++ 1) connected. A new (v15) player
(RForestFC++ 2) connected. A new (v15) player (RForestFC++ 3)
connected. A new (v15) player (RForestFC++ 4) connected. A new (v4)
monitor connected. A new (v15) player (RForestFC++ 5) connected. A
new (v15) player (RForestFC++ 6) connected. A new (v15) player
(RForestFC++ 7) connected. A new (v4) monitor connected. A new (v15)
player (RForestFC++ 8) connected. A new (v15) player (RForestFC++ 9)
connected. A new (v15) player (RForestFC++ 10) connected. A new
(v15) player (RForestFC++ 11) connected. A new (v15) online coach
(RForestFC++) connected.
Figure 5.14. The Debrecen Round Forest FC++'s team logo in the soccerwindow2 and the rcssmonitor.
Downloading the Debrecen Round Forest FC++
rcssserver-15.1.0.light5.rf.tar.bz2.
Part III. Java Case Studies
Chapter 6. Community consciousness net
The „Community consciousness net” is only an exercise that is based on the mobile game called Hetedik Szem, in English „Seventh Eye”.
„A gépek ilyenformán szakadatlanul együttműködő egységet alkotnak, s e nagy egységen belül a nyilvántartott adatok és ellentmondások folytonos változása szükségszerűen megy végbe.”
—Wigner Jenő A tudomány növekedése - kedvező kilátások és várható veszélyek [SZIRE]
1. The Seventh Eye mobile game
The Seventh Eye is a Java ME mobile game which was released as an open source subproject of Jávácska ONE. This game was introduced in detail in the environment of the lecture notes, in Mobil programozás, Nehogy már megint a mobilod nyomkodjon Téged!http://www.inf.unideb.hu/~nbatfai/konyvek/MOBP/mobp.book.xml.pdf, [MOBP].
We are only bringing the idea of „Community consciousness net” forward. The concept of this idea is based on the Java ME MIDP Hungarian language mobile game called Hetedik Szem, or in English Seventh Eye.
1.1. The Seventh Eye and the „Community consciousness net”
This exercise is introduced on the blog of the course by the following Hungarian language posts:
-
„Minket az Isten is egymásnak teremtett”http://progpater.blog.hu/2011/04/24/tudatmintak_rendezese,
-
„Közösségi háló reloaded”http://progpater.blog.hu/2011/03/11/kozossegi_halo_reloaded.
The game Seventh Eye is „a free will probe”. The name and the idea of the game is rooted in our scientific reading experience, for example in [CSASZAR] book and the articles [VOLF] and [TCON]. The game works on a discrete time scale. It watches the player during 2048 equidistant time intervals of 100 ms. If the player pushes the fire button (it corresponds to a situation where the player deflects his finger in line with the terminology of the above mentioned papers) the digit 1 will be assigned to the corresponding time interval and otherwise the digit 0. As a result, we get a sequence of 0's and 1's of length 2048. Such sequences are referred to as mental fingerprints in the game. These mental fingerprints are compared by Ziv-Lempel-Welch (LZW) algorithm. The idea of the comparison came from the book [SZSZTEK]. The standard deviations of the lengths of the branches of the LZW tree are compared. In the game we perform hypothesis testing to assess whether the two given standard deviations are from the same distribution or not.
Example 6.1. Running the Seventh Eye on a real mobile phone
The following photos show how the game runs on a Nokia 6212 classic.
Figure 6.1. The starting icon of the Seventh Eye.
Figure 6.2. The splash screen of the Seventh Eye.
Figure 6.3. The main menu of the Seventh Eye.
Example 6.2. The client side of the „Community consciousness net”
Modify the Seventh Eye so that it will fulfil the following functions.
-
The user must be able to upload the gathered mental fingerprints to the server.
-
The upload code must be run in a separate thread.
Example 6.3. The server side of the „Community consciousness net”
Create a Java servlet that can receive and process the mental fingerprints.
-
First, develop a simple protocol for sending and receiving the mental fingerprints.
-
Then store the uploaded data in a database.
Example 6.4. A community-based exercise
In your acquaintance network,
-
record some fingerprints
-
then try to draw the community structure using graphs, where the edges represent the nearest neighbours by comparing the mental fingerprints between your acquaintances.
Example 6.5. A community portal based on the mental fingerprints
If the previous exercise is successful, it would be interesting to think about building a mental fingerprint based community portal.
Part IV. Python Case Studies
This part shows the starting steps of building an AIML (Artificial Intelligence Markup Language) based knowledge base.
Chapter 7. A virtual librarian
This exercise mainly helps students of the course called XML, HTML because the programming does not play an essential role in the building of an XML based knowledge base.
„Detective Del Spooner: Is there something you want tell me? Dr. Alfred Lanning: I'm sorry. My responses are limited. You must ask the right questions. ”
—I, Robot [IROBOT]
1. Kálmán Könyves
Kálmán Könyves (in English Coloman the Bookish) was a famous Hungarian king. But now, in our case here in this case study he is a virtual librarian chat robot that is based on the Loebner prize-winning ALICE chatbot. Richard Wallace's ALICE program uses his AIML[AIML] (Artificial Intelligence Markup Language) XML format.
ALICE implementations are available in several languages. Now we use the Python implementation. This is called PyAIML or, in its other name, Program Y that can be downloaded from http://sourceforge.net/projects/pyaiml/ For this implementation we write a short front end Python program that is based on the PyAIML's documentation. It is called KiralyiKonyvtaros.py. The following video shows its running: http://youtu.be/nVneMJt0UEo,
The Kálmán Könyves chatbot is introduced in detail in the paper [KK] or in online form at http://tmt.omikk.bme.hu/show_news.html?id=5431&issue_id=522.
As can be seen and heard in the above video, we also use the speech synthesis program called espeak to say ALICE's responses. A further function of the front end program is to build the LZW tree of words from the conversations. It is interesting to note that in a given arbitrary level of the tree a node may include any number of client nodes.
The TudatFa class controls the building of the tree of words. The AIMLChatterBot class is a wrapper class that hides the services of the PyAIML chatbot engine. Finally the infinite loop of the function tajekoztat of the class KiralyiKonyvtaros reads the user's input from the console, then sends it to ALICE and receives back the response from ALICE. In addition the building of the word tree has been called from this loop, too.
#!/usr/bin/python # -*- coding:
utf-8 -*- import aiml import commands import re class TudatFa(object):
agak = {} # Ide jöhetnek majd olyan funkciók, mint a kapcsolat # az
ILS-el, például kölcsönzéshez, hosszabbításhoz stb. class Konyvtaros:
# most még ilyenek nincsenek pass # A PyAIML (ProgramY) AIML
csevegőrobotot használjuk, # ebben az osztályban az ezzel kapcsolatos
részek class AIMLChatterBot: def __init__(self): self.konyvtaros =
aiml.Kernel() self.konyvtaros.learn("../AIML/*.aiml.xml")
self.konyvtaros.setBotPredicate("name", "Konyves Kalman")
self.konyvtaros.setBotPredicate("master", "Batfai Norbert es Batfai
Erika") self.konyvtaros.setBotPredicate("birthday", "2010. oktober
23.") class KiralyiKonyvtaros(AIMLChatterBot, Konyvtaros): gyoker = fa
= TudatFa() def __init__(self): AIMLChatterBot.__init__(self) def
tajekoztat(self): while 1: keres = raw_input('olvasó> ') if
len(keres) == 0: self.kiir(self.gyoker) break valasz =
self.konyvtaros.respond(keres) self.tudatfa(keres+" "+valasz) print
valasz print commands.getoutput("espeak -v hu+f1 -p 40 -s 160 -k 8
\""+valasz+"\"") def tudatfa(self, szoveg): szavak =
re.compile("\s").split(unicode(szoveg, 'utf-8')) print szavak for szo
in szavak: if self.fa.agak.has_key(szo): self.fa = self.fa.agak[szo]
print szo + u" - mar szerepelt, raleptem" else: self.fa.agak[szo] =
TudatFa() self.fa.agak[szo].agak={} print szo + " - nem szerepelt,
felvettem" self.fa = self.gyoker melyseg = 0 def kiir(self, honnan):
for szo in honnan.agak.keys(): m = (self.melyseg+1)*10 formatum=u"{0:"
+ str(m) + "d} {1:10s}" print formatum.format(self.melyseg,
"<"+szo+">") self.melyseg +=1 self.kiir(honnan.agak[szo])
self.melyseg -=1 konyvesKalman = KiralyiKonyvtaros()
konyvesKalman.tajekoztat()
Python vs. C++
It is worth pointing out that the next Python code snippet
for szo in
szavak: if self.fa.agak.has_key(szo): self.fa = self.fa.agak[szo]
print szo + u" - mar szerepelt, raleptem" else: self.fa.agak[szo] =
TudatFa() self.fa.agak[szo].agak={} print szo + " - nem szerepelt,
felvettem" self.fa = self.gyoker
do exactly the same function as the next C++ snippet
// Mit kell betenni éppen, '0'-t? if (b == '0') { /*
Van '0'-s gyermeke az aktuális csomópontnak? megkérdezzük Tőle, a
"fa" mutató éppen reá mutat */ if (!fa->nullasGyermek ()) // ha
nincs, hát akkor csinálunk { // elkészítjük, azaz páldányosítunk a
'0' betű akt. parammal Csomopont *uj = new Csomopont ('0'); // az
aktuális csomópontnak, ahol állunk azt üzenjük, hogy // jegyezze már
be magának, hogy nullás gyereke mostantól van // küldjük is Neki a
gyerek címét: fa->ujNullasGyermek (uj); // és visszaállunk a
gyökérre (mert ezt diktálja az alg.) fa = &gyoker; } else // ha
van, arra rálépünk { // azaz a "fa" pointer már majd a szóban forgó
gyermekre mutat: fa = fa->nullasGyermek (); } } // Mit kell
betenni éppen, vagy '1'-et? else { if (!fa->egyesGyermek ()) {
Csomopont *uj = new Csomopont ('1'); fa->ujEgyesGyermek (uj); fa
= &gyoker; } else { fa = fa->egyesGyermek (); } }
from the http://www.inf.unideb.hu/~nbatfai/z3a7.cpp. But certainly the latter code only inserts letters into the tree.
Example 7.1. Kálmán Könyves on IRC using the Program W
Install Kálmán Könyves using the Program W.
Example 7.2. Kálmán Könyves on the web using the Program D
Install Kálmán Könyves using the Program D.
1.1. The structure of the AIML files
The next Hungarian language AIML file is a part of the work [KK], this and the other files can be download from the author's page: http://www.inf.unideb.hu/~nbatfai/kk/.
[norbert@matrica 0.0.2]$ python KiralyiKonyvtaros.py Loading
../AIML/konyvtar.aiml.xml... done (0.01 seconds) Loading
../AIML/tmt.aiml.xml... done (0.00 seconds) Loading
../AIML/udvariassag.aiml.xml... done (0.01 seconds) Loading
../AIML/jucs.aiml.xml... done (0.00 seconds) Loading
../AIML/robot.aiml.xml... done (0.00 seconds) Loading
../AIML/jcscs.aiml.xml... done (0.00 seconds) Loading
../AIML/kf.aiml.xml... done (0.01 seconds) olvasó> Hello, Alice!
[u'Hello,', u'Alice!', u'Szervusz!'] Hello, - nem szerepelt,
felvettem Alice! - nem szerepelt, felvettem Szervusz! - nem
szerepelt, felvettem Szervusz! olvasó> Ki vagy Te valójában?
[u'Ki', u'vagy', u'Te', u'val\xf3j\xe1ban?', u'Virtu\xe1lis',
u'k\xf6nyvt\xe1ros', u'vagyok,', u'egy', u'cseveg\u0151', u'robot.',
u'A', u'nevem', u'Konyves', u'Kalman.', u'A', u'Debreceni',
u'Egyetem', u'Informatikai', u'Kar\xe1n', u'dolgozom.'] Ki - nem
szerepelt, felvettem vagy - nem szerepelt, felvettem Te - nem
szerepelt, felvettem valójában? - nem szerepelt, felvettem Virtuális
- nem szerepelt, felvettem könyvtáros - nem szerepelt, felvettem
vagyok, - nem szerepelt, felvettem egy - nem szerepelt, felvettem
csevegő - nem szerepelt, felvettem robot. - nem szerepelt, felvettem
A - nem szerepelt, felvettem nevem - nem szerepelt, felvettem
Konyves - nem szerepelt, felvettem Kalman. - nem szerepelt,
felvettem A - mar szerepelt, raleptem Debreceni - nem szerepelt,
felvettem Egyetem - nem szerepelt, felvettem Informatikai - nem
szerepelt, felvettem Karán - nem szerepelt, felvettem dolgozom. -
nem szerepelt, felvettem Virtuális könyvtáros vagyok, egy csevegő
robot. A nevem Konyves Kalman. A Debreceni Egyetem Informatikai
Karán dolgozom. olvasó>
The input Hello, Alice! matches the patternHELLO * defined by the category element:
HELLO *
SZIA
The appropriate response is given in the contained template element. Now it is not a simple text element but a recursive one. That means that the robot must respond the same as in case of the patternSZIA. That response will be one of the following possibilities:
SZIA
Szia! Szevasz!
Szervusz!
Now the Szevasz! has been selected:
Q: Hello, Alice!
A: Szevasz!
encoding="utf-8"?> Kálmán virtuális királyi könyvtáros # # Copyright (C) 2010, Bátfai
Norbert, Bátfai Erika # # This program is free software: you can
redistribute it and/or modify # it under the terms of the GNU
General Public License as published by # the Free Software
Foundation, either version 3 of the License, or # (at your option)
any later version. # # This program is distributed in the hope that
it will be useful, # but WITHOUT ANY WARRANTY; without even the
implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the # GNU General Public License for more details. # #
You should have received a copy of the GNU General Public License #
along with this program. If not, see
Share with your friends: |