4子棋程序

规则简单,没有斜线。棋力低还慢,但程序完整、短。Search(博弈树 α-β剪枝 评价函数/局面分)

  1 # -*- coding: gbk -*-
  2 from functools import reduce
  3 from copy import deepcopy
  4 
  5 def get_list(n, v): return list(map(lambda _:deepcopy(v), range(n)))
  6 
  7 B = 'B'; W = 'W'; E = '.' # black, white, empty
  8 ltm = [9, 9] # left-top-most
  9 
 10 def init_brd():
 11     global b
 12     b = get_list(11, 11 * [E])
 13     b[0] = b[10] = [' '] + list(map(lambda _:str(_), range(1, 10))) + [' ']
 14     for i in range(1, 10): b[i][0] = b[i][10] = str(i)
 15 
 16 def print_brd(): # Don't nest reduce it's like n += i
 17     for i in range(11): print(reduce(lambda x,y:x+' '+y, b[i], ''))
 18 
 19 class Won(Exception):
 20     def __init__(m, n) : m.n = n
 21 
 22 def update_ltm(x, y): # update
 23     global ltm
 24     x -= 1; y -= 1
 25     if x < 1: x = 1
 26     if y < 1: y = 1
 27     if x < ltm[0]: ltm[0] = x
 28     if y < ltm[1]: ltm[1] = y
 29 
 30 def get_longest_run(x, y, dx, dy): # 搜索水平或竖直最长连续串
 31     m = [0, 0]; nb = nw = 0; pp = '' # max, n_black, n_white, previous_piece
 32     def um(): # update max
 33         if nb == 4: raise Won(9)
 34         if nw == 4: raise Won(-9)
 35         if nb > m[0]: m[0] = nb
 36         if nw > m[1]: m[1] = nw
 37     def cont(): return pp == '' or pp == p # continuous
 38     while True:
 39         p = b[y][x]
 40         if p == W:
 41             if cont(): nw += 1
 42             else: um(); nb = 0; nw = 1
 43         elif p == B:
 44             if cont(): nb += 1
 45             else: um(); nb = 1; nw = 0
 46         elif p == E: um(); nb = nw = 0
 47         else: break
 48         x += dx; y += dy; pp = p
 49     return m
 50 
 51 def get_score(): # 搜索全盘,不支持对角线
 52     try:
 53         m = [0, 0]
 54         def um(t):
 55             if t[0] > m[0]: m[0] = t[0]
 56             if t[1] > m[1]: m[1] = t[1]
 57         for x in range(1, 10): um(get_longest_run(x, 1, 0, 1))
 58         for y in range(1, 10): um(get_longest_run(1, y, 1, 0))
 59         return m[0] - m[1] # 黑方最长串长度 - 白方
 60     except Won as w: return w.n # raised by get_longest_run
 61 
 62 def get_winner():
 63     s = get_score()
 64     return '' if s == -9 or s == 9 else None
 65 
 66 def search(ll): # level
 67     global best
 68     s = []; c = [] # scores, coordinates
 69     for y in range(ltm[0], 10):
 70         for x in range(ltm[1], 10):
 71             if b[y][x] != E: continue
 72             b[y][x] = W if ll & 1 else B # 双方交替落子
 73             s.append(get_score() if ll > 0 else search(ll + 1))
 74             if ll == 0: c.append((x, y))
 75             b[y][x] = E
 76     if ll & 1: return min(s) # 对手走时按最坏情况考虑
 77     else:
 78         m = max(s) # 自己走时选最好一步
 79         if ll != 0: return m
 80         for i in range(len(s)):
 81             if s[i] != m: continue
 82             best = c[i]
 83             return
 84     raise Won(0)
 85 
 86 def put_piece(x, y, p): b[y][x] = p; update_ltm(x, y)
 87 
 88 def machine_move():
 89     try:
 90         search(0)
 91         put_piece(best[0], best[1], B)
 92     except Exception: quit()
 93 
 94 def human_move():
 95     while 1:
 96         try:
 97             (x, y) = map(lambda _:int(_), input('Your move (x <no-space> y, 00 to quit) ? '))
 98             if (x, y) == (0, 0): quit()
 99             if x < 1 or x > 9 or y < 1 or y > 9 or b[y][x] != E: continue
100             put_piece(x, y, W); break
101         except Exception: pass
102 
103 init_brd(); b[5][5] = B
104 while 1:
105     print_brd()
106     if get_winner() != None: break
107     human_move()
108     machine_move()

 

posted @ 2021-11-30 22:17  Fun_with_Words  阅读(66)  评论(0编辑  收藏  举报









 张牌。