51
\$\begingroup\$

Note: The survey for community favorite will be released soon

In this KoTH, the aim is to be the last bot alive. Coins will be placed in random areas, and your bot must get the coins first. If a bot runs into another bot, the bot with more coins wins, and the other bot dies. More details below.

Coin types

There will be 2 types of coins: gold and silver. Gold adds 5 coins to the bot's strength, and silver adds 2. Once a coin is collected, another coin is placed at another spot on the board. At any given time, there is one gold coin and four silver coins in the arena.

Bot collisions

In the event of two bots trying to occupy the same space, the one with more coins will stay, and the one with less will...not. The winning bot will gain 85% of opponents coins (Rounded up). If they are tied, both die. If three or more try to occupy the same space, the most powerful wins, and gets 85% of all the other bot's coins. In the event that the most powerful bot is a tie, all of the bots die who tried to enter the space.

Arena

The arena's side length is calculated with 4 + botCount. When placing bots in the beginning of the game, random places are chosen. The system ensures that no bots start in the same space, or next to each other. Coins generate randomly, excluding a 3 by 3 square centered on each bot. If a bot is found outside of the arena, it dies instantly. The arena starts at (0,0), or Northwest, in the upper left corner, and the location of a bot is always an integer.

Your bot

Your bot should be a function, in any object oriented language that has arrays, integers, strings, and functions. Note that all submissions will be converted to Javascript, to make things simple. To store information between moves, use botNotes.storeData(key, value) and botNotes.getData(key, value). You may not store or access data any way, other than that which is provided through the parameters and botNotes. You should create a function that, when called, returns a string north, east, south, west, or none. There will be 3 arguments for the function:

  • An object with four integers (locationX, locationY, coins, arenaLength), your current location, your coins, and the length of the arena

  • A multidimensional array with the X and Y coordinates of other bots, and their coin count, ex-[[0,5,4],[4,7,1],[7,4,12]]

  • An array with the coin locations listed (Gold is always first)

This is a king of the hill challenge, Standard Loopholes prohibited. Your function will be run several thousand times, each time allowed one "Move". Note that if the game exceeds 20,000 moves, the bot with the most coins wins. This will be done 8,000 times, to remove randomness.

Chatroom: https://chat.stackexchange.com/rooms/81347/gold-collectors-koth

Prizes:

First Place: 100-point bounty
Community Favorite: 15-point accepted answer

Winners:

First Place: TBTPTGCBCBA
Second Place: Big King Little Hill
Third Place: Potentially Victorious
Fourth Place: Polite Near-Sighted Drunk Bot
Fifth Place: Safety Coin

\$\endgroup\$
17
  • 6
    \$\begingroup\$ "Note that all submissions will be converted to Javascript, to make things simple." How is this supposed to work? Do you make the conversion? \$\endgroup\$
    – Laikoni
    Aug 8, 2018 at 14:20
  • 23
    \$\begingroup\$ There's nothing wrong with a koth only allowing a single language, especially one as widely spread as JavaScript. Rather than ambiguously "converting" answers to JavaScript (presumably yourself and by hand) you should simply limit the challenge to JS only. We've had plenty of Java-only and Python-only koths in the past, after all. \$\endgroup\$
    – Mayube
    Aug 8, 2018 at 14:23
  • 2
    \$\begingroup\$ A version of this where you control acceleration instead of position would be pretty cool. \$\endgroup\$
    – akozi
    Aug 8, 2018 at 19:21
  • 13
    \$\begingroup\$ To everyone: There are waaaay too many comments already. Do not leave useless comments such as "+1, nice bot", and please delete your comments if it's redundant. We are not a typical Q&A site, but nobody likes reading hundreds of commands. \$\endgroup\$
    – DELETE_ME
    Aug 9, 2018 at 5:16
  • 5
    \$\begingroup\$ (To my own question): According to N.P. in chat, it is the latter: all the bots move, then all the conflicts get resolved, then all the coin pickups occur, then all the new coins are placed. \$\endgroup\$
    – BradC
    Aug 9, 2018 at 20:59

34 Answers 34

1
2
0
\$\begingroup\$

Seeker.Armageddon

function(me, others, coins) {
    var x = me.locationX;
    var y = me.locationY;
    var dirs = [];
    for (var i = 0; i < others.length; i++) {
        if (Math.abs(others[i][0] - x) <= 3 && Math.abs(others[i][0] - y) <= 3) {
            if (others[i][3] < me.coins && others[i][3] * 0.85 > 5) {
                if (Math.abs(others[i][0] - x) > Math.abs(others[i][1] - y)) {
                    if (others[i][0] - x < 0) {
                        dirs.push('west');
                    } else {
                        dirs.push('east');
                    }
                } else if (Math.abs(others[i][0] - x) < Math.abs(others[i][1] - y)) {
                    if (others[i][1] - y < 0) {
                        dirs.push('north');
                    } else {
                        dirs.push('south');
                    }
                } else {
                    if (Math.random() < 0.5) {
                        if (others[i][0] - x < 0) {
                            dirs.push('west');
                        } else {
                            dirs.push('east');
                        }
                    } else {
                        if (others[i][1] - y < 0) {
                            dirs.push('north');
                        } else {
                            dirs.push('south');
                        }
                    }
                }
            } else if (others[i][3] >= me.coins) {
                if (Math.abs(others[i][0] - x) < Math.abs(others[i][1] - y)) {
                    if (others[i][0] - x < 0) {
                        dirs.push('east');
                    } else {
                        dirs.push('west');
                    }
                } else if (Math.abs(others[i][0] - x) > Math.abs(others[i][1] - y)) {
                    if (others[i][1] - y < 0) {
                        dirs.push('south');
                    } else {
                        dirs.push('north');
                    }
                } else {
                    if (Math.random() < 0.5) {
                        if (others[i][0] - x < 0) {
                            dirs.push('east');
                        } else {
                            dirs.push('west');
                        }
                    } else {
                        if (others[i][1] - y < 0) {
                            dirs.push('south');
                        } else {
                            dirs.push('north');
                        }
                    }
                }
            }
        }
    }
    for (i = 1; i < 5; i++) {
        if (Math.abs(coins[i][0] - x) <= 5 && Math.abs(coins[i][1] - y) <= 5) {
            if (Math.abs(coins[i][0] - x) > Math.abs(coins[i][1] - y)) {
                if (coins[i][0] - x < 0) {
                    dirs.push('west');
                } else {
                    dirs.push('east');
                }
            } else if (Math.abs(coins[i][0] - x) < Math.abs(coins[i][1] - y)) {
                if (coins[i][1] - y < 0) {
                    dirs.push('north');
                } else {
                    dirs.push('south');
                }
            } else {
                if (Math.random() < 0.5) {
                    if (coins[i][0] - x < 0) {
                        dirs.push('west');
                    } else {
                        dirs.push('east');
                    }
                } else {
                    if (coins[i][1] - y < 0) {
                        dirs.push('north');
                    } else {
                        dirs.push('south');
                    }
                }
            }
        }
    }
    var fin = [];
    for (i = 0; i < dirs.length; i++) {
        if (dirs[i] == 'north' && y !== 0 && fin.indexOf('north') == -1) {
            fin.push('north');
        } else if (dirs[i] == 'east' && x != me.arenaLength - 1 && fin.indexOf('east') == -1) {
            fin.push('east');
        } else if (dirs[i] == 'west' && x !== 0 && fin.indexOf('west') == -1) {
            fin.push('west');
        } else if (dirs[i] == 'south' && y != me.arenaLength && fin.indexOf('south') == -1) {
            fin.push('south');
        }
    }
    if (fin.length > 1) {
        return fin[randInt(0, fin.length - 1)];
    } else if (fin.length == 1) {
        return fin[0];
    } else {
        return 'none';
    }
}

Seeker.Armageddon is a bot of few thoughts. He checks for nearby coins, and darts over to them. He carefully avoids the gold coins, since they attract big, bad Uberbots. He can run from bots, but not well. He also pursues smaller bots that will earn him profit.

\$\endgroup\$
0
\$\begingroup\$

Hunter.Armageddon

One last bot for now

    //Hunter.Armageddon: Designed to move carefully around, and hunt bots and coins. Made to win
    function(me, others, coins) {
        var x = me.locationX;
        var y = me.locationY;

        var enemies = [];
        var threats = [];
        var targets = [];
        var dirs = [];
        var secure = [true, true, true, true];

        var meTo = (loc) => (Math.abs(x - loc[0]) + Math.abs(y - loc[1]));
        var inSquare = (loc, r) => (Math.abs(loc[0] - x) <= r && Math.abs(loc[1] - y) <= r);
        var distance = (from, loc) => (Math.abs(from[0] - loc[0]) + Math.abs(from[1] - loc[1]));
        var attackRange = (from, check) => {
            for (var i = 0; i < check.length; i++) {
                if (distance(check[i], from) == 1) {
                    return true;
                }
            }
            return false;
        };
        var dirStr = (dir) => (['north','east','south','west'][dir]);

        var i, n, l, o;
        for (i = 0; i < others.length; i++) {
            o = others[i];
            if (o[2] >= me.coins) {
                enemies.push(o);
            } else {
                targets.push([o[0], o[1], Math.ceil(o[2] * 0.85), meTo(o), true]);
            }
        }
        for (i = 1; i < 5; i++) {
            o = coins[i];
            targets.push([o[0], o[1], 2, meTo(o), false]);
        }
        targets.push([coins[0][0], coins[0][1], 5, meTo([coins[0][0], coins[0][1]]), false]);
        targets.sort((a, b) => ((-(b[3]) + b[2]) - (-(a[3]) + a[2])));
        for (i = 0; i < enemies.length; i++) {
            o = enemies[i];
            if (inSquare(o, 3)) {
                threats.push(o);
            }
        }
        for (i = 0; i < targets.length; i++) {
            o = targets[i];
            if (o[5] && Math.random() < 0.35 && threats.length === 0) {
                return 'none';
            }
            if (o[0] == x && o[1] + 1 == y && !(attackRange(o, threats))) {
                return 'north';
            }
            if (o[0] == x && o[1] - 1 == y && !(attackRange(o, threats))) {
                return 'south';
            }
            if (o[0] + 1 == x && o[1] == y && !(attackRange(o, threats))) {
                return 'west';
            }
            if (o[0] - 1 == x && o[1] == y && !(attackRange(o, threats))) {
                return 'east';
            }
        }
        if (x === 0 || attackRange([x - 1, y], threats)) {
            secure[3] = false;
        }
        if (y === 0 || attackRange([x, y - 1], threats)) {
            secure[0] = false;
        }
        if (y == me.arenaLength - 1 || attackRange([x, y + 1], threats)) {
            secure[2] = false;
        }
        if (x == me.arenaLength - 1 || attackRange([x + 1, y], threats)) {
            secure[1] = false;
        }
        for (i = 0; i < targets.length; i++) {
            o = targets[i];
            if (o[0] == x) {
                if (o[1] < y) {
                    dirs.push(0);
                } else {
                    dirs.push(2);
                }
            } else if (o[1] == y) {
                if (o[0] < x) {
                    dirs.push(3);
                } else {
                    dirs.push(1);
                }
            } else if (Math.abs(o[0] - x) < Math.abs(o[1] - y)) {
                if (o[1] < y) {
                    dirs.push(0);
                } else {
                    dirs.push(2);
                }
                if (o[0] < x) {
                    dirs.push(3);
                } else {
                    dirs.push(1);
                }
            } else if (Math.abs(o[0] - x) > Math.abs(o[1] - y)) {
                if (o[0] < x) {
                    dirs.push(3);
                } else {
                    dirs.push(1);
                }
                if (o[1] < y) {
                    dirs.push(0);
                } else {
                    dirs.push(2);
                }
            }
        }
        dirs.push(0, 1, 2, 3);
        for (i = 0; i < dirs.length; i++) {
            o = dirs[i];
            if (secure[o]) {
                return dirStr(o);
            }
        }
        return 'none';
    }

A master warrior that seeks coins while avoiding enemies, and hunts victims for coins

\$\endgroup\$
1
  • \$\begingroup\$ Just updated him to be a winner \$\endgroup\$ Aug 14, 2018 at 18:01
0
\$\begingroup\$

CloseCoin

Conquerer of Battles

    function(me,others,coins){
        var x = me.locationX;
        var y = me.locationY;
        var pref = [];
        var safe = [true, true, true, true];
        var dist = (loc) => (Math.abs(loc[0] - x) + Math.abs(loc[1] - y));
        var inSquare = (loc, r) => (Math.abs(loc[0] - x) <= r && Math.abs(loc[1] - y) <= r);
        var b = (loc, X, Y) => (Math.abs(loc[0] - X) + Math.abs(loc[1] - Y));
        var a = (loc, v) => (Math.abs(loc - v));
        var i, n, o, p, t;
        for (i = 0; i < coins.length; i++) {
            o = coins[i];
            if (t === undefined || dist(o) <= dist(t)) {
                t = o;
            }
        }
        if (x == 0) {
            safe[3] = false;
        }
        if (y == 0) {
            safe[0] = false;
        }
        if (x == me.arenaLength - 1) {
            safe[1] = false;
        }
        if (y == me.arenaLength - 1) {
            safe[2] = false;
        }
        for (i = 0; i < others.length; i++) {
            o = others[i];
            if (o[2] >= me.coins) {
                if (b(o, x + 1, y) == 1) {
                    safe[1] = false;
                }
                if (b(o, x, y + 1) == 1) {
                    safe[2] = false;
                }
                if (b(o, x, y - 1) == 1) {
                    safe[0] = false;
                }
                if (b(o, x - 1, y) == 1) {
                    safe[3] = false;
                }
            } else {
                if (arrayEqual([x + 1, y], o.slice(0,1))) {
                    pref.push(1);
                }
                if (arrayEqual([x, y + 1], o.slice(0,1))) {
                    pref.push(2);
                }
                if (arrayEqual([x, y - 1], o.slice(0,1))) {
                    pref.push(0);
                }
                if (arrayEqual([x - 1, y], o.slice(0,1))) {
                    pref.push(3);
                }
                if (inSquare(o, 3) && Math.ceil(o[2] * 0.85) > 2) {
                    p = botNotes.getData("chase");
                    if (p) {
                        if (p < 4) {
                            t = o;
                            botNotes.storeData("chase", p + 1);
                        } else {
                            botNotes.storeData("chase", false);
                        }
                    }
                }
            }
        }
        if (x !== t[0]) {
            if (x < t[0]) {
                pref.push(1);
            } else {
                pref.push(3);
            }
            if (y < t[1]) {
                pref.push(2);
            } else if (y > t[1]) {
                pref.push(0);
            }
        } else if (y !== t[1]) {
            if (y < t[1]) {
                pref.push(2);
            } else if (y > t[1]) {
                pref.push(0);
            }
            if (x < t[0]) {
                pref.push(1);
            } else {
                pref.push(3);
            }
        }
        pref.push(0, 1, 2, 3);
        for (i = 0; i < 3; i++) {
            if (safe[pref[i]]) {
                return ['north','east','south','west'][pref[i]]
            }
        }
        return 'none';
    }

He will crush you under his boot, and then collect the coins that "Should have been yours"

\$\endgroup\$
0
\$\begingroup\$

BotsAreMoney

function(me,maybecoins,coins) {
    function dist(a,b){
        return Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]);
    }
    var mycoin = null, indanger = {n:false,s:false,e:false,w:false}, 
        notallowed = {n:false,s:false,e:false,w:false}, nearestcoin = [0,0,9999], 
        nearestmaybe = [0,0,9999], mydist, i, j;
    if(me.locationY == 0)                   notallowed.n = true;
    if(me.locationY == me.arenaLength-1)    notallowed.s = true;
    if(me.locationX == me.arenaLength-1)    notallowed.e = true;
    if(me.locationX == 0)                   notallowed.w = true;
    for(j=0;j<maybecoins.length;j++){
        if(maybecoins[j][2] > me.coins){
            if(maybecoins[j][0]-1 == me.locationX && maybecoins[j][1] == me.locationY){
                indanger.e = maybecoins[2];
            }
            else if(maybecoins[j][0]+1 == me.locationX && maybecoins[j][1] == me.locationY){
                indanger.w = maybecoins[2];
            }
            else if(maybecoins[j][0] == me.locationX && maybecoins[j][1]-1 == me.locationY){
                indanger.s = maybecoins[2];
            }
            else if(maybecoins[j][0] == me.locationX && maybecoins[j][1]+1 == me.locationY){
                indanger.n = maybecoins[2];
            }
        }
        else if(maybecoins[j][2] > 7 && maybecoins[j][2] < me.coins){
            mydist = dist([me.locationX,me.locationY],maybecoins[j]);
            maybecoins[j][3] = mydist;
            if(mydist < nearestmaybe[2]){
                nearestmaybe = [maybecoins[j][0],maybecoins[j][1],mydist];
            }
        }
    }
    for(i=0;i<coins.length && mycoin==null;i++){
        mycoin = coins[i];
        mydist = dist([me.locationX,me.locationY],coins[i]);
        if(mydist < nearestcoin[2]){
            nearestcoin = [mycoin[0],mycoin[1],mydist];
        }
        for(j=0;j<maybecoins.length;j++){
            if(dist(maybecoins[j],coins[i]) <= mydist){
                mycoin = null;
                break;
            }
        }
    }
    if(nearestcoin[2] < 9999 && nearestmaybe[2] < 9999 && nearestmaybe[2] < nearestcoin[2]-3){
        if(nearestmaybe[1] < me.locationY && !indanger.n && !notallowed.n)      return 'north';
        else if(nearestmaybe[1] > me.locationY && !indanger.s && !notallowed.s) return 'south';
        else if(nearestmaybe[0] > me.locationX && !indanger.e && !notallowed.e) return 'east';
        else if(nearestmaybe[0] < me.locationX && !indanger.w && !notallowed.w) return 'west';
    }
    if(mycoin != null){
        if(mycoin[1] < me.locationY)            return 'north';
        else if(mycoin[1] > me.locationY)       return 'south';
        else if(mycoin[0] > me.locationX)       return 'east';
        else if(mycoin[0] < me.locationX)       return 'west';
        else                                    return 'none';
    }
    if((indanger.n !== false || notallowed.n) && (indanger.s !== false || notallowed.s) && (indanger.e !== false || notallowed.e) && (indanger.w !== false || notallowed.w)){
        if(indanger.n >= indanger.s && indanger.n >= indanger.e && indanger.n >= indanger.w && !notallowed.n)   return 'north';
        if(indanger.s >= indanger.n && indanger.s >= indanger.e && indanger.s >= indanger.w && !notallowed.s)   return 'south';
        if(indanger.e >= indanger.s && indanger.e >= indanger.n && indanger.e >= indanger.w && !notallowed.e)   return 'east';
        if(indanger.w >= indanger.s && indanger.w >= indanger.e && indanger.w >= indanger.n && !notallowed.w)   return 'west';
    }
    else if((indanger.s || indanger.e || indanger.w) && indanger.n === false)       return 'north';
    else if((indanger.n || indanger.e || indanger.w) && indanger.s === false)       return 'south';
    else if((indanger.n || indanger.s || indanger.w) && indanger.e === false)       return 'east';
    else if((indanger.n || indanger.s || indanger.e) && indanger.w === false)       return 'west';
    if(notallowed.n)                            return 'south';
    if(notallowed.s)                            return 'north';
    if(notallowed.e)                            return 'west';
    if(notallowed.w)                            return 'east';
    if(nearestcoin[2] < 9999){
        if(nearestcoin[1] < me.locationY)       return 'north';
        else if(nearestcoin[1] > me.locationY)  return 'south';
        else if(nearestcoin[0] > me.locationX)  return 'east';
        else if(nearestcoin[0] < me.locationX)  return 'west';
        else                                    return 'none';
    }
    return 'none';
}

Would still like to tweak this a bit, but it'll have to do for now.

Logic (picks first possible):

  • Goes for nearby bots with valuable coins
  • Goes for coins that only he can get
  • Avoids bigger bots (attempts a phase-through if surrounded)
  • Avoids the edges
  • Heads for nearest coin
\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.