if not init then rom.best_player = nil init = true depth = 4; -- how many moves does random player evaluate error_rate = 0.25; -- players make wrong decision with this probability generation = 10; -- how many times we repeat steps = 100; -- how many steps each generation bestc = 0; -- how many times was new best player picked mode = 2; -- 1, evolution!, 2 play game -- game pay offs rules = { { {2., 2.}, -- first player cooperate, second player cooperate: +2,+2 {-1, 3}, -- first player cooperate, second player cheat: -1,+3 }, { {3,-1}, -- first player cheats, second player cooperate {0,0}, -- first player cheats, second player cheat } }; copytable = function(tab) if type(tab)~="table" then return tab end local ret = {}; for k,v in pairs(tab) do ret[k] = copytable(v) end return ret end copycat = { rules = { {0}, -- initial: 0 = cooperate {0,1}, -- after one move : cooperate if other cooperated last turn, cheat if other cheated last turn }, -- encode decision sequence in binary: 01110 = dec 8+4+2=14 memory = 1, -- how many moves back player consideres? moves ={}, -- opponent moves mood = 0, -- probability that player will cheat if he had intention to cooperate moody = 0.5, -- by how much cheat/cooperate change mood points = 0, name = "copycat" } cheater = { rules = { {1}, }, memory = 0, -- how many moves back player consideres? moves ={}, -- opponent moves mood = 0, moody = 0.5, points = 0, name = "cheater" } realplayer = { rules = { {0}, }, memory = 0, -- how many moves back player consideres? moves ={}, -- opponent moves mood = 0, moody = 0., points = 0, name = "real player", real = true, out = 0 } create_random_player = function(memory) local rules = {}; for i = 1, memory+1 do rules[i] = {}; for j = 1,2^(i-1) do rules[i][j] = math.random(2)-1 end end return {rules = rules, memory = memory, moves = {}, mood = 0, moody = math.random(), points = 0, name = "randomplayer"} end -- player makes next move according to his memory of moves so far play = function(player) if player.real then return player.out end -- real player local moves = player.moves; local n = #moves; if n > player.memory then n = player.memory end -- there are many moves, examine only what we can local rules = player.rules[n+1] local state = bin2dec(player.moves,n); -- examine last n moves --say("n " .. n .. " state " .. state) return rules[state+1] end group_play = function(playrs) -- each randomplayer plays with every other player in lower group local n = #playrs; local m = 10; -- play m games with each opponent, random pair order for i = 1,10 do for j = 11,20 do -- i plays with j, randomized order playrs[i].moves = {}; playrs[j].moves = {}; -- reset remembered moves before paired match! playrs[i].mood = 0; for k = 1,m do if math.random(2) == 1 then interact(playrs[i],playrs[j]) else interact(playrs[j],playrs[i]) end end end end end sort_players = function(pl) table.sort(pl, function(p1,p2) return p1.points1 then mood = 1 elseif mood<0 then mood = 0 end player2.mood = mood end if res1 == 0 then -- mood change for player1 mood = player1.mood; if res2==1 then mood = mood + player1.moody; else mood = mood - player1.moody; end if mood>1 then mood = 1 elseif mood<0 then mood = 0 end player1.mood = mood end end dec2bin = function(input) local ret = {}; if input == 0 then return {0} end while input~=0 do local r=input%2; input = (input -r)/2 ret[#ret+1] = r; end local n = #ret; local rret = {} for i = 1, n do rret[i]=ret[n-i+1] end return rret end bin2dec = function(bin, length) -- length= how many last elements we take if length == 0 then return 0 end if not length then length = #bin end local offset = #bin - length; if offset<0 then offset = 0 end local ret = 0; for i = 1,#bin-offset do ret = 2*ret + bin[i+offset] end return ret end get_results = function(players) local ret = {} for i=1,#players do ret[i] = players[i].name .. " " .. players[i].points .. "M " .. players[i].mood .. "(" .. players[i].moody .. ")" end return table.concat(ret,"\n") end players = {} -- start with 5 cheaters, 5 copycats and 10 randomplayers if mode == 1 then for i = 1,5 do players[i] = copytable(cheater) end for i = 1,5 do players[5+i] = copytable(copycat) end for i = 1,10 do players[10+i] = create_random_player(depth) end -- last 10 players are random age = 0 rom.best_player = nil; elseif mode == 2 then players = {copytable(realplayer), copytable( create_random_player(4) ) } ; self.listen(1) end --players[20] = copytable(rom.best_player) or create_random_player(depth) -- add best player from before --players[20].name = "randomplayer" end if mode == 1 then local bestpoints = 0 for k = 1, generation do -- repeat experiment generation* --rom.best_player = nil for i = 1,#players do players[i].points = 0 end for j = 1, steps do -- several steps to see who is best long term on average --for i = 1,#players do players[i].points = 0 end group_play(players) end bestpoints = 0 genetics(players) -- remove 5 worst randomplayers & replace them by new randoms local population = {} bestrandom = 0 for i = 11,20 do if players[i].points >= bestrandom then bestrandom = players[i].points end population[#population+1] = players[i] end --say("randomplayer population size " .. #population) sort_players(population); if rom.best_player then lastbest = rom.best_player.points if bestrandom >= lastbest then -- PICK NEW BEST bestc = bestc+1 rom.best_player = copytable(population[#population]); -- remember best randomplayer for next experiment end else rom.best_player = copytable(population[#population]); -- remember best randomplayer for next experiment end end age = age + generation --display results! msg = "" msg = msg .. "Planet Earth (galactical name Halfwits), age " .. age .. ", error_rate " .. error_rate .. ", steps " .. steps .. ", generations " .. generation .. ":\n" msg = msg .."\nlast round\n" --sort_players(players) bestpoints = 0 for i =1,#players do if players[i].points>bestpoints then bestpoints = players[i].points end msg = msg .. players[i].name .. ": " .. players[i].points .. " M " .. players[i].mood .. "(" .. players[i].moody .. ")\n" end local rules = rom.best_player.rules; msg = msg .. "BEST: " .. bestpoints .. "\n\n## alltime best random player no. " .. bestc .. ", points " .. rom.best_player.points .. " moody " .. rom.best_player.moody .. "\ncurrent best random player/max current score: ".. math.floor(100*bestrandom/bestpoints*100)/100 .. "% \nrules " .. serialize(rules) .. " )\n"; local msg1 = "{" .. rules[1][1] .. "}\n" for i = 2,#rules do local rule = rules[i]; msg1 = msg1.. "{" for j = 1,#rule do local rule_string = table.concat(dec2bin(j-1),""); rule_string = string.rep("0",i-string.len(rule_string)-1) .. rule_string; msg1 = msg1 .. rule_string .."="..rule[j].."," end msg1 = msg1 .. "}\n" end self.label(msg .. msg1) elseif mode == 2 then -- play vs player speaker,msg = self.listen_msg(); if msg then if msg == "0" or msg == "1" then local nextmove = tonumber(msg); if nextmove == 1 and players[1].out == 1 then say("look buddy, we dont like cheaters around here. dont cheat twice in a row") else players[1].out = nextmove interact(players[1], players[2]) say("input " .. players[1].out .. ", BOT MOVES: " .. serialize(players[1].moves) .. " BOT MOOD " .. players[2].mood .. "(" .. players[2].moody .. ") SCORE: you " .. players[1].points .. " bot " .. players[2].points) end end end end