简体   繁体   中英

Recursive function for connect four possible moves generation in Python

I am programming a connect four AI for my school project. But first I want to simulate every possible moves on the 6(row)*7(column) before I write the minimax algorithm to work the perfect move for each stage of board. Instead of using

for a in range(7):
   place_player_disk()
   complete_set.append
   if check_win():
      continue
   for b in legal_move():
       place_AI_disk()
       complete_set.append
       if check_win()
          continue
       .... #repeat the nested for loop 42 times

I want to use a neater way of doing it

state0=[['','','','','','',''],['','','','','','',''],['','','','','','',''],['','','','','','',''],['','','','','','',''],['','','','','','',''],['','','','','','','']]
complete_set=[[],[],[],[],[],[]...]
import copy
def playerplacetoken(perimeter,location):
      count=0
      for row in range(6):
          if perimeter[row][location]=='X' or perimeter[row][location]=='Y':
              count+=1
      perimeter[5-count][location]='X'
def full(perimeter):
    free = []
    for column in range(7):
    if perimeter[0][column] == '':
            free.append(column)
    return free
def PlacingCPUToken(perimeter,location):
    count=0
    for row in range (6):
      if perimeter[row][location]=='X' or perimeter[row][location]=='Y':
              count+=1
    perimeter[5-count][location]='Y'
def CheckP(perimeter):
    changerow=[0,1,1]
    changecolumn=[1,0,1]
    Pwin=False
        for col in range(7):
          for row in range (6):
            for change in range (3):
                try:
                    consecutivecount=0
                    for nochange in range(4):
                        if perimeter[row+(changerow[change]*(nochange))]     [col+(changecolumn[change]*(nochange))]=='X':
                            consecutivecount+=1
                        if consecutivecount==4:
                            Pwin=True
                except:
                    continue
    return Pwin
def CheckC(perimeter):
    changerow=[0,1,1]
    changecolumn=[1,0,1]
    Cwin=False
    for col in range(7):
        for row in range (6):
            for change in range (3):
                try:
                    consecutivecount=0
                    for nochange in range(4):
                        if perimeter[row+(changerow[change]*(nochange))][col+(changecolumn[change]*(nochange))]=='Y':
                            consecutivecount+=1
                        if consecutivecount==4:
                            Cwin=True
                except:
                    continue
    return Cwin
def recursive(state,move): #state: the state of board, first starts with an empty board and as the function loops, the state changes Move: no of moves taken by both the player and the computer

 for a in full(state):  #full returns a list of legal moves, which means columns that are not full
    state1= copy.deepcopy(state)
    playerplacetoken(state1, a)
    complete_set[move].append(state1)
    if CheckP(state1): #Check p returns boolean, checking if the player has won
        continue
    for b in full(state1):
        state2= copy.deepcopy(state1)
        PlacingCPUToken(state2, b)
        complete_set[move+1].append(state2)
        if CheckC(state2): #Check C checks if the computer wins and return a boolean
            continue
        while move<44:
            move+=2
            recursive(state2,move)
recursive(state0,0)

but this doesn't work properly (I mean it has no error but the results are not correct) I dont really know how to use a recursive function.Please help!

  • You do a deep copy of the state to compute further moves.
  • You create a new complete_set for each recursive invocation.
  • You never return anything from the recursive step.

Because of this, there's no way for information computed in the nested steps to trickle up to the calling step.

UPDATE: the state is indeed updated by a recursive step: complete_set[...].append(...) does that, because complete_set is global.

Try to think about the type of the function you're trying to write.

Eg it takes a state and an integer depth level. It returns a list of possible moves, which is empty if the depth it too big.

What you may actually want is a tree of moves, where each element of your list is a pair: (move, [...]) . The list contains pairs of the same type: a move with a subtree of moves possible after it, etc. The leaves have an empty set of possible moves.

You might consider calculating the immediate utility function value right when you're building the nodes.

If you make the calculation lazy (using yield and generators), alpha-beta pruning will become easy to implement, too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM