2016-08-08 14 views
2

Ich schreibe ein Python-Skript, das es menschlichen und Computerspielern ermöglichen soll, Tic Tac Toe zu spielen. Um das Board darzustellen, verwende ich ein 3x3 Numpy-Array mit 1 und 0 für die Marken der Spieler (statt "X" und "O"). Ich habe die folgende Funktion geschrieben, um den Sieger zu ermitteln:Wie man eine Funktion zur Bestimmung des Gewinners von Tic-Tac-Toe prägnanter macht

import numpy as np 

class Board(): 
    def __init__(self, grid = np.ones((3,3))*np.nan): 
     self.grid = grid 

    def winner(self): 
     rows = [self.grid[i,:] for i in range(3)] 
     cols = [self.grid[:,j] for j in range(3)] 
     diag = [np.array([self.grid[i,i] for i in range(3)])] 
     cross_diag = [np.array([self.grid[2-i,i] for i in range(3)])] 

     lanes = np.concatenate((rows, cols, diag, cross_diag)) 

     if any([np.array_equal(lane, np.ones(3)) for lane in lanes]): 
      return 1 
     elif any([np.array_equal(lane, np.zeros(3)) for lane in lanes]): 
      return 0 

So zum Beispiel, wenn ich

board = Board() 
board.grid = np.diag(np.ones(3)) 
print board.winner() 

ausführen ich das Ergebnis 1. Was mich etwas stört ist die Wiederholung der any Aussagen. Ich würde denken, dass es eine prägnantere, trockenere Art geben würde, dies zu kodieren. (Ich dachte an einen Schalter/Fall wie in MATLAB, aber das gibt es in Python nicht). Irgendwelche Vorschläge?

+0

Es ist _much_ effizienter, einen Generator ausdruck als ein Listenverständnis zu füttern. "beliebige" Kurzschlüsse, d. h., es stoppt die Auswertung weiterer Elemente, sobald es ein True-Element erhält. Aber wenn Sie eine Liste comp übergeben, muss die gesamte Liste erstellt werden, bevor "any" mit der Arbeit beginnen kann. Wenn Sie dagegen ein gen exp wie 'any (np.array_equal (lane, np.ones (3)) für lane in lanes) übergeben, erzeugt das gen exp nicht die späteren Elemente. Ähnliche Bemerkungen gelten für "alle". –

Antwort

2

Eine andere Möglichkeit ist es, die Summe von lanes zu überprüfen.

s = np.sum(lanes, axis=1) 
    if 3 in s: 
     return 1 
    elif 0 in s: 
     return 0 
1

ich eine Schleife stattdessen gemacht habe, und nur einmal zurückkehren, mit PEP8 anzupassen und zu meinen persönlichen Coding-Standards :)

enumerate in der richtigen Reihenfolge 0,zeromatrix dann 1,onematrix

rval = None 
for i,m in enumerate([np.zeros(3),np.ones(3)]): 
    if any([np.array_equal(lane, m) for lane in lanes]): 
     rval = i; break 
return rval 
nachgeben ehrlich zu sein
+0

Sie brauchen die 'return None' nicht, Python gibt immer' None' zurück, wenn 'return' nicht heißt –

+0

Ich weiß, aber ich dachte, es sei eine schlechte Übung. Ok, dann ist es noch kürzer, danke. –

+2

"In Rückgabeanweisungen konsistent sein. Entweder alle return-Anweisungen in einer Funktion sollten einen Ausdruck zurückgeben, oder keiner von ihnen sollte. Wenn eine return-Anweisung einen Ausdruck zurückgibt, sollten alle return-Anweisungen, bei denen kein Wert zurückgegeben wird, explizit als" none "angeben. und eine explizite Rückgabeanweisung sollte am Ende der Funktion vorhanden sein (falls erreichbar). " -PEP8 – acdr

0

fand ich einen Ausweg, durch eine Lambda-Funktion:

any_lane = lambda x: any([np.array_equal(lane, x) for lane in lanes]) 

if any_lane(np.ones(3)): 
    return 1 
elif any_lane(np.zeros(3)): 
    return 0 

Dies ist auf die Zusammenarbeit eine zusätzliche Zeile hinzufügt de aber macht es insgesamt lesbarer, denke ich.

+1

Sie könnten stattdessen 'functools.partial' verwenden. Auch die '[' '' '' '' '' '' 'sind nicht nur überflüssig, sie erstellen zunächst eine neue Liste. –

0

Dies kann auf zwei Linien durchgeführt werden, aus dem Vorstand ausgehend (grid): einfache Summen entlang Spalten, Zeilen und die beiden Hauptdiagonalen geben Ihnen einen Wert von 0 oder 3, je nachdem, wer (oder einige gewann Zwischenwerte nur wenn niemand gewinnt). Sie können somit berechnen etwas wie:

# Score along each column, row and both main diagonals: 
scores = (grid.sum(axis=0).tolist() + grid.sum(axis=1).tolist() 
      +[grid.trace(), np.flipud(grid).trace()]) 

# If there is no winner, None is declared the winner: 
print "Winner:", 1 if 3 in scores else 0 if 0 in scores else None 

wo flipud() die diagonal in die anti-diagonal-Transformationen (die Diagonale bei 90 ° von der Hauptdiagonalen) durch das Array horizontal Spiegel, so dass ein einfaches trace() den Gesamtwert ergibt entlang der Anti-Diagonale.