lolamontes69

Ch11 Ex7-Programming Collective Intelligence

Sep 21st, 2013
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.74 KB | None | 0 0
  1. """ Chapter 11 Exercise 7: Tic-tac-toe.
  2.  
  3.   "Build a tic-tac-toe simulator for your programs to play.
  4.    Set up a tournament similar to the Grid War tournament.
  5.    How well do the programs do? Can they ever learn to play perfectly?"
  6.  
  7.    Here is the implementation. See *end for usage and notes
  8.                   - lolamontes69
  9. """
  10.  
  11. from random import random,randint,choice
  12. from copy import deepcopy
  13. from math import log
  14. import os as os
  15.  
  16. class fwrapper:
  17.     def __init__(self,function,childcount,name):
  18.         self.function=function
  19.         self.childcount=childcount
  20.         self.name=name
  21.  
  22. class node:
  23.     def __init__(self,fw,children):
  24.         self.function=fw.function
  25.         self.name=fw.name
  26.         self.children=children
  27.  
  28.     def evaluate(self,inp):
  29.         results=[n.evaluate(inp) for n in self.children]
  30.         return self.function(results)
  31.  
  32.     def display(self,indent=0):
  33.         print (' '*indent)+self.name
  34.         for c in self.children:
  35.             c.display(indent+1)
  36.  
  37.     def display1(self):
  38.         list1=[]
  39.         list1.append(self.name)
  40.         list2=[]
  41.         for c in self.children:
  42.             list2.append(c.display1())
  43.         list1.append(list2)
  44.         return list1
  45.  
  46. class paramnode:
  47.     def __init__(self,idx):
  48.         self.idx=idx
  49.  
  50.     def evaluate(self,inp):
  51.         return inp[self.idx]
  52.  
  53.     def display(self,indent=0):
  54.         print '%sp%d' % (' '*indent,self.idx)
  55.  
  56.     def display1(self):
  57.         return 'p%d' % self.idx
  58.        
  59. class constnode:
  60.     def __init__(self,v):
  61.         self.v=v
  62.  
  63.     def evaluate(self,inp):
  64.         return self.v
  65.  
  66.     def display(self,indent=0):
  67.         print '%s%d' % (' '*indent,self.v)
  68.  
  69.     def display1(self):
  70.         return self.v
  71.  
  72. addw=fwrapper(lambda l:l[0]+l[1],2,'add')
  73. subw=fwrapper(lambda l:l[0]-l[1],2,'subtract')
  74. mulw=fwrapper(lambda l:l[0]*l[1],2,'multiply')
  75.  
  76. def iffunc(l):
  77.     if l[0]>0: return l[1]
  78.     else: return l[2]
  79. ifw=fwrapper(iffunc,3,'if')
  80.  
  81. def isgreater(l):
  82.     if l[0]>l[1]: return 1
  83.     else: return 0
  84. gtw=fwrapper(isgreater,2,'isgreater')
  85.  
  86. flist=[addw,mulw,ifw,gtw,subw]
  87. # flist=[addw,mulw,ifw,ifw1,ifw2,gtw,subw,eucw,taniw]
  88.                
  89. def makerandomtree(pc,maxdepth=4,fpr=0.5,ppr=0.6):
  90.     if random()<fpr and maxdepth>0:
  91.         f=choice(flist)
  92.         children=[makerandomtree(pc,maxdepth-1,fpr,ppr)
  93.                   for i in range(f.childcount)]
  94.         return node(f,children)
  95.     elif random()<ppr:
  96.         return paramnode(randint(0,pc-1))
  97.     else:
  98.         return constnode(randint(0,10))
  99.  
  100. def hiddenfunction(x,y):
  101.     return x**2+2*y+3*x+5
  102.  
  103. def buildhiddenset():
  104.     rows=[]
  105.     for i in range(200):
  106.         x=randint(0,40)
  107.         y=randint(0,40)
  108.         rows.append([x,y,hiddenfunction(x,y)])
  109.     return rows
  110.  
  111. def scorefunction(tree,s):
  112.     dif=0
  113.     for data in s:
  114.         v=tree.evaluate([data[0],data[1]])
  115.         dif+=abs(v-data[2])
  116.     return dif
  117.  
  118. def mutate(t,pc,probchange=0.1):
  119.     if random()<probchange:
  120.         return makerandomtree(pc)
  121.     else:
  122.         result=deepcopy(t)
  123.         if hasattr(t,"children"):
  124.             result.children=[mutate(c,pc,probchange) for c in t.children]
  125.         return result
  126.  
  127. def crossover(t1,t2,probswap=0.7,top=1):
  128.     if random()<probswap and not top:
  129.         return deepcopy(t2)
  130.     else:
  131.         result=deepcopy(t1)
  132.         if hasattr(t1, 'children') and hasattr(t2, 'children'):
  133.             result.children=[crossover(c,choice(t2.children),probswap,0)
  134.                              for c in t1.children]
  135.         return result
  136.  
  137. def getrankfunction(dataset):
  138.     def rankfunction(population):
  139.         scores=[(scorefunction(t,dataset),t) for t in population]
  140.         scores.sort()
  141.         return scores
  142.     return rankfunction
  143.  
  144. def evolve(pc,popsize,rankfunction,maxgen=500,mutationrate=0.1,breedingrate=0.4,pexp=0.7,pnew=0.05):
  145.     # Returns a random number, tending towards lower numbers.
  146.     # The lower pexp is, more lower numbers you will get
  147.     def selectindex(lenscores):
  148.         while True:
  149.             # Stop selectindex() from returning numbers out of index.
  150.             ind =  int(log(random())/log(pexp))
  151.             if (ind-lenscores>(lenscores*2)-1) or (ind>lenscores): pass
  152.             else: return ind
  153.  
  154.     # Create a random initial population
  155.     population=[makerandomtree(pc) for i in range(popsize)]
  156.     for i in range(maxgen):
  157.         scores=rankfunction(population)
  158.         print scores[0][0]
  159.         if scores[0][0]==0: break
  160.        
  161.         # The two best will always make it
  162.         newpop=[scores[0][1],scores[1][1]]
  163.  
  164.         # Build the next generation
  165.         while len(newpop)<popsize:
  166.             if random()>pnew:
  167.                 newpop.append(mutate(
  168.                                 crossover(scores[selectindex(len(scores))][1],
  169.                                         scores[selectindex(len(scores))][1],
  170.                                         probswap=breedingrate),
  171.                                 pc,probchange=mutationrate))
  172.             else:
  173.                 # Add a random node to mix things up
  174.                 newpop.append(makerandomtree(pc))
  175.         population=newpop
  176.     scores[0][1].display()
  177.     return scores[0][1]
  178.  
  179. def seeifwinner(player):
  180.     winners=[(0,1,2),(3,4,5),(6,7,8),(0,3,6),(1,4,7),(2,5,8),(0,4,8),(2,4,6)]
  181.     for a in range(len(winners)):
  182.         total=0
  183.         for b in winners[a]:
  184.             if b in player:
  185.                 total+=1
  186.             if total==3:
  187.                 return 1
  188.     return 0
  189.  
  190. def print_board(players):
  191.     edges=[2,5]
  192.     for a in range(9):
  193.         if a in players[0]: print 'O',
  194.         elif a in players[1]: print 'X',
  195.         else: print '.',
  196.         if a in edges: print
  197.  
  198. # Example output [2,-1,0,1,0,0,0,-1,6]
  199. def getparams(players,i):
  200.     winners=[(0,1,2),(3,4,5),(6,7,8),(0,3,6),(1,4,7),(2,5,8),(0,4,8),(2,4,6)]
  201.     list1=[0]*8
  202.     for a in range(len(winners)):
  203.         for b in players[i]:
  204.             if b in winners[a]:
  205.                 list1[a]+=1
  206.         for b in players[1-i]:
  207.             if b in winners[a]:
  208.                 list1[a]-=1
  209.     return list1
  210.  
  211. def ttt1(p):
  212.     players =[[],[]]
  213.     possiblemoves=range(9)
  214.     while True:
  215.         for i in range(2):
  216.             pml=len(possiblemoves)     # possible moves left
  217.             if pml==0:
  218.                 return -1   # A draw
  219.             boardstate=getparams(players,i)
  220.             boardstate.append(pml)
  221.             move=p[i].evaluate(boardstate)%pml
  222.             players[i].append(possiblemoves[move])
  223.             possiblemoves.remove(possiblemoves[move])
  224.             if seeifwinner(players[i])==1:
  225.                 return i
  226.  
  227. def ttt_tournament(pl):
  228.     # Count losses
  229.     losses=[0 for p in pl]
  230.  
  231.     # Every player plays every other player
  232.     for i in range(len(pl)):
  233.         for j in range(len(pl)):
  234.             if i==j: continue
  235.  
  236.             # Who is the winner?
  237.             winner=ttt1([pl[i],pl[j]])
  238.  
  239.             # Two points for a loss, one point for a tie
  240.             if winner==0:
  241.                 losses[j]+=2
  242.             elif winner==1:
  243.                 losses[i]+=2
  244.             elif winner==-1:
  245.                 losses[i]+=1
  246.                 losses[j]+=1
  247.                 pass
  248.     # Sort and return the results
  249.     z=zip(losses,pl)
  250.     z.sort()
  251.     return z
  252.  
  253. def ttt2(p):
  254.     players =[[],[]]
  255.     possiblemoves=range(9)
  256.     print "The board is numbered as follows;\n          012\n          345\n          678"
  257.     letsplay=raw_input('Press <ENTER> to play')
  258.     print '. . .\n. . .\n. . .'
  259.     print "-"*44
  260.     while True:
  261.         for i in range(2):
  262.             pml=len(possiblemoves)     # possible moves left
  263.             if pml==0:
  264.                 return -1   # A draw
  265.  
  266.             if isinstance(p[i],humanplayer):
  267.                 move=p[i].evaluate(possiblemoves)
  268.                 players[i].append(move)
  269.                 possiblemoves.remove(move)
  270.             else:
  271.                 boardstate=getparams(players,i)
  272.                 boardstate.append(pml)
  273.                 move=p[i].evaluate(boardstate)%pml
  274.                 players[i].append(possiblemoves[move])
  275.                 possiblemoves.remove(possiblemoves[move])
  276.  
  277.             if seeifwinner(players[i])==1:
  278.                 print_board(players)
  279.                 return i
  280.             print_board(players)
  281.             print
  282.             print "-"*44
  283.  
  284. class humanplayer:
  285.     def evaluate(self,possiblemoves):
  286.         # Return whatever the user enters
  287.         print "Possible moves are",possiblemoves
  288.         move=int(raw_input('Enter number >'))
  289.         print "-"*44
  290.         return move
  291.  
  292. """
  293.  
  294. #########
  295. # Usage #
  296. #########
  297.  
  298. import ttt_gp as gp
  299. winner=gp.evolve(9,40,gp.ttt_tournament,maxgen=10)
  300.  
  301. gp.ttt1([winner1,winner])
  302.  
  303. gp.ttt2([winner,gp.humanplayer()])
  304. gp.ttt2([gp.humanplayer(),winner])
  305.  
  306. -------------------------------------------------------------------------------
  307.  
  308. #########
  309. # Notes #
  310. #########
  311.  
  312. boardstate - Needing to find some parameters to send to the programs I came up
  313.             with boardstate. Example [2,-1,0,1,0,0,0,-1,6]
  314.             The first 8 numbers of boardstate refer to the lines on the board
  315.             in the order shown in the list 'winners'. If the current player
  316.             has a square on that line 1 is added to the value, if the opponent
  317.             has a square on that line 1 is deducted from the value.
  318.             The last number refers to the possible number of moves left
  319.  
  320. ttt1       - used by ttt_tournament() for program vs program
  321. ttt2       - used for humanplayer vs program
  322.  
  323. The programs evolved are very predictable at the moment because they have static
  324. algorithms that always react the same way to circumstances. Still, there is
  325. always the chance of evolving (if p8>8: return 1   else: return 0)  :)
  326. """
Advertisement
Add Comment
Please, Sign In to add comment