Make a simple robot for IWOR
(C++ edition)

Author: Aidin Gharibnavaz

Table Of Contents


1. Introduction

Using simple messages for communicating between robots and the simulation server makes it easy to constructing robots. But if you want to have a real intelligence robot, you need to use artificial intelligence techniques.

This document explain how to make a simple robot for Imperfect world of Robots. This robot moves around the world randomly, and try to detect crystals around her. This not an intelligence robot and can't survive longer than a minute in this pitiless world! But you will gain some idea about how IWOR works, and how to make your own robots.

In this tutorial, we use Unix sockets. You can use it without any change for any unix-like system. If you use other operating system (remember that robots can be on different and separated operating systems), you can still use this tutorial. Find about socket programming in your OS, then read this document from third section.

You can find the complete robot in `sample/robots/Tutorial' directory.

NOTE: Codes in the `sample/robot/Tutorial' directory, and in this tutorial, are publish under the terms of GNU General Public License. According to this license, If you use these codes in your robot, you have to publish your robot under GPL, too. Means your program will be free (as in freedom), and everyone can modify and redistribute it again. If you don't like it, please don't use the codes in this tutorial.


2. Connecting to the server

First of all, our robot need to connect to the simulating server. By default, server listen to the 7200 port and wait for the robot's connection. We need to open a socket and use it to connect to the server. To make it more simpler, we use `RobotSocket' class in `sample/robots/Tutorial' directory.

`RobotSocket' have three methods: constructor, receive() and sendMessage(). Constructor needs two arguments, a port number and a host name. First lines of our robot are:

#include <iostream> 
#include "RobotSocket.hpp" 

RobotSocket* server;

int main(){
  //Connecting.
  server = new RobotSocket("localhost", 7200);
}

This code create a socket and connect it to the simulation server, which running on the same machine (localhost). We define `server' as a global variable, so all of methods can access it, send and receiving messages.


3. Initialization

Our robot need to initialize her self in order to join the game. This can be done by sending `INIT' command to the server.

#include <iostream> 
#include <string> 
#include "RobotSocket.hpp" 

//Global variables.
RobotSocket* server;

int main(){
  //Connecting.
  server = new RobotSocket("localhost", 7200);
  
  server->sendMessage("INIT&1&tutorial&0&");
  std::string initResult = server->receive();
  //Send INIT until success.
  while(initResult.compare("255") != 0){
    //Send it again.
    server->sendMessage("INIT&1&worker&0&");
    initResult = server->receive();
  }
}

INIT command have three argument. `1' is the tribe number we want to join to, `tutorial' is the name of our robot, and `0' is the key code to join the game. Zero keys are available only at the start of the game, and number of them is limited. After all of the robots consumed these zero keys, robot must gain new ones from her parents, so its a good idea to add a ability for your robots to gain these keys by command line arguments, so their parents can give keys to them easily. We don't want to go through with this here, take a look at the hand book to gain more information.

The reason of using while() is that sometimes server can't create this robot in the simulated world, cause there's no empty space. In this case, we will receive 190 error number which tell us to send INIT later. 255 mean success. Robot send INIT command until she receive a success message from the server.

Now we are in the game! Next step is to teach our robot how to move around.


4. Moving around randomly

in this section, we will add a method named `randomMove' which generate a random number, and move to a direction according to the number that generated.

#include <cstdlib> 
#include <ctime>

//Constants
int const NORTH=0;
int const SOUTH=1;
int const EAST=2;
int const WEST=3;

void randomMove(){
  std::string moveCommand;
  
  //Change direction randomly.
  srand((unsigned)time(0));
  int rndint = int(4*(rand()/(float)RAND_MAX));
  if(rndint==NORTH){
    moveCommand = "MOVE&NORTH&";
  }else if(rndint==WEST){
    moveCommand = "MOVE&WEST&";
  }else if(rndint==SOUTH){
    moveCommand = "MOVE&SOUTH&";
  }else if(rndint==EAST){
    moveCommand = "MOVE&EAST&";
  }
  //Moving around ...
  server->sendMessage(moveCommand);
  server->receive();
}

In order to generate a random number, we use `rand()' function, which can be found in `cstdlib' header. It will generate a number between zero and RAND_MAX. But we need a range between zero to 3. That strange formula will handle this for us.

`rand()' itself dosen't make real random numbers. In fact, it will generate same numbers each time you run the program. But fortunately, `srand()' is here to solve this problem for us. It will take a number as its argument and generate a series of random numbers for `rand()' function. The numbers it generate are depend on its argument. By using a dynamic argument (in our code, it's the current time) we can generate near random numbers.

Because it's a random move, we don't need the moving result that server return to us, if we hit a wall or something, direction will be changed next time and robot will pass it. But it's a good idea to wait for the server response each time we send a command. Sometimes server receive our message with delay, and if we send another command before last one deliver, strange things may happen!


5. Finding crystals around the robot

Now our robot can move around the world, and we're going to add an ability of detecting crystals around herself. Robots can use `SENSE' command to see what objects are around them. We call our method `seekForCrystals()'.

#include <vector>

void seekForCrystals(){
  std::vector<std::string> args;
  std::vector<std::string>::iterator argsIterator;
  std::vector<std::string> objects;
  std::string senseResult;

  //Sniff around.
  server->sendMessage("SENSE&");
  //Getting the result.
  senseResult = server->receive();    

  //Extracting message arguments.
  int findResult;
  int index=0;
  int length;

  findResult = senseResult.find('&');
  while(findResult != -1){
    length = findResult - index;
    args.push_back(senseResult.substr(index,length));
    index = findResult+1;
    findResult = senseResult.find('&',index);
  }
  args.push_back(senseResult.substr(index));

  //Finding crystals in the result.
  std::string currentArg;
  argsIterator = args.begin();
  while(argsIterator != args.end()){
    currentArg = *argsIterator;

    //Extracting objects in this argument.
    index=0;
    objects.clear();
    findResult = currentArg.find(',');
    while(findResult != -1){
      length = findResult - index;
      objects.push_back(currentArg.substr(index,length));
      index = findResult+1;
      findResult = currentArg.find(',',index);
    }
    objects.push_back(currentArg.substr(index));

    if(objects.size() > 2){
      if(objects.at(2).compare("C")==0){
	//Printing out message.
	std::cout << "A crystal has been detected at ";
	std::cout << objects.at(0) << ",";
	std::cout << objects.at(1) << std::endl;
      }
    }
    ++argsIterator;
  }
}

It's a very big method! But it's not as completed as it seems. First, we send `SENSE&' command to the server and gain its result. The result is something like 3,5,#&4,6,C& which means there's a wall at the (3,5) location, and there's a crystal at (4,6). As you can see, objects are separated with '&' and their location is separated with ','. So all we need to do is to extract objects from the result, and if it's a crystal, find its position. Following code will extract objects in the result:

findResult = senseResult.find('&');
  while(findResult != -1){
    length = findResult - index;
    args.push_back(senseResult.substr(index,length));
    index = findResult+1;
    findResult = senseResult.find('&',index);
  }
  args.push_back(senseResult.substr(index));

It find '&' characters in the result, then break the string and put the result in the `senseResult' vector. After doing this, we need to know which one is a crystal. First we find ',' characters in the result, then break it same as before:

    findResult = currentArg.find(',');
    while(findResult != -1){
      length = findResult - index;
      objects.push_back(currentArg.substr(index,length));
      index = findResult+1;
      findResult = currentArg.find(',',index);
    }
    objects.push_back(currentArg.substr(index));

Now we can check if the object is a crystal. If it is, robot print out its position.


6. Last words

This was a very very simple robot, which only move around the world and report if there's a crystal around her. she won't pick up any crystal, don't care about her battery (which cause she became inactive very soon) and in fact do nothing useful! You should make more complicated robots if you want to enjoy the game! Take a look at our sample robots to find out some ideas.


Copyright (c) 2008 Aidin Gharibnavaz
You are free to redistribute and/or modify this document under the terms of the GNU Free Documentation License. A copy of this license can be found on the FDL file along with this document.

Syntax highlighting generated by Web C Plus Plus v0.8.4
Webcpp Copyrighted by Jeffrey Bakker (2001-2004) and publish under the terms of GNU GPL.