Note: Bot Factory KoTH (2.0) is now posted; you're probably looking for that one instead!
In this challenge, bots (consisting of JS functions) move around an infinite factory (playing field), collecting characters (UTF-16). These characters can be used to build worker bots, or droppedfor other bots to pick up.
Results
Average number of characters collected per game (20k rounds)
[1484.5] The Forsaken Farmer
[1432.9] The Replicator
[957.9] Safe Player V2
[739.1] Hunter
[101.65] First
[9.75] IDKWID
The Factory
All bots start out randomly placed around the center of the factory, [0, 0]
, where coordinates are arrays [x, y]
. North is -Y, and west is -X. Each round consists of up to 100000 turns. A bot may move one space in any cardinal direction (or build a worker, or drop a character) per turn.
Bots can move by returning north()
, east()
, south()
, or west()
.
Characters
Characters will be randomly distributed, centered around [0, 0]
. There are always up to a total of 4 characters per bot at any given time (excluding those from dead bots).
Character's positions may overlap, and their character value (such as a
or (
) is selected from a pool of the source code of every bot and worker currently in the factory.
Bots collect characters by moving into the same position in the factory, and these collected characters are stored within the bot.
Bots may also drop a character they have previously collected in any of the four cardinal directions. This character is then removed from the bot's collected characters array.
Bots drop characters by returning drop.north(c)
, drop.east(c)
, drop.south(c)
, or drop.west(c)
, where c
is a string.
Score
Bots have a score, which is initially -floor(sqrt(LEN))
, where LEN
is the length of the bot's source code in characters. Worker bots start with a score of 0 regardless of their length.
Whenever a character is collected, this score value increments; when a character is dropped, it decrements.
Collisions
When two or more bots collide (occupy the same position), whichever has the highest score survives (if there is a tie, none survive). All bots that die "drop" the characters they have collected, which are randomly distributed centered around the position they collided in.
Bots can switch places by moving into each others' previously occupied positions without colliding.
Workers
Bots can use the characters they have collected to build a worker bot. A worker bot's source code (provided as a function or arrow function) must be entirely made up of characters its owner has collected, which are then removed. Half of the length of the worker's source code is deducted from the owner's score.
Worker bots are placed randomly around the position of their owner, using the same system as characters, and are not immune to collision. Worker bots can also build worker bots, whose owner would be the worker.
Workers can be built by returning the result of the function build(source)
, where source
is a string. If the bot cannot be built (such as not having all necessary characters), nothing happens.
Functions
All bots are functions. They are provided a single argument, an object that can be used for storage, and can access information about other bots and characters using the following functions:
bots()
: Returns an array of bots (as objects)chars()
: Returns an array of characters (as objects)self()
: Returns the bot that called it (as an object)owner()
: Returns the owner of the bot that called it (as an object,null
if owner is dead, orself()
if no owner)
A bot object has the following properties:
uid
: An integer ID unique to each bot, randomly selectedowner
: The UID of the bot's ownerscore
: The score of the botpos
: The position of the bot formatted as[x, y]
A bot object also has the following properties if it is the owner or worker of the bot:
chars
: An array of characters the bot has collectedsource
: A string with the bot's source code
A character object has the following properties:
char
: A stringpos
: The position of the character formatted as[x, y]
There are also the following library functions:
center()
: Get average of bots' positions weighted by scoreturn()
: Get current turn (starts at 0)dir(from, to)
: Get direction fromfrom
toto
, which should be arrays formatted[x, y]
dirTo(pos)
: Same asdir
, usesself().pos
asfrom
dist(from, to)
: Get taxicab distance fromfrom
toto
, which should be arrays formatted[x, y]
distTo(pos)
: Same asdist
, usesself().pos
asfrom
Winning
Once all surviving bots are direct or indirect workers of the same initial bot, characters will no longer generate. Games automatically end when all characters are collected.
The winner is the bot which, after some number of rounds, has collected (or had workers collect) the most characters.
Rules
- Bots may not use global variables in a way which produces side effects other than intended (such as to sabotage other bots or the controller)
- Bots which error will be killed and drop their characters
- Bots may only attempt to build workers which are valid functions
- Bots may not take an unnecessarily long time to run (no hard limitation, but be reasonable)
- Bots may not team with other which do not originate from the same owner (directly or not)
Technical Notes
- Character and bot spawning radius is based on a geometric distribution (
p=0.1
), with a random angle. The resulting coordinates are truncated to integers. Repeated until a position is found with no bots within a taxicab distance of 4 - For dead bots' drops,
p=0.2
and there is no distance requirement - For worker bot spawning, minimum taxicab distance is 3 for the owner
- Every time a character is picked up, one attempt is made to generate another. An attempt will only fail if there are already
4 * botCount
characters not dropped by a bot (or a bots' death), wherebotCount
is the total number of alive bots (including workers).4 * botCount
characters are generated at the start.
Example Bot
ExampleBot uses an arrow function to keep its starting score higher, but still isn't well golfed. It likes characters which are in the middle of the action, which it finds by sorting the chars()
array and using the dist
and center
library functions. It will not be included in the competition game.
() => dirTo(chars().sort((a, b) => dist(center(), a.pos) - dist(center(), b.pos))[0].pos)
Controller: https://gist.github.com/Radvylf/31408373bae12843bfbf482188653a42
Edit: Fixed the controller. Made a few changes before putting it in the gist to clean up some debugging and deleted a few things by mistake. Sorry about that, should be up and running!
Due Date: Challenge completed
Prize: Bounty (100 reputation)
Chatroom: https://chat.stackexchange.com/rooms/105613/bot-factory-koth