;;;; strategies.ss: players for a ``prisoner's dilemma'' tournament ;;; John David Stone ;;; Department of Mathematics and Computer Science ;;; Grinnell College ;;; stone@math.grin.edu ;;; Original version: July 17, 1997 ;;; Last revised: July 2, 2001 ;;; The ``prisoner's dilemma'' is a game for two persons -- call them A and ;;; B. In each round of the game, each player independently selects one of ;;; two options, traditionally called ``cooperation'' and ``defection.'' ;;; The players then reveal their selections simultaneously and score ;;; points according to the following table: ;;; A's play B's play A's score B's score ;;; ------------------------------------------------------- ;;; cooperation cooperation 3 3 ;;; cooperation defection 0 5 ;;; defection cooperation 5 0 ;;; defection defection 1 1 ;;; Thus the game is symmetrical and does not favor either player. Since ;;; the scoring table is such that each player gets more points for ;;; defecting than for cooperating, no matter which option the other player ;;; selects, a rational player always defects if he sees the other player ;;; as an opponent and concerns himself only with trying to outscore the ;;; other player. Two such players, therefore, score one point each. A ;;; different kind of rational player sees the other player as a potential ;;; ally and chooses cooperation in the hope of obtaining a total of six ;;; points (the maximum) for the allies. ;;; Although this latter strategy is in one sense less certain to succeed, ;;; an additional reason for cooperating appear when the same players ;;; participate in several successive rounds of the game: Cooperation in ;;; early rounds may induce the other player to cooperate subsequently, to ;;; the advantage of both players. When such a multi-round game forms part ;;; of a tournament involving a large number of players, each successively ;;; paired with each, with the overall scores determined by adding the ;;; results of the individual matches, there is an even stronger reason to ;;; choose cooperation at least some of the time: If cooperation is ;;; reciprocal, a player who receives three points per round in many games ;;; will accumulate a higher total than a chronic defector who usually ;;; receives one point per round. It is even possible for a player who ;;; never outscores any of her opponents in a single match to place first ;;; in the overall tournament, if the other players obtain lower scores ;;; when matched to one another than when matched to her. ;;; A player in such a tournament is represented by a Scheme procedure that ;;; embodies his selection strategy as a function of the number of rounds ;;; previously played in the current match and the record of both players' ;;; selections in previous rounds. ;;; Here is a collection of players suggested by participants in various ;;; tournaments and workshops that I have staged or read about. ;;; From the Grinnell College Summer Computing Institute, 1987: ;;; The GOTCHA player uses the same strategy as LOOK-BACK, except that it ;;; defects in rounds 40 and 60 no matter what the other player has done. (define gotcha (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((member rounds-played '(39 59)) 'defection) (else (vector-ref your-plays (- rounds-played 1)))))) ;;; HOPEFUL cooperates in the first two rounds and thereafter plays a ;;; delayed LOOK-BACK strategy: It echoes the play its opponent made _two_ ;;; rounds earlier. (define hopeful (lambda (rounds-played my-plays your-plays) (if (< rounds-played 2) 'cooperation (vector-ref your-plays (- rounds-played 2))))) ;;; The JUST-MEAN player defects in every round, regardless of what the ;;; other player does. (define just-mean (lambda (rounds-played my-plays your-plays) 'defection)) ;;; The LOOK-BACK player cooperates in the first round. On every subsequent ;;; round, it does whatever the other player did in the previous round. ;;; (Another name for this player is TIT FOR TAT.) (define look-back (lambda (rounds-played my-plays your-plays) (if (zero? rounds-played) 'cooperation (vector-ref your-plays (- rounds-played 1))))) ;;; The OORE player cooperates in odd-numbered rounds and defects in ;;; even-numbered ones, no matter what the other player does. (define oore (lambda (rounds-played my-plays your-plays) (if (even? rounds-played) 'cooperation 'defection))) ;;; The OVERTIME player follows a pre-programmed sequence of acts of ;;; cooperation and defection, basing its choice entirely on the round ;;; number and not on the opponent's behavior. The pattern consists of ;;; alternating strings of cooperations and defections, growing longer and ;;; longer as the round number increases. After round 100, it always ;;; defects. (define overtime (lambda (rounds-played my-plays your-plays) (if (member rounds-played '(0 3 4 8 9 14 15 21 22 27 28 32 33 36 37 39 40 43 44 48 49 54 55 61 62 67 68 72 73 76 77 79 80 83 84 88 89 94 95 96 97 98 99)) 'cooperation 'defection))) ;;; SMARTSTRAT cooperates in the first round and and thereafter chooses its ;;; move according to the exchange that took place in the preceding round. ;;; It always defects if both sides defected in the previous round. If ;;; both sides cooperated in the previous round, SMARTSTRAT cooperates ;;; forty percent of the time and defects sixty percent, randomly. If ;;; SMARTSTRAT} got stung in the previous round, cooperating when the other ;;; player defected, it cooperates twenty percent of the time and defects ;;; eighty percent, randomly. Finally, after a successful sting of its ;;; own, SMARTSTRAT cooperates seventy percent of the time and defects ;;; thirty percent, randomly. (define smartstrat (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((eq? (vector-ref my-plays (- rounds-played 1)) 'defection) (cond ((eq? (vector-ref your-plays (- rounds-played 1)) 'defection) 'defection) ((< (random 10) 7) 'cooperation) (else 'defection))) ((eq? (vector-ref your-plays (- rounds-played 1)) 'defection) (if (zero? (random 5)) 'cooperation 'defection)) ((< (random 5) 2) 'cooperation) (else 'defection)))) ;;; TESTER defects in the first round, cooperates in the second round, and ;;; continues to alternate defection with cooperation as long as the other ;;; player does not defect. TESTER cooperates after the other player's ;;; first defection, but after that plays the same strategy as LOOK-BACK. (define tester (lambda (rounds-played my-plays your-plays) (let ((first-defection (let loop ((round-number 0)) (cond ((= round-number rounds-played) #f) ((eq? (vector-ref your-plays round-number) 'defection) round-number) (else (loop (+ round-number 1))))))) (cond ((not first-defection) (if (even? rounds-played) 'defection 'cooperation)) ((= first-defection (- rounds-played 1)) 'cooperation) (else (vector-ref your-plays (- rounds-played 1))))))) ;;; The ZERO-TWO player cooperates indefinitely as long as its opponent ;;; does not make the fatal mistake of defecting twice in a row; ZERO/TWO ;;; responds to this repeated defection by defecting in every subsequent ;;; round. (define zero-two (lambda (rounds-played my-plays your-plays) (let ((defected-twice-in-a-row (let loop ((round-number 1)) (cond ((<= rounds-played round-number) #f) ((and (eq? (vector-ref your-plays round-number) 'defection) (eq? (vector-ref your-plays (- round-number 1)) 'defection)) #t) (else (loop (+ round-number 1))))))) (cond ((< rounds-played 2) 'cooperation) (defected-twice-in-a-row 'defection) (else 'cooperation))))) ;;; From the Grinnell College Summer Computing Institute, 1988: ;;; The CHEAP player defects in the first round, but after that it plays ;;; the same strategy as LOOK-BACK. ;;; Designer: Jeff Dunn (define cheap (lambda (rounds-played my-plays your-plays) (if (zero? rounds-played) 'defection (vector-ref your-plays (- rounds-played 1))))) ;;; CHEEZY opens with a fixed pattern of cooperations and defections ;;; (cooperate in the first three rounds, defect in the next two, cooperate ;;; in the one after that), after which it cooperates if and only if its ;;; opponent has defected exactly twice (ever). ;;; Designer: Julie Baglan (define cheezy (lambda (rounds-played my-plays your-plays) (cond ((< rounds-played 3) 'cooperation) ((< rounds-played 5) 'defection) ((< rounds-played 6) 'cooperation) (else (let ((your-defections (let loop ((round-number 0) (defections 0)) (cond ((= round-number rounds-played) defections) ((eq? (vector-ref your-plays round-number) 'defection) (loop (+ round-number 1) (+ defections 1))) (else (loop (+ round-number 1) defections)))))) (if (= your-defections 2) 'defection 'cooperation)))))) ;;; The FEIN-2P player cooperates in the first round, chooses as its play ;;; in the second round whatever the other player did in the first round, ;;; and thereafter defects if and only if its opponent has defected within ;;; the two previous rounds. In other words, it plays like LOOK-BACK ;;; except that it ``punishes'' a defection twice instead of once. ;;; Designer: Ron Fein (define Fein-2p (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((= rounds-played 1) (vector-ref your-plays 0)) ((eq? (vector-ref your-plays (- rounds-played 1)) 'defection) 'defection) (else (vector-ref your-plays (- rounds-played 2)))))) ;;; The FEIN-PUNISHER player cooperates in the first round, and thereafter ;;; defects when the other player's previous move was a defection, when the ;;; other player has defected more than one-third of the time, and when the ;;; other player has defected more than half as often as FEIN-PUNISHER ;;; itself has. Moreover, when the other player defected two rounds back, ;;; FEIN-PUNISHER defects half the time, randomly, and when the other ;;; player defected three rounds back, FEIN-PUNISHER defects one-third of ;;; the time, randomly. ;;; Designer: Ron Fein (define Fein-punisher (let ((defection-counter (lambda (vec limit) (let loop ((round-number 0) (defections 0)) (cond ((= round-number limit) defections) ((eq? (vector-ref vec round-number) 'defection) (loop (+ round-number 1) (+ defections 1))) (else (loop (+ round-number 1) defections))))))) (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((eq? (vector-ref your-plays (- rounds-played 1)) 'defection) 'defection) (else (let ((your-defections (defection-counter your-plays rounds-played))) (cond ((< rounds-played (* 3 your-defections)) 'defection) ((< (* 2 (defection-counter my-plays rounds-played)) your-defections) 'defection) ((= rounds-played 1) 'cooperation) ((eq? (vector-ref your-plays (- rounds-played 2)) 'defection) (if (zero? (random 2)) 'defection 'cooperation)) ((= rounds-played 2) 'cooperation) ((eq? (vector-ref your-plays (- rounds-played 3)) 'defection) (if (zero? (random 3)) 'defection 'cooperation)) (else 'cooperation)))))))) ;;; The GEFANGENER player cooperates in the first three rounds, defects in ;;; the next two, plays in the sixth round as the other player has played ;;; in the majority of the first five rounds, and subsequently uses the ;;; same strategy as LOOK-BACK. ;;; Designer: Stefanie Lange (define gefangener (lambda (rounds-played my-plays your-plays) (cond ((< rounds-played 3) 'cooperation) ((< rounds-played 5) 'defection) ((< rounds-played 6) (let ((excessive-defection (let loop ((round-number 0) (defections 0)) (cond ((= round-number 6) #f) ((eq? (vector-ref your-plays round-number) 'cooperation) (loop (+ round-number 1) defections)) ((= defections 2) #t) (else (loop (+ round-number 1) (+ defections 1))))))) (if excessive-defection 'defection 'cooperation))) (else (vector-ref your-plays (- rounds-played 1)))))) ;;; The LIL-ACES player uses the LOOK-BACK strategy, except in the fourth, ;;; fifth, and sixth rounds. In the fourth and fifth rounds, it cooperates ;;; if the other player has cooperated in _any_ previous round. In the ;;; sixth round, it always cooperates. ;;; Designer: Kathy Baglan (define lil-aces (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((< rounds-played 3) (vector-ref your-plays (- rounds-played 1))) ((< rounds-played 5) (let loop ((round-number 0)) (cond ((= round-number rounds-played) 'defection) ((eq? (vector-ref your-plays round-number) 'cooperation) 'cooperation) (else (loop (+ round-number 1)))))) (else (vector-ref your-plays (- rounds-played 1)))))) ;;; PLAY-BY-MY-RULES is the same as FEIN-2P, except that if the other ;;; player ever defects twice in a row, PLAY-BY-MY-RULES defects in all ;;; subsequent rounds. ;;; Designer: Ron Fein (define play-by-my-rules (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((= rounds-played 1) (vector-ref your-plays 0)) ((eq? (vector-ref your-plays (- rounds-played 1)) 'defection) 'defection) ((eq? (vector-ref your-plays (- rounds-played 2)) 'defection) 'defection) (else (let ((defected-twice-in-a-row (let loop ((round-number 1)) (cond ((<= rounds-played round-number) #f) ((and (eq? (vector-ref your-plays round-number) 'defection) (eq? (vector-ref your-plays (- round-number 1)) 'defection)) #t) (else (loop (+ round-number 1))))))) (if defected-twice-in-a-row 'defection 'cooperation)))))) ;;; The SHEN player cooperates in the first three rounds and defects in the ;;; next two. After that, it first attempts to recognize itself in its ;;; opponents, by seeing whether the opponent used this characteristic ;;; opening, and cooperating automatically if it did; otherwise, it makes a ;;; random selection between defecting and playing the LOOK-BACK strategy. ;;; Designer: Alice Shen (define Shen (lambda (rounds-played my-plays your-plays) (cond ((< rounds-played 3) 'cooperation) ((< rounds-played 5) 'defection) (else (let ((you-are-like-me (and (eq? (vector-ref your-plays 0) 'cooperation) (eq? (vector-ref your-plays 1) 'cooperation) (eq? (vector-ref your-plays 2) 'cooperation) (eq? (vector-ref your-plays 3) 'defection) (eq? (vector-ref your-plays 4) 'defection)))) (cond (you-are-like-me 'cooperation) ((zero? (random 2)) 'defection) (else (vector-ref your-plays (- rounds-played 1))))))))) ;;; From the fall 1991 tutorial on paradoxes: ;;; The ABSENTEE player cooperates in the first two rounds and ;;; subsequently defects if the other player has defected in each of the ;;; two preceding rounds, but cooperates if the other player cooperated in ;;; either of those two rounds. (This player is sometimes called TIT FOR ;;; TWO TATS.) (define absentee (lambda (rounds-played my-plays your-plays) (cond ((< rounds-played 2) 'cooperation) ((eq? (vector-ref your-plays (- rounds-played 2)) 'cooperation) 'cooperation) (else (vector-ref your-plays (- rounds-played 1)))))) ;;; ANTI-LOOK-BACK cooperates in the first round and thereafter looks at what ;;; the other player did in the preceding round and does just the ;;; _opposite_. (That is, it cooperates after the opponent has defected ;;; and defects after the opponent has cooperated.) (define anti-look-back (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((eq? (vector-ref your-plays (- rounds-played 1)) 'cooperation) 'defection) (else 'cooperation)))) ;;; The BILL player cooperates in the first round and thereafter defects ;;; with a probability determined as a weighted average of its opponent's ;;; previous plays; an opponent's defection in the immediately preceding ;;; round adds 1/2 to this probability, a defection two rounds back adds ;;; 1/4, one three rounds back adds 1/8, and so on. ;;; Designer: Bill Murphy (define Bill (lambda (rounds-played my-plays your-plays) (let ((rand (random 1.0))) (let loop ((remaining rounds-played) (round-defection-weight 1/2) (lower-bound 0) (upper-bound 1)) (cond ((zero? remaining) 'cooperation) ((< rand lower-bound) 'defection) ((<= upper-bound rand) 'cooperation) (else (let ((next-round-back (- remaining 1))) (if (eq? (vector-ref your-plays next-round-back) 'cooperation) (loop next-round-back (/ round-defection-weight 2) lower-bound (- upper-bound round-defection-weight)) (loop next-round-back (/ round-defection-weight 2) (+ lower-bound round-defection-weight) upper-bound))))))))) ;;; The DOUBLEDEAL player cooperates in the first round, chooses as its ;;; play in the second round whatever the other player did in the first ;;; round, and thereafter cooperates if and only if its opponent has ;;; cooperated on both of the preceding moves and has never defected twice ;;; in a row. (define doubledeal (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((= rounds-played 1) (vector-ref your-plays 0)) ((eq? (vector-ref your-plays (- rounds-played 1)) 'defection) 'defection) ((eq? (vector-ref your-plays (- rounds-played 2)) 'defection) 'defection) (else (let ((defected-twice-in-a-row (let loop ((round-number 1)) (cond ((<= rounds-played round-number) #f) ((and (eq? (vector-ref your-plays round-number) 'defection) (eq? (vector-ref your-plays (- round-number 1)) 'defection)) #t) (else (loop (+ round-number 1))))))) (if defected-twice-in-a-row 'defection 'cooperation)))))) ;;; The GUESS player cooperates in the first round and subsequently ;;; plays whatever its opponent played in the round whose ordinal number ;;; is half that of the current round. In other words, it plays a sort of ;;; delayed tit-for-tat, echoing each of its opponent's moves twice (and ;;; thus falling farther and farther behind in its reactions as the match ;;; proceeds). (define guess (lambda (rounds-played my-plays your-plays) (if (zero? rounds-played) 'cooperation (vector-ref your-plays (quotient (- rounds-played 1) 2))))) ;;; The OVERKILL player uses the LOOK-BACK strategy, with two exceptions: It ;;; defects in the first two rounds, regardless of what the other player ;;; does, and after the first four rounds it defects whenever the other ;;; player has defected three times in a row within not more than five ;;; previous rounds, even if the other player cooperated on the immediately ;;; preceding round. (define overkill (lambda (rounds-played my-plays your-plays) (cond ((< rounds-played 2) 'defection) ((< rounds-played 4) (vector-ref your-plays (- rounds-played 1))) ((< rounds-played 5) (if (or (eq? (vector-ref your-plays 3) 'defection) (and (eq? (vector-ref your-plays 0) 'defection) (eq? (vector-ref your-plays 1) 'defection) (eq? (vector-ref your-plays 2) 'defection))) 'defection 'cooperation)) (else (if (or (eq? (vector-ref your-plays (- rounds-played 1)) 'defection) (and (eq? (vector-ref your-plays (- rounds-played 3)) 'defection) (eq? (vector-ref your-plays (- rounds-played 4)) 'defection) (or (eq? (vector-ref your-plays (- rounds-played 2)) 'defection) (eq? (vector-ref your-plays (- rounds-played 5)) 'defection)))) 'defection 'cooperation))))) ;;; The POINT SEVEN player cooperates in the first round and thereafter ;;; cooperates whenever the other player cooperated in the preceding round; ;;; after a defection by the other player, POINT SEVEN generates a random ;;; number in the range from 0 to 1 and defects if the random number is ;;; less than 0.7. ;;; Designer: Bill Murphy (define point-seven (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((eq? (vector-ref your-plays (- rounds-played 1)) 'cooperation) 'cooperation) ((< (random 10) 7) 'defection) (else 'cooperation)))) ;;; The SEMIPATIENT player cooperates in the first round and thereafter ;;; responds to a defection with a defection. In responding to ;;; cooperation, it always cooperates during the first ten rounds, but ;;; afterwards defects whenever the other player has previously defected ;;; more than 3/8 of the time. (define semipatient (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((eq? (vector-ref your-plays (- rounds-played 1)) 'defection) 'defection) ((< rounds-played 10) 'cooperation) (else (let ((your-defections (let loop ((round-number 0) (defections 0)) (cond ((= round-number rounds-played) defections) ((eq? (vector-ref your-plays round-number) 'defection) (loop (+ round-number 1) (+ defections 1))) (else (loop (+ round-number 1) defections)))))) (if (< 3/8 (/ your-defections rounds-played)) 'defection 'cooperation)))))) ;;; The SIMPLE player, during the first ten rounds, cooperates eighty ;;; percent of the time (randomly) and defects twenty percent of the time. ;;; Subsequently, it defects whenever its opponent has defected three times ;;; or more during the previous ten rounds; otherwise, it continues to ;;; cooperate eighty percent of the time and defect twenty percent, ;;; randomly. (define simple (lambda (rounds-played my-plays your-plays) (if (< rounds-played 10) (if (< (random 5) 4) 'cooperation 'defection) (let loop ((round-number (- rounds-played 10)) (your-defections 0)) (cond ((= round-number rounds-played) (if (< (random 5) 4) 'cooperation 'defection)) ((eq? (vector-ref your-plays round-number) 'cooperation) (loop (+ round-number 1) your-defections)) ((= your-defections 2) 'defection) (else (loop (+ round-number 1) (+ your-defections 1)))))))) ;;; The SNEAKY player follows the same strategy as LOOK-BACK for the first ;;; fifteen rounds. Beginning in the sixteenth round, however, if the ;;; other player has cooperated in all five of the preceding rounds, SNEAKY ;;; defects once, then cooperates in the following round. If, in that ;;; following round, the other player ``punishes'' SNEAKY by defecting, ;;; SNEAKY reverts to following the LOOK-BACK strategy for another fifteen ;;; rounds and then tries another unprovoked defection, and so on. If the ;;; other player fails to punish SNEAKY, SNEAKY continues to defect ;;; indefinitely until it provokes a response. (define sneaky (let* ((recently-cooperative? (lambda (rounds-played your-plays) (and (eq? (vector-ref your-plays (- rounds-played 1)) 'cooperation) (eq? (vector-ref your-plays (- rounds-played 2)) 'cooperation) (eq? (vector-ref your-plays (- rounds-played 3)) 'cooperation) (eq? (vector-ref your-plays (- rounds-played 4)) 'cooperation) (eq? (vector-ref your-plays (- rounds-played 5)) 'cooperation)))) (find-sneaky-state (lambda (rounds-played your-plays) (do ((round-number 15 (+ round-number 1)) (look-back-timer 0) (state 'looking-back)) ((= round-number rounds-played) state) (cond ((eq? state 'looking-back) (if (zero? look-back-timer) (if (recently-cooperative? round-number your-plays) (set! state 'testing)) (set! look-back-timer (- look-back-timer 1)))) ((eq? state 'testing) (set! state 'apologizing)) ((eq? state 'apologizing) (set! state 'assessing)) ((eq? state 'assessing) (if (eq? (vector-ref your-plays (- round-number 1)) 'defection) (begin (set! state 'looking-back) (set! look-back-timer 15))))))))) (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((< rounds-played 15) (vector-ref your-plays (- rounds-played 1))) (else (let ((state (find-sneaky-state rounds-played your-plays))) (cond ((eq? state 'looking-back) (vector-ref your-plays (- rounds-played 1))) ((eq? state 'testing) 'defection) ((eq? state 'apologizing) 'cooperation) ((eq? state 'assessing) (if (eq? (vector-ref your-plays (- rounds-played 1)) 'cooperation) 'defection 'cooperation))))))))) ;;; SPANNER operates on a twenty-nine-round cycle. In the first and ninth ;;; round of each cycle, it defects; in the seventh, eighth, and ;;; twenty-ninth round, it cooperates; in the second through sixth rounds ;;; and the eighteenth through twenty-third rounds, it plays the LOOK-BACK ;;; strategy; and in the remaining rounds, it plays the ANTI-LOOK-BACK ;;; strategy. (define spanner (lambda (rounds-played my-plays your-plays) (case (modulo rounds-played 29) ((0 8) 'defection) ((6 7 28) 'cooperation) ((1 2 3 4 5 17 18 19 20 21 22) (vector-ref your-plays (- rounds-played 1))) (else (if (eq? (vector-ref your-plays (- rounds-played 1)) 'cooperation) 'defection 'cooperation))))) ;;; From a class for prospective students, July 18, 1997: ;;; SAINT cooperates in every round, regardless of what the other player ;;; does. ;;; Designer: Morris Matati (define saint (lambda (rounds-played my-plays your-plays) 'cooperation)) ;;; The FRIEDMAN player cooperates in every round until the other player ;;; defects, after which FRIEDMAN always defects. (define Friedman (lambda (rounds-played my-plays your-plays) (let loop ((round-number 0)) (cond ((= round-number rounds-played) 'cooperation) ((eq? (vector-ref your-plays round-number) 'defection) 'defection) (else (loop (+ round-number 1))))))) ;;; THREE-STRIKES cooperates in every round until the other player has ;;; defected three times altogether; after that, it defects in every round. (define three-strikes (lambda (rounds-played my-plays your-plays) (let loop ((round-number 0) (defections 0)) (cond ((= round-number rounds-played) 'cooperation) ((eq? (vector-ref your-plays round-number) 'cooperation) (loop (+ round-number 1) defections)) ((= defections 2) 'defection) (else (loop (+ round-number 1) (+ defections 1))))))) ;;; PUNISHER cooperates in every round until the other player defects. It ;;; responds to the other player's first defection by defecting in the next ;;; round, to the second defection by defecting in the next two rounds, to ;;; the third defection by defecting in the next three rounds, and so ;;; on. Each new defection starts the retaliation count over at 0. When not ;;; retaliating, PUNISHER responds to cooperation with cooperation. ;;; Designer: Doria Laura (define punisher (lambda (rounds-played my-plays your-plays) (let loop ((round-number 0) (previous-defections 0) (punishment 0)) (cond ((= round-number rounds-played) (if (zero? punishment) 'cooperation 'defection)) ((eq? (vector-ref your-plays round-number) 'defection) (loop (+ round-number 1) (+ previous-defections 1) (+ previous-defections 1))) (else (loop (+ round-number 1) previous-defections (if (positive? punishment) (- punishment 1) punishment))))))) ;;; From a class for prospective students, June 26, 2000: ;;; FLORENCIO defects in even-numbered rounds and cooperates in ;;; odd-numbered ones. (define Florencio (lambda (rounds-played my-plays your-plays) (if (even? rounds-played) 'defection 'cooperation))) ;;; MARILEE defects if the opponent has defected in either ;;; of the preceding rounds. (define Marilee (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((eq? (vector-ref your-plays (- rounds-played 1)) 'defection) 'defection) ((= rounds-played 1) 'cooperation) (else (vector-ref your-plays (- rounds-played 2)))))) ;;; From a class for prospective students, June 29, 2001: ;;; In the first five rounds, FAYE alternately cooperates and defects ;;; (beginning with cooperation). Subsequently, FAYE does whatever the ;;; other player did in the previous round. (define Faye (lambda (rounds-played my-plays your-plays) (case rounds-played ((0 2 4) 'cooperation) ((1 3) 'defection) (else (vector-ref your-plays (- rounds-played 1)))))) ;;; VANESSA cooperates in the first three rounds, then switches over to ;;; constant defection if the other player has defected in each of those ;;; first three rounds, and otherwise does whatever the other player did in ;;; the preceding round. (define Vanessa (lambda (rounds-played my-plays your-plays) (cond ((< rounds-played 3) 'cooperation) ((and (eq? (vector-ref your-plays 0) 'defection) (eq? (vector-ref your-plays 1) 'defection) (eq? (vector-ref your-plays 2) 'defection)) 'defection) (else (vector-ref your-plays (- rounds-played 1)))))) ;;; From Axelrod's tournaments: ;;; The CHAMPION player cooperates during the first ten rounds, uses the ;;; LOOK-BACK strategy during the next fifteen rounds, and subsequently ;;; switches to a more complicated strategy: It cooperates if the other ;;; player cooperated in the preceding round, but otherwise computes a ;;; ``cooperation rate'' -- the number of rounds in which the other player ;;; cooperated, divided by the current round number. If this cooperation ;;; rate is 3/5 or more, CHAMPION continues to cooperate; otherwise, it ;;; selects a random number in the range from 0 to 1 and defects unless ;;; this number is less than or equal to the cooperation rate. ;;; Designer: Danny C. Champion (define Champion (lambda (rounds-played my-plays your-plays) (cond ((< rounds-played 10) 'cooperation) ((< rounds-played 25) (vector-ref your-plays (- rounds-played 1))) ((eq? (vector-ref your-plays (- rounds-played 1)) 'cooperation) 'cooperation) (else (let* ((your-cooperations (let loop ((round-number 0) (cooperations 0)) (cond ((= round-number rounds-played) cooperations) ((eq? (vector-ref your-plays round-number) 'cooperation) (loop (+ round-number 1) (+ cooperations 1))) (else (loop (+ round-number 1) cooperations))))) (cooperation-rate (/ your-cooperations rounds-played))) (cond ((<= 3/5 cooperation-rate) 'cooperation) ((<= (random 1.0) cooperation-rate) 'cooperation) (else 'defection))))))) ;;; The COIN-TOSSER player, in effect, tosses a coin, defecting if it comes ;;; up heads and cooperating if it comes up tails. (Another name for this ;;; player is RANDOM.) (define coin-tosser (lambda (rounds-played my-plays your-plays) (if (zero? (random 2)) 'cooperation 'defection))) ;;; The DOWNING player defects on the first two rounds, then decides which ;;; move to make on the basis of the opponent's track record: It reviews ;;; the game record, determining how often in the past the opponent has ;;; responded to defection with defection and how often it has responded to ;;; cooperation with defection. It then assumes that the opponent will ;;; continue to respond to future acts of cooperation and defection with ;;; cooperation and defection in the same proportions. Finally, DOWNING ;;; computes whether it is more profitable to cooperate or to defect, given ;;; the opponent's response policy, and makes the appropriate move. (In ;;; cases where the strategy would be cooperating for the first time, it ;;; assumes that the probability that an opponent will respond to ;;; cooperation with cooperation is fifty percent.) ;;; Designer: Leslie Downing. (define Downing (let ((rewarded (lambda (trial rounds-played my-plays your-plays) (let loop ((round-number 0) (rewards 0)) (if (= round-number (- rounds-played 1)) rewards (loop (+ round-number 1) (if (and (eq? (vector-ref my-plays round-number) trial) (eq? (vector-ref your-plays (+ round-number 1)) 'cooperation)) (+ rewards 1) rewards))))))) (lambda (rounds-played my-plays your-plays) (if (< rounds-played 2) 'defection (let ((my-cooperations (let loop ((round-number 0) (cooperations 0)) (cond ((= round-number rounds-played) cooperations) ((eq? (vector-ref my-plays round-number) 'cooperation) (loop (+ round-number 1) (+ cooperations 1))) (else (loop (+ round-number 1) cooperations)))))) (let ((chance-of-cooperation-rewarded (if (zero? my-cooperations) 1/2 (/ (rewarded 'cooperation rounds-played my-plays your-plays) my-cooperations))) (chance-of-defection-rewarded (/ (rewarded 'defection rounds-played my-plays your-plays) (- rounds-played my-cooperations)))) (if (< (* 3 chance-of-cooperation-rewarded) (+ (* 4 chance-of-defection-rewarded) 1)) 'defection 'cooperation))))))) ;;; PAVLOV cooperates in the first round. Subsequently, it cooperates ;;; whenever both players did the same thing in the preceding round (i.e., ;;; they both cooperated or both defected) and defects if they did ;;; different things in the preceding round. (define Pavlov (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((eq? (vector-ref my-plays (- rounds-played 1)) (vector-ref your-plays (- rounds-played 1))) 'cooperation) (else 'defection)))) ;;; The REVISED-DOWNING player follows the same strategy as DOWNING, except ;;; that it _cooperates_ on the first two rounds rather than defecting and ;;; assumes that the other player will invariably respond to its first ;;; defection by defecting. (define revised-Downing (let ((rewarded (lambda (trial rounds-played my-plays your-plays) (let loop ((round-number 0) (rewards 0)) (if (= round-number (- rounds-played 1)) rewards (loop (+ round-number 1) (if (and (eq? (vector-ref my-plays round-number) trial) (eq? (vector-ref your-plays (+ round-number 1)) 'cooperation)) (+ rewards 1) rewards))))))) (lambda (rounds-played my-plays your-plays) (if (< rounds-played 2) 'cooperation (let ((my-cooperations (let loop ((round-number 0) (cooperations 0)) (cond ((= round-number rounds-played) cooperations) ((eq? (vector-ref my-plays round-number) 'cooperation) (loop (+ round-number 1) (+ cooperations 1))) (else (loop (+ round-number 1) cooperations)))))) (let ((chance-of-cooperation-rewarded (/ (rewarded 'cooperation rounds-played my-plays your-plays) my-cooperations)) (chance-of-defection-rewarded (let ((my-defections (- rounds-played my-cooperations))) (if (zero? my-defections) 0 (/ (rewarded 'defection rounds-played my-plays your-plays) my-defections))))) (if (< (* 3 chance-of-cooperation-rewarded) (+ (* 4 chance-of-defection-rewarded) 1)) 'defection 'cooperation))))))) ;;; Some strategies of my own design: ;;; CAREGIVER cooperates in the first round and thereafter always responds ;;; to cooperation with cooperation. In responding to defection, CAREGIVER ;;; always defects in the first sixteen rounds; over the following ;;; twenty-four rounds, it gradually decreases the probability of defection ;;; from 1 to 2/3, where it stays. (In other words, after the fortieth ;;; round, when the other player defects, CAREGIVER retaliates only 2/3 of ;;; the time.) (define caregiver (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((< rounds-played 16) (vector-ref your-plays (- rounds-played 1))) ((eq? (vector-ref your-plays (- rounds-played 1)) 'cooperation) 'cooperation) ((< rounds-played 40) (if (< (random 72) (- rounds-played 15)) 'cooperation 'defection)) (else (if (zero? (random 3)) 'cooperation 'defection))))) ;;; EXPERIMENTER cooperates in the first round and thereafter always ;;; responds to a defection with a defection; in responding to cooperation, ;;; EXPERIMENTER defects one time out of ten, choosing its occasions ;;; randomly. (At one point, I thought that this was one of the strategies ;;; from Axelrod's tournaments, but it turns out that I was mistaken.) (define experimenter (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((eq? (vector-ref your-plays (- rounds-played 1)) 'defection) 'defection) ((zero? (random 10)) 'defection) (else 'cooperation)))) ;;; FORGIVER cooperates in the first round. It then keeps track of the ;;; number of times the other player has defected _without provocation_ ;;; (that is, defected after FORGIVER cooperated in the preceding round), ;;; and also the number of times the other player has cooperated since the ;;; last episode of unprovoked defection. It cooperates whenever the ;;; former number is no more than one greater than the latter. (In other ;;; words, it forgives the other player for stabbing it in the back the ;;; first time, but subsequently requires increasingly heavy compensation ;;; before returning to cooperation.) (define forgiver (lambda (rounds-played my-plays your-plays) (let loop ((round-number 0) (your-unprovoked-defections 0) (apology-rounds 0)) (cond ((= round-number rounds-played) (if (<= your-unprovoked-defections (+ apology-rounds 1)) 'cooperation 'defection)) ((and (eq? (vector-ref your-plays round-number) 'defection) (or (= round-number 0) (eq? (vector-ref my-plays (- round-number 1)) 'cooperation))) (loop (+ round-number 1) (+ your-unprovoked-defections 1) 0)) ((zero? apology-rounds) (loop (+ round-number 1) your-unprovoked-defections 0)) (else (loop (+ round-number 1) your-unprovoked-defections (+ apology-rounds 1))))))) ;;; Like FORGIVER, FORGIVE-THRICE keeps track of the number of times the ;;; other player has defected without provocation. It plays like LOOK BACK ;;; until the third unprovoked defection, at which point it switches over ;;; to constant defection. (define forgive-thrice (lambda (rounds-played my-plays your-plays) (if (zero? rounds-played) 'cooperation (let loop ((round-number 0) (your-unprovoked-defections 0)) (cond ((<= 3 your-unprovoked-defections) 'defection) ((= round-number rounds-played) (vector-ref your-plays (- round-number 1))) ((and (eq? (vector-ref your-plays round-number) 'defection) (or (zero? round-number) (eq? (vector-ref my-plays (- round-number 1)) 'cooperation))) (loop (+ round-number 1) (+ your-unprovoked-defections 1))) (else (loop (+ round-number 1) your-unprovoked-defections))))))) ;;; GOLDEN-RULE cooperates in the first round, and thereafter always ;;; responds to a defection with a defection. In responding to cooperation ;;; after the first round, it looks to see how frequently its opponent has ;;; defected in all previous rounds and defects with the same probability. (define golden-rule (lambda (rounds-played my-plays your-plays) (cond ((zero? rounds-played) 'cooperation) ((eq? (vector-ref your-plays (- rounds-played 1)) 'defection) 'defection) (else (let ((your-defections (let loop ((round-number 0) (defections 0)) (cond ((= round-number rounds-played) defections) ((eq? (vector-ref your-plays round-number) 'defection) (loop (+ round-number 1) (+ defections 1))) (else (loop (+ round-number 1) defections)))))) (if (< (random 1.0) (/ your-defections rounds-played)) 'defection 'cooperation))))))