Cheth Manual

Kim Rutherford, Michael Norrish


Copyright (C) 1996-2000 Kim Rutherford, Michael Norrish

Copyright and Cast of Characters

The Cheth Guide is copyright (C) 1996-2001 Kim Rutherford, Michael Norrish

Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.

Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.

Copying Cheth

Cheth is copyright (C) 1992--2001 Simon McAuliffe, Michael Norrish and Kim Rutherford.

It can be distributed only under the terms of the GNU Public License, a copy of which is provied with the cheth distribution.

Dramatis Personae

Cheth was written by

Most of the recent work has been done by Kim and Michael.

The following is an incomplete list of other people who have contributed code, ideas or who didn't laugh when told about Cheth. All are or were staff or students at Victoria University of Welligton.

Introduction

Cheth is a game. It has direct ancestors in games such as Core Wars and C Robots but aims to present the game player with a much greater flexibility. Cheth has a number of features that, so far as we know, set it apart from other games (such as those mentioned above):

History

Cheth came about one day in 1992 (!) when Robert Biddle came into the third year lab at Victoria University of Wellington, and told Sai and Michael about a dream he had had which involved playing a game of chess, where the pieces on the board had programs of their own. The dream was actually quite a nightmare, because it was very hard to debug the pieces to do the right thing. We decided that we should implement a system to allow people to do exactly this.

We very quickly decided to change some facets of the original idea. In particular, we decided that the game shouldn't just be chess, but should be more of a war-game, and we also decided that Lisp shoudn't be the only programming language.

The first version of Cheth was based around a fairly simple world, with a specially designed form of Robot chip being emulated "underneath the hood". This was an elegant (but unrealistic) language known as puce-code.

Name

Credit for Cheth's name must go to David Wallace. He suggested it as the obvious name for a game that was at that stage going to be all about playing chess with Lisp programs.

Invocation

This is the result of running cheth with the --help option:


cheth [OPTION]... [LONG OPTION]... [ROBOT FILE]...

These are the most useful options:
  -x          use X to display the state of the game
  -d          turn on low level debugging
  -D NUM      set the debug level to NUM
  -r NUM      set the random seed to NUM
  -f FILE     configure cheth from FILE
  -h, --help  show all options

You must supply at least two robots

The following long options are available:
(options are shown with their default values)
  --armour_size_factor[=5]  --attack_cost[=1]  --attack_cycle[=2]
  --base_size[=1000]  --biomass_burn_factor[=2]  --biomass_growth_time[=20000]
  --board_size[=32]  --burn_biomass_cost[=0]  --burn_biomass_cycle[=30]
  --burn_petro_cost[=0]  --burn_petro_cycle[=30]  --cell_biomass_damage[=100]
  --cell_biomass_fractalness[=900]  --cell_biomass_max[=999]
  --cell_biomass_min[=0]  --cell_dirt_damage[=10]
  --cell_dirt_fractalness[=5000]  --cell_dirt_max[=100]  --cell_dirt_min[=0]
  --cell_fertility_damage[=0]  --cell_fertility_fractalness[=900]
  --cell_fertility_max[=1000]  --cell_fertility_min[=0]
  --cell_impedance_damage[=0]  --cell_impedance_fractalness[=900]
  --cell_impedance_max[=100]  --cell_impedance_min[=0]  --cell_iron_damage[=2]
  --cell_iron_fractalness[=900]  --cell_iron_max[=9]  --cell_iron_min[=0]
  --cell_petro_damage[=10]  --cell_petro_fractalness[=2]  --cell_petro_max[=0]
  --cell_petro_min[=0]  --cell_raw_iron_fractalness[=800]
  --cell_raw_iron_max[=999]  --cell_raw_iron_min[=33]
  --cell_raw_petro_fractalness[=800]  --cell_raw_petro_max[=99]
  --cell_raw_petro_min[=33]  --cell_raw_silicon_fractalness[=800]
  --cell_raw_silicon_max[=999]  --cell_raw_silicon_min[=33]
  --cell_silicon_damage[=5]  --cell_silicon_fractalness[=900]
  --cell_silicon_max[=9]  --cell_silicon_min[=0]  --cell_water_damage[=10]
  --cell_water_fractalness[=0]  --cell_water_max[=0]  --cell_water_min[=0]
  --create_robot_cost[=1]  --create_robot_cycle[=50]  --cycle_cost[=1]
  --damage_radius_ratio[=500]  --detonate_cost[=1]  --detonate_cycle[=1]
  --display_angle[=30]  --display_size[=16]  --drop_armour_cost[=1]
  --drop_armour_cycle[=5]  --drop_biomass_cost[=1]  --drop_biomass_cycle[=5]
  --drop_dirt_cost[=1]  --drop_dirt_cycle[=5]  --drop_iron_cost[=1]
  --drop_iron_cycle[=5]  --drop_memory_cost[=1]  --drop_memory_cycle[=5]
  --drop_petro_cost[=1]  --drop_petro_cycle[=5]  --drop_robot_cost[=1]
  --drop_robot_cycle[=5]  --drop_silicon_cost[=1]  --drop_silicon_cycle[=5]
  --drop_water_cost[=1]  --drop_water_cycle[=5]  --extract_iron_cost[=10]
  --extract_iron_cycle[=30]  --extract_petro_cost[=10]
  --extract_petro_cycle[=30]  --extract_silicon_cost[=10]
  --extract_silicon_cycle[=30]  --get_code_info_cost[=0]
  --get_code_info_cycle[=1]  --give_armour_cost[=-10]  --give_armour_cycle[=3]
  --give_biomass_cost[=-10]  --give_biomass_cycle[=3]
  --give_capacity_cost[=-10]  --give_capacity_cycle[=3]
  --give_dirt_cost[=-10]  --give_dirt_cycle[=3]  --give_energy_cost[=-10]
  --give_energy_cycle[=3]  --give_iron_cost[=-10]  --give_iron_cycle[=3]
  --give_memory_cost[=-10]  --give_memory_cycle[=3]  --give_petro_cost[=-10]
  --give_petro_cycle[=3]  --give_silicon_cost[=-10]  --give_silicon_cycle[=3]
  --give_water_cost[=-10]  --give_water_cycle[=3]  --initial_ability[=1]
  --look_cost[=1]  --look_cycle[=3]  --make_armour_cost[=10]
  --make_armour_cycle[=30]  --make_capacity_cost[=10]
  --make_capacity_cycle[=30]  --make_memory_cost[=10]
  --make_memory_cycle[=30]  --max_drop_height[=20]  --mem_move_team_cost[=20]
  --memmove_cost[=1]  --memmove_cycle[=3]  --message_size[=16]
  --move_cost[=1]  --move_cycle[=1]  --network_port[=2525]
  --oldest_age[=10000]  --petro_burn_factor[=100]
  --piece_initial_armour[=100]  --piece_initial_biomass[=0]
  --piece_initial_capacity[=100000]  --piece_initial_dirt[=0]
  --piece_initial_energy[=10000]  --piece_initial_iron[=0]
  --piece_initial_memory[=50000]  --piece_initial_petro[=0]
  --piece_initial_silicon[=0]  --piece_initial_water[=0]  --radar_cost[=1]
  --radar_cycle[=9]  --reboot_cost[=1]  --reboot_cycle[=1]  --scan_cost[=1]
  --scan_cycle[=3]  --scanpassenger_cost[=1]  --scanpassenger_cycle[=3]
  --shield_run_cost[=1]  --take_armour_cost[=1]  --take_armour_cycle[=10]
  --take_biomass_cost[=-100]  --take_biomass_cycle[=10]  --take_dirt_cost[=1]
  --take_dirt_cycle[=10]  --take_iron_cost[=1]  --take_iron_cycle[=10]
  --take_memory_cost[=1]  --take_memory_cycle[=10]  --take_petro_cost[=1]
  --take_petro_cycle[=10]  --take_robot_cost[=1]  --take_robot_cycle[=10]
  --take_silicon_cost[=1]  --take_silicon_cycle[=10]  --take_water_cost[=1]
  --take_water_cycle[=10]  --teleport_cost[=1]
  --teleport_cycle_base_param[=1]  --teleport_cycle_mult_param[=2]
  --timer_cost[=1]  --transmit_cost[=1]  --transmit_cycle[=3]
  --write_long_cost[=0]  --write_long_cycle[=1]  --write_string_cost[=0]
  --write_string_cycle[=1]

Game Environment

Robots and their characteristics

Robots are deliberately left under-specified in terms of their physical appearance. This is a matter for graphical client implementors to decide. As far as the core of the game is concerned, robots are machines with a few simple characteristics. Most of the following characteristics are actually also resources (see section Resources).

Armour
A robot's armour characteristic represents the robot's general hardiness. If the robot is ever damaged by a force of greater strength than its armour, then it dies. Further, every blow suffered by the robot causes its armour's strength to reduce by that amount. Armour is thus analogous to the notion of "hit-point" in innumerable role-playing games except that death comes at an armour level of -1, not zero. A robot can make additional armour using the make system call and the iron resource.
Capacity
A robot's capacity represents its ability to hold things "inside" itself. Robots will often want to pick things up from the world around them, but they must have sufficient carrying capacity to do so. Robots can even pick up other robots and transport them. When creating new robots, the "child" robot is also contained within the parent, and again the womb must be big enough for this to happen. A robot's size is a (linear) function of its capacity.
Memory
A robot's memory is a number representing the number of bytes of accessible memory it has. Memory is a slightly special resource inasmuch making new memory in a robot will not affect the running processor until it reboots. Further, attempting to give away memory that is currently in use by the robot's processor is forbidden.
Shields
A robot can use electronically maintained force-shields to prevent damage ever occurring to its armour. Such shields can be set to whatever level the robot likes, but are a constant drain on the robot's energy supplies. The energy cost is equal to the configuration variable SHIELD_RUN_COST multiplied by the shield level. A shield at level n reduces all damage events it incurs by n points.

System Calls

To interact with the world around it, the code running inside a robot is able to make system calls. These can make robots perform actions visible in the world around them, such as moving or attacking, or give back the robot information about that world.

Robots written in C can use the wrapper functions in robot_syscalls.h to avoid the low-level code calling procedure documented below. Here is an example of a robot that uses the teleport system call to escape from danger:

#include "robot.h"

void proximity_alarm(void)
{
  write_string("Eeek!");
  teleport(get_hr_misc_random(), get_hr_misc_random());
}

int main(void)
{
  set_hr_misc_prox_range(1);
  set_hr_int_move(proximity_alarm);
  set_hr_misc_random(4);
  while(1);
}

In addition, the standard C library provided to all robots includes calls that wrap up some of the ways in which robots can get information about themselves through "hardware registers".

Making system calls

System calls are fairly tedious for a robot to set up, as the following discussion will illustrate, but the time spent doing so will still be fairly insignificant in comparison to the time spent executing the system call. After all, system calls involve interaction with the real world in one way or another, and this quite reasonably takes much longer than the operation of the simulated CPU.

All the communication necessary for system calls happens in a special part of memory with addresses between 0x80000000 and 0x90000000. Both system call parameters and results are stored in this region. Here, memory becomes "long-addressable" rather than byte addressable. In other words, all of the addresses become addresses for 32 bit values, rather than 8 bit values.

The address 0x80000000 is used to specify which system call the robot wishes to initiate. A robot writes the number of the system call to this address, and the system then reads the parameters for that call from the appropriate locations in the rest of system call area of memory. The system calls are numbered from zero up, as per the order given in the file syscall-info.

The locations of the parameter slots for given calls and the numbers of the system calls are available to assembly programmers as #defines. For example these are the defines for the move system call:

#define SYSCALL_MOVE_NUM 0
#define SYSCALL_SYNC_MOVE_NUM 0x80000000
#define SYSCALL_MOVE_ARGS 0x80000001

The high bit of the system call number is reserved so that the robot can indicate whether or not the call should be executed synchronously or asynchronously. With the high-bit off, the call is made asynchronously. In either case, when the call finishes, the return code from the system call is available in the hardware register HR_SYSRET_NAME, where NAME is the name of the call.

C programmers can make system calls by including the header file robot_syscalls.h. Names for the synchronous versions of the calls are as given below (see section System call listing), while names for asynchronous calls are preceded by the string async_. Other languages may use other conventions. In C, the return code hardware register is automatically examined and returned as the result of the call, so the programmer need not be concerned with this aspect of the system.

If making a call asynchronously, there are two extra facets of system calls that need to be understood. First, system calls are grouped into various categories, and no more than one call can be in progress from each category. An attempt to issue a call in a category where another call is already running will fail. This failure is detectable by reading the address 0x80000000 after the call is made. This address will contain a one if the call was valid, and a zero if not.

Assuming a call is not already in progress in the category in question, a call "event" is dispatched, which will eventually result in an attempt to perform the call. When the call returns, the robot receives an interrupt corresponding to the call. The symbolic name of this interrupt is INT_SYS_NAME, where NAME is the name of the system call. After this point, the hardware register containing the call's return code will contain the appropriate value.

Common system call conventions

Direction and coordinates

The directions are:

Extended directions for referring to other robots

System calls can sometimes extend the six standard directions with various negative numbers to refer to other robots. There are listed here:

-1
A child robot
-2, -3, -4 ...
Passenger robots, with the n-th passenger being given the number -(n+1).

System call listing

The following is an automatically generated list of all the system calls available to a robot:

move

prototype: move (const long direction)

Move one hex in the given direction.

Cost: MOVE_COST * impedance / ability.

Cycles: MOVE_CYCLE.

Implementation status: OK

teleport

prototype: teleport (const long x_rel, const long y_rel)

Teleport to the relative coordinate (x_rel,y_rel).

Cost: distance * TELEPORT_COST / ability.

Cycles: TELEPORT_CYCLE_BASE_PARAM + TELEPORT_CYCLE_MULT_PARAM * distance.

Implementation status: OK

look

prototype: look (const long x_rel, const long y_rel, Address address)

Read into address the information about the cell relative distance (x_rel,y_rel) away.

Cost: LOOK_COST * distance / ability.

Cycles: LOOK_CYCLE.

Implementation status: OK

scan

prototype: scan (const long x_rel, const long y_rel, const unsigned long energy, Address address)

Read into *address the information about the piece in the cell relative distance (x_rel,y_rel) away. The data placed at *address is a struct PieceInfo. Use energy units of energy. More energy makes the scan more accurate.

Cost: SCAN_COST * distance^2 / ability. Cycles: SCAN_CYCLE

Implementation status: OK

scanpassenger

prototype: scanpassenger (const unsigned long position, Address address)

Read into *address the information about the piece in position position in the passenger list of this piece. The data placed at *address is a struct PieceInfo.

Cost: SCAN_COST * distance^2 / ability. Cycles: SCAN_CYCLE

Implementation status: OK

radar

prototype: radar (const long start, const long finish, const long distance, Address address, const long count)

Scans around the piece for other pieces which are within radius. Scan from direction start to direction finish. The coordinates of pieces found are stored as integer pairs in *address, with a maximum of count pairs. If count is negative then a maximum of -count will be returned, but robots on the same team will be ignored. The number actually found is returned, or -1 on error. The number found may be bigger than count, but no more than count pieces will be recorded in the address given.

Cost: RADAR_COST * width * radius^2 / ability.

Implementation status: OK

attack

prototype: attack (const long x, const long y, const unsigned long energy, const unsigned long radius)

Attack the hex at the relative coordinate (x_rel,y_rel). Use energy units of energy in the attack. The attack is more precise and powerful if radius, x or y is smaller or energy is bigger.

Implementation status: OK

give

prototype: give (const long direction, const unsigned int item, const unsigned long quantity)

Transfer quantity of item from this robot to the robot at the cheth direction direction (note the first passenger is direction -2). The call will fail if there is no robot in direction (returns NO_ROBOT) or if the destination robot does not have enough room for quantity units (NO_ROOM). If quantity is negative give all but -quantity. Giving to yourself (ie. a direction of -1) will return BAD_ARG.

Implementation status: Presumed OK

drop

prototype: drop (const long direction, const long item, const long quantity)

Drop quantity of item into the cell given by direction. Drop into current cell if direction is = -1. If quantity is negative drop all but -quantity.

Implementation status: Presumed OK

take

prototype: take (const long direction, const long item, const long quantity)

Take quantity of item from the cell given by direction. Take from the current cell if direction is = -1. If quantity is negative take all but -quantity. If item is ITEM_ROBOT then the quantity is actually an index into the passenger list, with 0 being the first passenger.

Returns the quantity of the item that was actually taken; this is only relevant if the the quantity was negative; if the robot specifies more than it is possible to take, for whatever reason, the call fails. It does not take as much as possible.

Implementation status: OK

extract

prototype: extract (const unsigned long item, const unsigned long maxquantity)

Try and extract up to maxquantity of item from the robot's current heap of (carried) dirt. Returns the amount actually extracted.

Implementation status: Presumed OK

make

prototype: make (const unsigned long item, const unsigned long quantity)

Processes resources, creating new derived ones.

Implementation status: Presumed OK

burn

prototype: burn (const unsigned long item, const unsigned long quantity)

Burns burnable resources, creating energy

Implementation status: Presumed OK

transmit

prototype: transmit (const unsigned long signal_strength, Address msg)

Transmits the message given (the second argument, as a pointer) with strength signal_strength. This latter affects both how far the message will carry, and the strength with which it will be received. The stronger the strength at receipt, the more chance there is that this message will override others that might be competing with it.

Implementation status: OK

memmove

prototype: memmove (const long from_whom, const Address srcadr, const long to_whom, const Address destadr, const long len)

Allows contents of robots memory to be shifted about, using the standard convention for direction to identify specific robots, and the addresses to specify which bits of memory to move. If an attempt to move memory causes an exception then the robot whose memory has been badly used will still blow up.

Implementation status: OK

get_code_info

prototype: get_code_info (const Address name, const Address code_info)

create_robot

prototype: create_robot (const Address pieceinfo)

Create a new robot and make it a passenger of this robot. The arg pieceinfo is the address of a PieceStruct (defined in robot_piece_struct.h). The structure defines the abilities of the new robot and and the quantities of resources it receives. Call give to add resources to the new robot. The return code is a unique integer identifer for the robot. The most important field in the pieceinfo structure is name, which must be set or the new robot will have a very short life.

Implementation status: OK(ish)

timer

prototype: timer (const long time, const long userdata)

This system call does nothing but return the value userdata, and takes time pings to do it.

Implementation status: Presumed OK

detonate

prototype: detonate ()

Self-destruct this robot and burn all the resources (uranium, biomass etc.) it is carrying.

Implementation status: OK

reboot

prototype: reboot (const Address robot_name)

Robot this robot using the robot code given by the argument. If the argument is null the current code is reused. This call can only fail if the robot_name is incorrect. In that case BAD_ARG is returned.

Implementation status: In progress

write_string

prototype: write_string (const Address stringaddr)

Print the string at stringaddr to the stdout stream of the cheth process. This system call is provided to help with the debugging of robots.

Implementation status: OK

write_long

prototype: write_long (const long number)

Print number to the stdout stream of the cheth process. This system call is provided to help with the debugging of robots.

Implementation status: OK

write_slong

prototype: write_slong (const Address stringaddr, const long number)

Prints the string at stringaddr followed by number. This call is provided to help with the debugging of robots.

Implementation status: OK

Resources

Just as in the real world, the most important resource, and the one into some of the others will ultimately decay is energy. The other resources are more concrete: iron, silcon, dirt, etc.

Resource types

The PieceStruct structure

Concept Index

a

  • Armour (robot attribute)
  • Asynchronous system calls
  • c

  • Capacity (robot attribute)
  • d

  • Dirt-bound resources
  • f

  • Free-standing resources
  • m

  • Memory (robot attribute)
  • r

  • Robot attributes--armour
  • Robot attributes--capacity
  • Robot attributes--memory
  • Robot attributes--shields
  • s

  • Shields (robot attribute)

  • This document was generated on 17 June 2001 using the texi2html translator version 1.51.