7
\$\begingroup\$

Background

So, nowadays the popular Prisoner's Dilemma variant is the Prisoner's Trilemma, where there are three options. I can easily see that being increased, so I figured

Why settle for three options, when we can have INFINITE options?

Therefore, I created the Floating Point Prisoner's ?Lemma.

Equations:

Each round, your score will be calculated as (\$a\$ is what Player 1 returns, \$b\$ is what Player 2 returns):

$$ \text{Player 1 expected score: }\quad 2ab+3(1-a)b+(1-a)(1-b) $$

$$ \text{Player 2 expected score: }\quad 2ab+3a(1-b)+(1-a)(1-b) $$

\$3\$ is the temptation payoff, the payoff \$a\$ gets if \$a\$ defects and \$b\$ cooperates. \$2\$ is the reward, for if both cooperate. \$1\$ is the punishment, for if both defect. The sucker's payoff is \$0\$, which is what \$a\$ gets when \$a\$ cooperates and \$b\$ defects.

Explanation of what floating point numbers mean in output

Basically, an output of 0.5 means that the figurative probability (The controller is almost deterministic, only matching up contestants at random) of cooperation is 0.5. This means that since the output is closer to 1 than 0 is, the opponent gets some score, but not as much as if the output of the contestant we're focusing on was 1.

Forbidden Stuff

  • Standard Loopholes are forbidden.
  • No interacting with the controller other then by returning values in the strategy function.
  • No interference with other bots (with global variables, other stuff)
  • Global Vars are Highly Discouraged. Instead, use the store dict.
  • More stuff may be added

Generic Stuff

It uses an equation from the wonderful fellows at https://math.stackexchange.com to determine what to do, with the floating point numbers correlating to probability of coop or defect. However, the controller is deterministic in terms of the scoring stuff, and the probabilities are not treated as probabilities. The equations are in the play function in the controller.

NOTE: When run, it'll sometimes print something like [[0, 28948.234], [1, 32083.23849], [2, 0]]. That's just an old debugging feature I forgot to remove.

Technical Stuff

Create a bot that can play this Python implementation of the Prisoner's ?Lemma. Make two functions, strategy and plan, that are in a similar format as the below examples. Store is cleared after every matchup, you can change this by commenting out the line in run in the controller that says

self.store = {
}

This is a basic bot template:

def strategy(is_new_game, store):
  # Put Stuff Here™. is_new_game tells the function if it's a new game. returns a value between 0 and 1, where 1 = coop and 0 = defect, and in-between stuff correlates to probability of coop or defect. Store is a dict for storage.
def plan(opmove, store):
  # opmove is the opponents move last round. This function shouldn't return anything. Put pass here if you don't use this.

Example Bots

♫Coop Bop Bot♫

#Example Contestant
def strategy(is_new_game):
  return 1

def plan(opmove):
  pass

Random

#Example Contestant
import random
def strategy(is_new_game):
  return random.random()
def plan(opmove):
  pass

Controller is at https://github.com/4D4850/KotH-Floating-Dilemma

Feel free to make a pull request.

Leaderboard

Random, 165500.78318694307
Helped, 147835.72861717656
Cooperator, 125285.07526747975
Random Alternator, 82809.27322624522
Tit for Tat, 51139.558474789665

If you don't see your bot, there was an error.

Note: Helped and Random Alternator needed to be slightly modified to run without errors. Also, there was a catastrophic bug in the scoring system, that is now fixed.

\$\endgroup\$
7
  • \$\begingroup\$ Sandbox: codegolf.meta.stackexchange.com/questions/2140/… \$\endgroup\$
    – 4D4850
    Jun 17 at 22:15
  • \$\begingroup\$ Just to be clear about store: each bot starts with a store which can be manipulated, right? \$\endgroup\$
    – user100690
    Jun 18 at 7:57
  • \$\begingroup\$ You define a value in the store dict on your own. They don't each have their own dicts predefined. \$\endgroup\$
    – 4D4850
    Jun 18 at 12:53
  • \$\begingroup\$ Chat room for general ?Lemma related discussion: chat.stackexchange.com/rooms/126625/… \$\endgroup\$
    – 4D4850
    Jun 18 at 13:48
  • \$\begingroup\$ Your controller uses the same self.store dict for both players. In cases where the same players play against each other, this leads to faulty results, because the bots actually influence each other. \$\endgroup\$
    – agtoever
    Jun 22 at 11:13
1
\$\begingroup\$

Helped

def strategy(is_new_game, store):
  if store and store['moves']:
    return store['moves'][-1]
  return .1
def plan(opmove, store):
  if opmove > .5:
    if store and store['moves']:
      store['moves'].append(opmove / 2)
    else:
      store['moves'] = [opmove / 2]
  else:
    if store and store['moves']:
      store['moves'].append(opmove * 2)
    else:
      store['moves'] = [opmove * 2]

Try it online!

Helped is a bot that depends on the opponent's previous moves. Picks higher next moves for lower previous moves, and lower ones for higher ones.

\$\endgroup\$
8
  • \$\begingroup\$ I'm not sure moves is a valid index. \$\endgroup\$ Jun 18 at 11:08
  • \$\begingroup\$ @StackMeter It's not an index. You see, store is a dictionary, not a list. \$\endgroup\$
    – user100690
    Jun 18 at 11:38
  • \$\begingroup\$ This seems neat. I'll run the first run today. \$\endgroup\$
    – 4D4850
    Jun 18 at 11:44
  • \$\begingroup\$ Although I prefer the term array rather than list. \$\endgroup\$
    – 4D4850
    Jun 18 at 12:59
  • \$\begingroup\$ @4D4850 So do I as I'm more comfortable working with JavaScript, but Python uses lists so I say "list" here and "array" with JS \$\endgroup\$
    – user100690
    Jun 18 at 13:36
1
\$\begingroup\$

Tit for Tat

def strategy(is_new_game, store):
    if is_new_game: return 1
    return store[0]
def plan(opmove, store):
    store[0]=opmove
\$\endgroup\$
1
  • 3
    \$\begingroup\$ @4D4850 Please stop editing the answers to make them work - leave a comment underneath with what should be done to fix it instead. I've rolled back your edit. att, feel free to roll my rollback back if you'd like their fix to stay \$\endgroup\$ Jun 19 at 16:04
0
\$\begingroup\$

Random Alternator

store[0] = 0
store[1] = 0
print(store)
import random
def strategy(is_new_game, store):
  if is_new_game or store[0]%100 < 10:
    store[1] += 1
    return random.random()
  else:
      store.append(store[1] + 1, (sum(store)/len(store)))
      store[1] += 1
      return sum(list(store)[1:])/len(list(store)[1:])
def plan(opmove, store):
  store.append(store[1] + 1, opmove)
  store[1] += 1
  store[0] += random.random() + random.random()
  return store

Randomly alternates between taking the total average of the moves and random moves in a random way (Hopefully, unexploitable).

\$\endgroup\$
6
  • \$\begingroup\$ Just FYI, store is a dict rather than an array. \$\endgroup\$
    – 4D4850
    Jun 18 at 11:46
  • \$\begingroup\$ Although I don't understand it well enough to edit it. \$\endgroup\$
    – 4D4850
    Jun 18 at 13:17
  • \$\begingroup\$ @4D4850 fixed it \$\endgroup\$ Jun 18 at 13:53
  • \$\begingroup\$ I still needed to slightly modify it, but I understood how to. \$\endgroup\$
    – 4D4850
    Jun 18 at 14:11
  • \$\begingroup\$ @4D4850 Thanks for the help. \$\endgroup\$ Jun 18 at 15:28
0
\$\begingroup\$

Defector

def strategy(n, s):
    return 0

def plan(o, s):
    pass

Always defects (returns 0).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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