Last active
December 27, 2015 04:48
-
-
Save jpfuentes2/7269002 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns labrepl.ipd) | |
;; moves and utils | |
(defn defect [moves] (conj moves 0)) | |
(defn coop [moves] (conj moves 1)) | |
(defn defect? [move] (= move 0)) | |
(defn coop? [move] (= move 1)) | |
(defn random [mover] | |
(conj mover (rand-int 2))) | |
(defn if-empty [mover strategy-when-empty otherwise] | |
(if (empty? mover) | |
(strategy-when-empty mover) | |
(otherwise mover))) | |
(defn any-defects? [moves] | |
(contains? (set moves) 0)) | |
(defn count-choice [choice moves] | |
(reduce (fn [sum move] | |
(if (choice move) | |
(inc sum) | |
sum)) 0 moves)) | |
(defn num-defects [mover] | |
(count-choice defect? mover)) | |
(defn num-coops [mover] | |
(count-choice coop? mover)) | |
;; end moves and utils | |
;; strategies | |
(defn AlwaysDefect [mover opponent] (defect mover)) | |
(defn AlwaysCooperate [mover opponent] (coop mover)) | |
(defn AlwaysRandom [mover opponent] (random mover)) | |
(defn TitForTat [mover opponent] | |
(if-empty mover coop #(conj % (last opponent)))) | |
(defn TitForTwoTats [mover opponent] | |
(if (<= (count mover) 1) | |
(coop mover) | |
(if (every? defect? (take-last 2 opponent)) | |
(defect mover) | |
(coop mover)))) | |
(defn SuspiciousTitForTat [mover opponent] | |
(if-empty mover defect #(TitForTat % opponent))) | |
(defn Grudger [mover opponent] | |
(if-empty mover coop (fn [mover] | |
(if (some defect? opponent) | |
(defect mover) | |
(coop mover))))) | |
;; Soft Grudger - Co-operates until the opponent defects, in such case opponent | |
;; is punished with d,d,d,d,c,c. | |
(defn SoftGrudger [mover opponent] | |
(if-not (any-defects? opponent) | |
(coop mover) | |
(if (= [(last mover) (last opponent)] [1 1]) | |
(coop mover) | |
(let [last-6 (take-last 6 mover)] | |
(if-not (= (take-last 4 last-6) [0 0 0 0]) | |
(defect mover) | |
(coop mover)))))) | |
;; Gradual - Co-operates until the opponent defects, in such case defects the total | |
;; number of times the opponent has defected during the game. Followed up by two co-operations. | |
(defn Gradual [mover opponent] | |
(if-not (any-defects? opponent) | |
(coop mover) | |
(if (= (num-defects mover) (num-defects opponent)) | |
(coop mover) | |
(defect mover)))) | |
;; Naive Prober (Tit For Tat with Random Defection) - Repeat opponent's last choice (ie Tit For Tat), | |
;; but sometimes probe by defecting in lieu of co-operating.* | |
(defn NaiveProber [mover opponent] | |
(let [mover (TitForTat mover opponent) n (count mover)] | |
(if (and (coop? (last mover)) (> n 1)) | |
(assoc mover (dec (count mover)) (rand-int 2)) | |
mover))) | |
;; Remorseful Prober (Tit For Tat with Random Defection) - Repeat opponent's last choice (ie Tit For Tat), | |
;; but sometimes probe by defecting in lieu of co-operating. If the opponent defects in response to probing, | |
;; show remorse by co-operating once.* | |
(defn RemorsefulProber [mover opponent]) | |
;; Naive Peace Maker (Tit For Tat with Random Co-operation) - Repeat opponent's last choice (ie Tit For Tat), | |
;; but sometimes make peace by co-operating in lieu of defecting.* | |
(defn NaivePeaceMaker [mover opponent] | |
((cond | |
(empty? mover) coop | |
(defect? (last opponent)) random | |
:else coop) mover)) | |
;; True Peace Maker (hybrid of Tit For Tat and Tit For Two Tats with Random Co-operation) - | |
;; Co-operate unless opponent defects twice in a row, then defect once, but sometimes make peace by co-operating in lieu of defecting.* | |
(defn TruePeaceMaker [mover opponent] | |
(let [mover (TitForTwoTats mover opponent)] | |
(if (defect? (last mover)) | |
(assoc mover (dec (count mover)) (rand-int 2)) | |
mover))) | |
;; Adaptive - Starts with c,c,c,c,c,c,d,d,d,d,d and then takes choices | |
;; which have given the best average score re-calculated after every move. | |
;; Jekyll and Hyde - alternate b/t c and d | |
;; Pavlov | |
;; - Cooperate at start and when last choice matches last choice of opponent. | |
;; - Defect when last choice is different from last choice of opponent | |
;; end strategies | |
;; game play | |
(defn make-move [p1 p2] | |
(let [{p1-moves :moves p1-strategy :strategy} p1 | |
{p2-moves :moves} p2] | |
(p1-strategy p1-moves p2-moves))) | |
(defn player [strategy] | |
{:moves [] :strategy strategy}) | |
(defn game [p1 p2] | |
[(assoc p1 :moves (make-move p1 p2)) | |
(assoc p2 :moves (make-move p2 p1))]) | |
(defn iterated-game [iterations player1 player2] | |
(loop [n 0 [p1 p2] [player1 player2]] | |
(if (< n iterations) | |
(recur | |
(inc n) | |
(game p1 p2)) | |
[p1 p2]))) | |
;; end game play | |
;; scoring | |
(def scores { [1 0] 0 | |
[0 0] 1 | |
[1 1] 3 | |
[0 1] 5 }) | |
(defn score-moves [p1 p2] | |
(get scores [p1 p2])) | |
(defn total-scores [p1moves p2moves] | |
(if (= (count p1moves) (count p2moves)) | |
(reduce | |
(fn [[p1-sum p2-sum] [p1-move p2-move]] | |
[(+ p1-sum (score-moves p1-move p2-move)) | |
(+ p2-sum (score-moves p2-move p1-move))]) | |
[0 0] | |
(partition 2 (interleave p1moves p2moves))) | |
nil)) | |
;; end scoring | |
(->> [(player AlwaysRandom) (player AlwaysRandom)] | |
(apply iterated-game 1) | |
(map :moves) | |
(apply total-scores)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ipd functional | |
require 'hamster/list' | |
require 'hamster/hash' | |
def list; Hamster.list; end | |
module Prisoner | |
def prisoner(name, strategy, moves = Hamster.list, scores = Hamster.list) | |
Hamster.hash(name: name, strategy: strategy, moves: moves, scores: scores) | |
end | |
end | |
module Strategy | |
def strategy(strategy) | |
-> mover, other { strategy.(mover[:moves], other[:moves]) } | |
end | |
def always_cooperate(mover, other); cooperate(mover); end | |
def always_defect(mover, other); defect(mover); end | |
def always_random(mover, other) | |
Random.new.rand(2) == 0 ? cooperate(mover) : defect(mover) | |
end | |
end | |
module Moves | |
def cooperate(moves); moves.cons(1); end | |
def cooperated?(move); move == 1; end | |
def defect(moves); moves.cons(0); end | |
def defected?(move); move == 0; end | |
end | |
module Game | |
def game(a, z) | |
moves_a = a[:strategy].(a, z) | |
moves_z = z[:strategy].(z, a) | |
Hamster.list( | |
a.put(:moves, moves_a), | |
z.put(:moves, moves_z) | |
) | |
end | |
def iterated_game(iterations, a, z) | |
(1..iterations).reduce(Hamster.list(a,z)) do |prisoners, _| | |
game(prisoners.head, prisoners.last) | |
end | |
end | |
def score(a, z) | |
a.zip(z).reduce(Hamster.hash(a: list, z: list)) do |scores, (move_a, move_z)| | |
score_a = compute_score(move_a, move_z) | |
score_z = compute_score(move_z, move_a) | |
Hamster.hash( | |
a: scores[:a].cons(score_a), | |
z: scores[:z].cons(score_z) | |
) | |
end | |
end | |
def compute_score(a, z) | |
# f it, let's use state! | |
@scores ||= { | |
[0, 1] => 5, | |
[1, 1] => 3, | |
[0, 0] => 1, | |
[1, 0] => 0 | |
} | |
@scores[[a,z]] | |
end | |
end | |
[Prisoner, Moves, Strategy, Game].each { |m| include m } | |
a = prisoner(:a, strategy(method(:always_cooperate))) | |
z = prisoner(:z, strategy(method(:always_defect))) | |
a, z = iterated_game(10, a, z) | |
scores = score(a[:moves], z[:moves]) | |
p scores[:a] | |
p scores[:z] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment