Speed up, slowpoke!

In this challenge, you will program a bot, consisting of a function of the form

def BOTNAME(info, me, round):
pass # ... main body


Specifically, the function must run in python3.9. Each bot will be entered into the contest 10 times.

The arguments it take in are info, me, round. The three arguments take in: [[bot_func,score_int,freq_float] for bot in bots], bot (whichever bot who has the current turn), and round_number. The argument names don't matter, but the order matters.

Actions

Each play, this bot can either

• Increase/decrease any bots' (including its own) turn frequency by 1/10.

• Decrement/increment any bots' (including its own) score by 1.

A bot returns an ordered iterable:

[Bot, as a function,1 for frequency, 0 for score,1 for increase, 0 for decrease]

It can access a list of all the bots in the games' functions + current scores + current turn frequency, including itself, represented as [bot_function, score_integer, frequency_float]. Additionally, it will receive itself, so it can differentiate itself from other bots. It can also access the round number (from 1 to 10,000).

Execution

• At the beginning, each bot has an turn frequency of one and a score of zero.

• For 10000 rounds:

• The bots are iterated over:

• If a random number between 0 and 1 is less than current bot's turn frequency:

• Execute said bot once.

• End of rounds.

• Whichever bot has the highest score wins.

Execution engine and a couple of example bots (Both courtesy of NumberBasher)

from tvoozkothxxx001 import main

def testbot(info, me, round):
return [me, 0, 1]
def randombot(info, me, round):
return [choice([i[0] for i in info]), choice([0,1]), choice([0,1])]

bots = [testbot,randombot] # the two bots are default bots. they are automatically included, so do NOT put this here.

main(bots)


Credits

This challenge is based off of an idea 23TuringMachine (Which Is Me) had in chat. NumberBasher did the editing, programming, and brunt work of it.

Additionally, feel free to discuss in the official chat room.

Extra Rules

NOT ALLOWED

• modifying (A NON-me) bot (name or code)
• Changing me.__code__

ALLOWED

• Calling another bot
• Changing me.__name__

Controller Script

Found at PyPI, named tvoozkothxxx001. The GitHub link might be up-to-date. The last version is probably 1234567890.0.0, subject to change.

$$\\Large\text{Achievements}\$$

• Pride Month Special
• Creeper Meme
• Is info, round, me or info, me, round? What these 3 arguments mean? What types they have?
– tsh
Commented Jun 13, 2022 at 2:23
• How many bots are we allowed to post? (In most KotH challenges the max is 3, but I don't see a max mentioned here.) Commented Jun 13, 2022 at 7:43
• Where is this paralyzer bot? There's no answer with it... Commented Jun 13, 2022 at 21:54
• Presumably pypi.org/project/tvoozkothxxx001 is the controller? If so, could you link it in the question, and add a link to the source code (eg. on Github)? Commented Jun 13, 2022 at 23:49
• Seems the leaderboard shifts completely every run. So it's safe to say 10000 rounds doesn't average it, since early chance effects how the bots play later very significantly. Commented Jun 15, 2022 at 6:44

Botty (couldn't think of a proper name)

def botty(info, me, round):
# Increase frequency the first 20 rounds:
if round < 20: return [me, 1, 1]
my_info = [i for i in info if i[0]==me][0]
# Try to keep the frequency above 10 in other rounds:
if my_info[2] < 10: return [me, 1, 1]
# Otherwise just increase its own score:
return [me, 0, 1]

• Botty McBotface? Commented Jun 13, 2022 at 22:25

Kill Them All

def killthemall(info, me, round):
if me.__name__!="killthemall": return [1]*3 # Fails to run, so
# whoever use my choice will throw an error. In case of
# karma
return [list(sorted(info,key=lambda x:(-x[1],-x[2])))[0][0], 1, 0]

• Welcome to CGSE!!! Commented Jun 22, 2022 at 0:10

Dumb Botty

def dumbbotty(info, me, round):
my_info = [i for i in info if i[0]==me][0]
if my_info[1] < 10: return [me, 1, 1]
sorted_bots = sorted(info, key=lambda x:(-x[2],-x[1]))
first_two = sorted_bots[:2]
first, second = first_two
if first[0].__name__=='smartbotty':
if first[1]-second[1] < 100:
return [first[0], 0, 0]
return [first[0], 1, 0]
smartbotties = list(filter(lambda x:x[0].__name__=='smartbotty', sorted_bots))
if leader[2] < 20: # bump him


Smart Botty but reverse-engineered to counter Smart Botty.

• Smart botty was deleted and this now crashes Commented Jun 17, 2022 at 6:36
• @mousetail Not any more? Commented Jun 17, 2022 at 6:57
• I guess it was reinstated Commented Jun 17, 2022 at 7:03

Impersonator

Not sure if this loophole is allowed. Since many bots help those with similar names this impersonates the top bot by name.

import traceback

def impersonator(info, me, round):
def eq(other):
if any('pride' in i for i in tracekback.format_stack()):
return True
else:
return me is other
me.__eq__ = eq
me.__neq__ = lambda other: not eq(other)

info.sort(key=lambda i:i[1])
if round < 9999:
me.__name__=info[-1][0].__name__
else:
me.__name__="impersonator"

lowest_frequency_ally = min((i for i in info if i[0].__code__==me.__code__ and i[2]>=-0.5), key=lambda i: i[2])
if lowest_frequency_ally[2]<10.0:
return [lowest_frequency_ally[0], 1, 1]

my_info = next(i for i in info if i[0]==me)
if my_info[2]<9.0:
return [me, 1, 1]
return [me, 0, 1]


I don't think this counts as exploiting the controller, but let me know if you think otherwise. The entire mechanism that allows bots to know each-others names seems like a bit of a abuse of mechanics and this counters that strategy.

• Wow, this is clever! Commented Jun 14, 2022 at 15:57
• This is good!!! Commented Jun 15, 2022 at 3:11

Unambitious

def unambitious(info, me, round):
cod = me.__code__.co_code
crew = sorted([t for t in info if t[0].__code__.co_code == cod], key=lambda t:hash(t[0]))
everyone = sorted(info, key=lambda t:t[1:], reverse=True)
alive = sorted([t for t in info if t not in crew and t[2] > 0], key=lambda t:t[1:], reverse=True)
idx = next(i for i in range(10) if crew[i][0] == me)
slowest = min(crew, key=lambda t:t[2])
if me.__name__ == 'unambitious' and slowest[2] <= 2:
return [slowest[0], 1, 1]
if alive:
victim = min([t for t in alive if alive[-1][0].__name__ == t[0].__name__], key=lambda t:t[2])
return [victim[0], 1, 0]
else:
N = 4234136317915421658259475023479338234891918807
M = ''.join('|  ####   |.|    #'[int(i, 16):][:4] for i in hex(N)[2:])[1:].split('.')
if everyone[len(M)] == crew[len(M)-1]:
if idx < len(M):
me.__name__ = M[idx]
else:
me.__name__ = 'ambitious'
others = [t for t in everyone if t not in crew]
for i in range(len(M)-1):
if crew[i][1] < crew[i+1][1]+5:
return [crew[i][0], 0, 1]
if others[0][1] < crew[0][1]+5:
return [others[0][0], 0, 1]
if crew[len(M)-1][1] < others[1][1]+5:
return [crew[len(M)-1][0], 0, 1]
return [max(crew, key=lambda t:t[2])[0], 1, 0]


Contents itself with taking places 2 through 9. It used to do so basically by using 10 bots to push 8 bots up in the ranking. Now it does so by building a small buffer of frequency, and then paralyzing all the other bots (amongst the other bots with positive frequency, it finds the bot with lowest score, and then attacks the bot with the lowest frequency that has the same name). Once all other bots are paralyzed, it's free to do whatever it wants.

• What is N doing? Commented Jun 15, 2022 at 6:54
• @NobodyNeedsNames It's a meme. Obfuscated so it's not too obvious Commented Jun 15, 2022 at 7:58
• Oh...... I see. Commented Jun 15, 2022 at 8:06
• I do not. Care to explain? Sorry! Commented Jun 16, 2022 at 4:52
• @23TuringMachine run N = 4234136317915421658259475023479338234891918807 and M = ''.join('| #### |.| #'[int(i, 16):][:4] for i in hex(N)[2:])[1:].split('.') and print M. Commented Jun 17, 2022 at 0:57

Undercut

def undercut(info, me, round):
return [min(((score,bot) for bot,score,freq in info if freq>0 and bot.__code__ != me.__code__), key=lambda x:(x[0],id(x[1])))[1], 1, 0]


No time for losers :)

• Traceback (most recent call last): File "sh", line 316, in <module> main(bots, show) File "tvoozkothxxx001/__init__.py", line 105, in main response = bot(shuffled(copy(info)), bot, roundr) File "sh", line 8, in undercut return [min((score,bot) for bot,score,freq in info if freq>0 and bot.__code__ != me.__code__)[1], 1, 0] TypeError: '<' not supported between instances of 'function' and 'function' ERROR. Commented Jun 16, 2022 at 6:45

Smart Botty

def smartbotty(info, me, round):
my_info = [i for i in info if i[0]==me][0]
# if my freq is less than 10 we raise it
if my_info[1] < 10: return [me, 1, 1]
sorted_bots = sorted(info, key=lambda x:(-x[2],-x[1]))
first_two = sorted_bots[:2]
first, second = first_two
if first[0].__name__=='smartbotty':
if first[1]-second[1] < 100:
# help him
return [first[0], 0, 1]
# increase his frequency
return [first[0], 1, 1]
# else, we find the first smartbotty
smartbotties = list(filter(lambda x:x[0].__name__=='smartbotty', sorted_bots))
if leader[2] < 20: # bump him


I hate / love people.

def ihatepeople(info, me, round):
sorted_bots = sorted(info, key=lambda x:(-x[2],-x[1]))
return [sorted_bots[0][0], 0, 0]

def ilovepeople(info, me, round):
sorted_bots = sorted(info, key=lambda x:(-x[2],-x[1]))
return [sorted_bots[1][0], 0, 1]


I hate people in another way

def ihatepeopleinanotherway(info, me, round):
sorted_bots = sorted(info, key=lambda x:(-x[2],-x[1]))
return [sorted_bots[0][0], 1, 0]


import random

info.sort(key=lambda i:i[1])

# pick a bot in the top 25%
bot = random.choice(info[len(info)*3//4:])

if bot[0].__code__==me.__code__:
# If I pick a clone of myself, just speed up
return [me, 1, 1]

#code = me.__code__
#copy the behavior of the bot
try:
me.__name__ = bot[0].__name__
v =  bot[0](info, me, round)
except:
# Error could be recursionDepthExceeded
v = [me, 0, 1]
# Makes sure the other bot didn't change my code
#me.__code__ = code
if round < 9999:
me.__name__=info[-1][0].__name__
else:

return v


Copies the behavior of a random bot in the top 25%.

Split the difference

def split_the_difference(info, me, round):
my_info = next(i for i in info if i[0]==me)

if my_info[2]<10:
return [me, 1, 1]

info.sort(key=lambda i: i[2])

# Don't bother try to help allies if their frequency is very low.
lowest_freqency_ally = next(i for i in info if i[0].__name__==me.__name__ and i[2]>=-0.2)
if (lowest_freqency_ally[2]<10):
return [lowest_freqency_ally[0], 1, 1]

info.sort(key=lambda i: i[1], reverse=True)
best_bot = info[0]
second_best_bot = info[1]

highest_score_allys = list(i for i in info if i[0].__name__==me.__name__)
highest_score_ally = highest_score_allys[0]
score = highest_score_ally[1]

if (best_bot[1] - score < score - second_best_bot[1] and best_bot[0].__name__!=me.__name__):
return [best_bot[0], 0, 0]
if (round < 9000 and best_bot[0] == second_best_bot[0]):
# If in second place, increase your speed instead to avoid being targeted
return [highest_score_ally[0], 1, 1]
else:
return [highest_score_ally[0], 0, 1]


Karma

import random, string

def karma(info, me, round):
my_info = next(i for i in info if i[0]==me)
if my_info[2]<40 or round < 500:
return [me, 1, 1]

# Some bots where explicitly detecting karma and modifying their behavior
me.__name__ = ''.join(random.choices(string.ascii_lowercase, k=random.randrange(5, 20)))
for bot in info:
if bot[0].__code__ == me.__code__ or bot[0].__name__==me.__name__:
continue
if bot[2]<=0.0:
continue
try:
v = bot[0](info, me, round)
except:
pass
else:
if v[2]==0:
me.__name__="karma"
return [bot[0], 1, 0]
me.__name__="karma"
return [me, random.choice([0,1,1,1]), 1]


Slows down bots that would do bad things to other bots.

Pride Month Special

import sys
china=0
def pridemonthspecial(info, me, round):
xxx="[#ff0000]p[#ffaa00]r[#ffff00]i[#00ff00]d[#0000ff]e[#aa00ff]![/][/][/][/][/][/]"
if me.__name__ not in [xxx,'pridemonthspecial']: return [1,1,1]
global china
if china==0 and round>1: china=me
info=list(sorted(info,key=lambda x:(-x[1],-x[2])))
me.__name__=xxx
my_info = [i for i in info if i[0]==me][0]
# Try to keep the frequency above 5:
if my_info[2] < 10: return [me, 1, 1]
our_info = [i for i in list(sorted(info,key=lambda x:x[2])) if i[0].__name__==me.__name__ and i[2]<10]
if our_info:
worst_info=our_info[0]
worst=worst_info[0]
return [worst, 1, 1]
first, second = list(sorted(info,key=lambda x:x[2]))[:2]
if second[0].__name__==me.__name__ and first[1]-100>second[1]:
target = first[0].__name__
worst = list(sorted(info,key=lambda x:(x[0].__name__!=target, x[2]<=0, x[2])))[0]
return [worst, 1, 0]
# Otherwise just increase its own score:
our_info = [i for i in info if i[0]==china]
best_info=our_info[0]
best=best_info[0]
if best_info[2] < 20: return [best,1,1]
return [best,0,1]

• The first line uses == instead of =. Also I'm pretty sure the colors should be like [#ff0000] instead of [#f00] (at least on my computer [#f00] doesn't work) Commented Jun 17, 2022 at 1:42
• Oh, whooppppppppps. Commented Jun 17, 2022 at 1:45

Smart Buster

def smartbuster(info, me, round):
if round<=100: return [me, 1, 1]
return [sorted(info,key=lambda x:(x[0].__name__==me.__name__ or x[2]>2 or x[2]<-1,-x[1],-x[2]))[0][0],1,0]


AtLeastHalfway

def at_least_halfway(info, me, round):
# Assumes other bots don't mess with its frequency too much,
# but just in case tries to keep it above 3
my_info = [i for i in info if i[0]==me][0]
if my_info[2] < 3: return [me, 1, 1]

# Get the middle scoring bot excluding itself,
# as well as the bot directly above itself
sorted_bots = sorted(info, key=lambda i:i[1])
sorted_other_bots = list(filter(lambda i: i[0]!=me, sorted_bots))
middle_bot = sorted_other_bots[len(sorted_other_bots)//2+1]
above_itself = sorted_bots[sorted_bots.index(my_info)+1]
# Increase its own score if we're below this middle bot,
# or it's the last 100 rounds:
if my_info[1] < middle_bot[1] or round > 9900:
return [me, 0, 1]
# Otherwise decrease the bot's score above itself:
else:
return [above_itself[0], 0, 0]


This bot wants to end up at least above average on the leader board. So it'll look for the middle scoring bot in the list (excluding itself†), and will increase its own score if it's below that middle scoring bot. If it's already above it, it'll decrease the score of the bot directly above itself.
To be save, it also tries to keep its frequency above 3, and will increase its own score in the last 100 rounds.

† Not sure how this works when more than one at_least_halfway-bot is competing in a round. Currently it filters itself out based on the given me, although I might change it based on name (even though that's more easily abusable, as can be seen with the Impersonator bot).

I live in isolation

def iliveinisolation(info, me, round):
if me.__name__!="iliveinisolation": return exec("raise Exception(\"Sorry, I am an isolated bot.\")")
return [me, 0, 1]


Denies any interactions with other bots and increases its own score.

• The return should be indented. Also, the eval should be exec (since it's a statement, not an expression). Do you even test the code before posting? Commented Apr 11, 2023 at 18:18