Master Mind

 ☗ 

I programmi seguenti sono un esempio che mostra diversi livelli di "pythonizzazione" del codice, partendo da una prima versione che può facilmente essere scritta da chi proviene da altri linguaggi a minore astrazione, come BASIC, C, Pascal, per arrivare ad una forma più idiomatica del linguaggio Python.

Primissima versione Python2 "pensata come in Pascal"

import random

#-------------------------------------------------------------------
# Cancella console e scrive messaggio iniziale
#-------------------------------------------------------------------
for z in range(24):
  print
print "PYTHON MASTER MIND"
print "------------------"
print

#-------------------------------------------------------------------
# Prepara lista a con il codice da indovinare
#-------------------------------------------------------------------
a = [0, 0, 0, 0]
i = 0
while i < 4:
    a[i] = random.randint(1, 6)
    i = i + 1

#-------------------------------------------------------------------
# Ciclo principale
#-------------------------------------------------------------------
t = 0
while 1:

    #-------------------------------------------------------------------
    # Copia la lista a nella lista b
    #-------------------------------------------------------------------
    b = [0, 0, 0, 0]
    i = 0
    while i < 4:
        b[i] = a[i]
        i = i + 1

    #-------------------------------------------------------------------
    # Legge sequenza da tastiera e la splitta nella lista c
    #-------------------------------------------------------------------
    d = raw_input("Codice? ")
    c = [0, 0, 0, 0]
    i = 0
    while i < 4:
        c[i] = eval(d[i])
        i = i + 1

    #-------------------------------------------------------------------
    # Calcola quanti giusti nella posizione giusta
    #-------------------------------------------------------------------
    neri = 0
    i = 0
    while i < 4:
        if c[i] == b[i]:
            neri = neri + 1
            c[i] = 999
            b[i] = 0
        i = i + 1

    #-------------------------------------------------------------------
    # Calcola quanti rimanenti giusti ma nella posizione sbagliata
    #-------------------------------------------------------------------
    bianchi = 0
    i = 0
    while i < 4:
        j = 0
        while j < 4:
            if c[i] == b[j]:
                bianchi = bianchi + 1
                c[i] = 999
                b[j] = 0
            j = j + 1
        i = i + 1

    #-------------------------------------------------------------------
    # Scrive risultato
    #-------------------------------------------------------------------
    t = t + 1
    print "Tentativo",t,"  Codice",d," NERI =",neri,"  BIANCHI =",bianchi
    if neri == 4:
        break

print "ESATTO!"


Seconda versione

Le iterazioni while sono state sostituite con for.
import random

a = [0, 0, 0, 0]
b = [0, 0, 0, 0]
c = [0, 0, 0, 0]

for i in range(4):
    a[i] = random.randint(1, 6)

while 1:

    neri = 0
    bianchi = 0

    for i in range(4):
        b[i] = a[i]

    d = raw_input("Tenta: ")
    for i in range(4):
        c[i] = eval(d[i])

    for i in range(4):
        if c[i] == b[i]:
            neri = neri + 1
            c[i] = 999
            b[i] = 0

    for i in range(4):
        for j in range(4):
            if c[i] == b[j]:
                bianchi = bianchi + 1
                b[j] = 0

    print " "*15,"Codice",d,"  NERI =", \
          neri,"  BIANCHI =",bianchi

    if neri == 4:
        print "ESATTO!"
        break


Terza versione

Le iterazioni sulle liste sono state sostituite con list comprehension. La copia degli elementi della lista 'a' nella lista 'b' è stata ridotta ad un semplice sezionamento dell'intera lista 'a'. I due cicli per il controllo bianchi/neri sono stati accorpati.
import random

a = [0] * 4
b = [0] * 4
c = [0] * 4

a = [random.randint(1, 6) for i in range(4)]

while True:

    neri = bianchi = 0

    b = a[:]

    d = raw_input("Tenta: ")
    c = [int(d[i]) for i in range(4)]

    for i in range(4):
        if c[i] = =b[i]:
            neri += 1
            b[i] = 0
        else:
            for j in range(4):
                if c[i] == b[j] and b[j] != c[j]:
                    bianchi += 1
                    b[j] = 0
                    break

    print " "*15,"Codice",d,"  NERI =", \
          neri,"  BIANCHI =",bianchi

    if neri == 4:
        print "ESATTO!"
        break


Quarta versione (compatibile Python2 e 3)

Il controllo bianchi/neri è stato spostato in una funzione a parte (generalizzata per accettare codici di qualsiasi lunghezza) e non non è più necessaria una lista di copia. La lista passata al parametro 't' viene modificata, ma trattandosi del codice inserito da tastiera questo viene rinnovato ad ogni ciclo. Il risultato viene scritto usando la formattazione di stringa in cui i diversi campi '%' vengono sostituiti rispettivamente con i valori presenti nella tupla finale. La dichiarazione iniziale delle liste non è più necessaria. La costruzione della lista tentativo viene fatta iterando direttamente sugli elementi della stringa immessa da tastiera, invece che iterare attraverso indici. Infine l'input da tastiera e la stampa a video sono state rese compatibili Python2 e 3.
from random import randint

#------------------------------------------------------------------------------

def confronta(c, t):
    neri = bianchi = 0
    for i in range(len(c)):
        if c[i] == t[i]:
            neri += 1
            t[i] = 0
        else:
            for j in range(len(c)):
                if c[i] == t[j] and t[j] != c[j]:
                    bianchi += 1
                    t[j] = 0
                    break
    return neri, bianchi

#------------------------------------------------------------------------------

codice = [randint(1, 6) for i in range(4)]
while True:
    try:              d = raw_input("Tenta: ") #Py2
    except NameError: d = input("Tenta: ")     #Py3
    tentativo = [int(i) for i in d]
    neri, bianchi = confronta(codice, tentativo)
    print("%15s Codice=%4s NERI=%1s BIANCHI=%1s" % (" ", d, neri, bianchi))
    if neri == 4:  break
print("ESATTO!")

#------------------------------------------------------------------------------


Idiomatic Python

Una serie di linee guida per scrivere codice pythonicamente corretto: python.net/~goodger/projects/pycon/2007/idiomatic/handout.html