2011-12-05 72 views
2

我正在尋找一個3x3井字遊戲棋盤叫做winner(board)的python程序,它需要一個二維列表來表示一個井字遊戲棋盤,並確定是否有是贏家(如果有贏家,是誰),或者如果遊戲以平局結束。該板使用'-'來表示的打開位置,用於'x'播放器1和'o'爲播放器2確定井字遊戲中的獲勝者

我還希望使用的程序和select_row(array, i)其中select_col(array,i)接受的2維陣列(表示爲嵌套列表)和一行或一列的索引,並返回一個表示與該索引關聯的行或列的列表,以及接受方形2維數組並返回具有主對角線元素的列表的過程select_main_diag(array)select_counter_diag(array)或反向對角線(分別)。

收益情況如下:

winner([['-','-','-'], ['-','-','-'], ['-','-','-']]) 
False 

winner([['x','x','x'], ['-','-','-'], ['-','-','-']]) 
'x' 

winner([['o', '-','-'], ['-', 'o','-'], ['-','-','o']]) 
'o' 

winner([['-','-','x'], ['-','-','x'], ['-','-', 'x']]) 
'x' 

winner([['x','o','x'], ['x','o','o'], ['o','x','x']]) 
"Draw" 

winner([['x','o','x'], ['x','o','o'], ['o','-','x']]) 
False 

,並且是我希望包含在代碼中使用的程序如下:

def select_row(lst, i): 
return lst[i] 

def select_col(lst, i): 
    return [lst[idx][i] for idx in range(len(lst))] 

def select_main_diag(array): 
    return [array[i][i] for i in range(len(array))] 

def select_counter_diag(array): 
    return [array[len(array)-i-1][i] for i in range(len(array))] 

我完全新的使用Python和我對此很不熟悉,所以對這個問題的任何建議 - 無論是怎麼去做,怎麼把它放到代碼中 - 都會很有幫助。

+0

這功課嗎? – Nate

+0

@Nate是否有任何可能的情況下,這不是作業? –

+0

這是我的計算機科學課的一個實驗室。因此,我必須處理非常具體的限制。 – user1023010

回答

1

這是我怎麼會去贏家確定:

  1. 對於每一行,列和對角線:是三個空格都一樣嗎?如果是這樣,而且他們不是空的,那麼這就是贏家。
  2. 否則,董事會是否已滿(即沒有空位)?如果是這樣,這是一個平局。
  3. 否則,沒有贏家,遊戲繼續。
0

在下面的實現中,程序試圖最大化獲勝的機會。更強大的版本會盡量減少失敗的機會。另一種策略是瞭解什麼樣的動作導致勝利,什麼樣的動作導致失敗。至於獲勝者,grade_grid(state.grid)給出了答案。

import tkinter 
from itertools import product 
from math import trunc 
from functools import lru_cache, wraps 
from random import choice 
from sys import modules 

################################################################################ 

class Cross(tkinter.Frame): 

    @classmethod 
    def main(cls): 
     tkinter.NoDefaultRoot() 
     root = tkinter.Tk() 
     root.title('Demo') 
     root.resizable(False, False) 
     widget = cls(root) 
     widget.grid() 
     root.mainloop() 

    def __init__(self, master=None, cnf={}, **kw): 
     super().__init__(master, cnf, **kw) 
     self.__ai = CrossAI() 
     space = ' ' * 11 
     self.__buttons = {} 
     for r, c in product(range(3), range(3)): 
      b = tkinter.Button(self, text=space, command=self.__bind(r, c)) 
      b.grid(row=r, column=c, padx=10, pady=10) 
      self.__buttons.setdefault(r, {})[c] = b 

    def __bind(self, row, column): 
     return lambda: self.click(row, column) 

    def click(self, row, column): 
     r, c = self.__ai.move(row, column) 
     if r != -1 != c: 
      self.__buttons[row][column]['text'] = ' X ' 
      if r != -2 != c: 
       self.__buttons[r][c]['text'] = ' O ' 

################################################################################ 

def enum(names): 
    "Create a simple enumeration having similarities to C." 
    return type('enum',(), dict(map(reversed, enumerate(
     names.replace(',', ' ').split())), __slots__=()))() 

################################################################################ 

class Static(type): 

    def __new__(cls, name, bases, members): 
     for name, member in members.items(): 
      if callable(member): 
       members[name] = cls.__wrap(member) 
      elif isinstance(member, property): 
       members[name] = property(cls.__wrap(member.fget), 
             cls.__wrap(member.fset), 
             cls.__wrap(member.fdel), 
             member.__doc__) 
      elif isinstance(member, (classmethod, staticmethod)): 
       members[name] = type(member)(cls.__wrap(member.__func__)) 
     return super().__new__(cls, name, bases, members) 

    @classmethod 
    def __wrap(cls, function): 
     if function: 
      annotations = function.__annotations__ 
      co_varnames = function.__code__.co_varnames 
      if not annotations: 
       return function 
      @wraps(function) 
      def wrapper(*args): 
       for arg, name in zip(args, co_varnames): 
        cls.__raise(arg, annotations[name]) 
       value = function(*args) 
       cls.__raise(value, annotations['return']) 
       return value 
      return wrapper 

    @staticmethod 
    def __raise(item, klass): 
     if klass is None: 
      klass = type(None) 
     elif isinstance(klass, str): 
      klass = vars(modules[item.__module__])[klass] 
     if not isinstance(item, klass): 
      raise TypeError('{} must be of type {}'.format(item, klass)) 

################################################################################ 

class CrossAI(metaclass=Static): 

    STATE = enum('changing, victory, defeat, error, draw') 

    def __init__(self: 'CrossAI') -> None: 
     self.__db = State(((0, 0, 0), (0, 0, 0), (0, 0, 0)), 1) 

    def move(self: 'CrossAI', row: int, column: int) -> tuple: 
     if not self.__db.moves: 
      return -1, -1 
     self.__make_move(row, column) 
     return self.__best_move() 

    def __make_move(self: 'CrossAI', row: int, column: int) -> None: 
     copy = tuple(map(list, self.__db.grid)) 
     copy[row][column] = 1 
     self.__db = State(tuple(map(tuple, copy)), -1) 

    def __best_move(self: 'CrossAI') -> tuple: 
     if not self.__db.moves: 
      return -2, -2 
     score = min(move.grade for move in self.__db.moves) 
     moves = tuple(move for move in self.__db.moves if move.grade == score) 
     final = choice(moves) 
     for r, c in product(range(3), range(3)): 
      if self.__db.grid[r][c] != final.grid[r][c]: 
       self.__db = State(final.grid, 1) 
       return r, c 

################################################################################ 

class State(tuple): 

    @lru_cache(None) 
    def __new__(cls, grid, next_move): 
     return super().__new__(cls, (grid, make_moves(grid, next_move))) 

    @property 
    def grid(self): 
     return self[0] 

    @property 
    def moves(self): 
     return self[1] 

    @property 
    def grade(self): 
     return grade(*self) 

################################################################################ 

@lru_cache(None) 
def make_moves(grid, next_move): 
    moves = [] 
    for r, c in available_moves(grid): 
     copy = tuple(map(list, grid)) 
     copy[r][c] = next_move 
     moves.append(State(tuple(map(tuple, copy)), -next_move)) 
    return frozenset(moves) 

@lru_cache(None) 
def available_moves(grid): 
    return() if grade_grid(grid) else \ 
     tuple((r, c) for r, c in product(range(3), range(3)) if not grid[r][c]) 

@lru_cache(None) 
def grade(grid, moves): 
    return grade_grid(grid) + grade_moves(moves) 

@lru_cache(None) 
def grade_grid(grid): 
    for triplet in combinations(grid): 
     grade = trunc(sum(triplet)/3) 
     if grade: 
      return grade 
    return 0 

@lru_cache(None) 
def combinations(grid): 
    combos = list(grid) 
    for c in range(3): 
     combos.append(tuple(grid[r][c] for r in range(3))) 
    combos.append(tuple(grid[i][i] for i in range(3))) 
    combos.append(tuple(grid[i][2 - i] for i in range(3))) 
    return combos 

@lru_cache(None) 
def grade_moves(moves): 
    return sum(grade(*move) for move in moves) 

################################################################################ 

if __name__ == '__main__': 
    Cross.main()