Copyright (C) 1996-2000 Kim Rutherford, Michael Norrish
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.
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.
Cheth was written by
S.McAuliffe@dtsp.co.nz>,
Michael.Norrish@cl.cam.ac.uk> and
kmr@sanger.ac.uk>
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.
robert@comp.vuw.ac.nz>
jules@clearview.co.nz>
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):
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.
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.
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]
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).
make system
call and the iron resource.
SHIELD_RUN_COST multiplied by the shield level. A
shield at level n reduces all damage events it incurs by n
points.
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".
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.
The directions are:
System calls can sometimes extend the six standard directions with various negative numbers to refer to other robots. There are listed here:
The following is an automatically generated list of all the system calls available to a robot:
prototype: move (const long direction)
Move one hex in the given direction.
Cost: MOVE_COST * impedance / ability.
Cycles: MOVE_CYCLE.
Implementation status: OK
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
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
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
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
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
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
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
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
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
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
prototype: make (const unsigned long item, const unsigned long quantity)
Processes resources, creating new derived ones.
Implementation status: Presumed OK
prototype: burn (const unsigned long item, const unsigned long quantity)
Burns burnable resources, creating energy
Implementation status: Presumed OK
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
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
prototype: get_code_info (const Address name, const Address code_info)
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)
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
prototype: detonate ()
Self-destruct this robot and burn all the resources (uranium, biomass etc.) it is carrying.
Implementation status: OK
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
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
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
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
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.
take piles
of dirt, and then use the extract system calls to pull the things
they want out of the piles of dirt. A possibly incomplete list of
dirt-bound resources is:
This document was generated on 17 June 2001 using the texi2html translator version 1.51.