Hola, estoy aprendiendo a programar en Python y he intentado hacer una
versión del juego de mesa 'Othello' sólo con texto. Pero mi problema
esque la función que cambia las piezas blancas por negras y viceversa no
funciona, y tras muchas horas probando cosas, me parece que el problema
viene de la función que duplica la matriz (una lista de listas) que
representa el tablero.
Esto se puede observar gracias a lo que imprimen las líneas 164 y 165
del archivo .py; concretamente la 165. Esta línea debería mostrar todo
el rato el mismo tablero (lista) exacto, puesto que no hay nada dentro
de la función 'giraFitxes' (giraFichas) que lo modifique. Pero éste va
adoptando los mismos valores que el tablero provisional que utilizo para
girar las fichas (el que imprime la línea 164). Por eso, deduzco que
cuando creo un tablero provisional con la función
'duplicaTauler' (duplicaTablero) no se crea una lista nueva, sino que la
nueva variable es sólo otra referencia al tablero principal.
Además de ésta forma de duplicar el tablero, lo he probado con la
función descrita en 'http://challenges.qumax.org/?p=351', pero tampoco
ha funcionado. También lo he intentado con un bucle que recorriera las
filas y, dentro de éste, 'duplicado = tablero[fila][:]', pero no hay
forma. Es muy probable que, además de esto, haya algún otro fallo en el
código, pero si es así no me he percatado por culpa de éste que comento.
Entonces, ¿cómo debería hacerlo para crear un tablero provisional con
los mismos valores que el tablero original sin que, al modificarlo, se
modifique también el original?
El programa (las variables, los comentarios, etc.) está en catalán,
espero que no sea una molestia; si lo es, os lo puedo traducir. No sé si
es relevante, pero utilizo Python 2.6.7 en Debian Wheezy (testing).
Muchas gracias por adelantado.
Francesc Gispert
#!/usr/bin/env Python
#-*- coding: UTF-8 -*-
#Aquest programa és una implementació en Python del joc de taula Othello.
#--------------------------------------------------
#Normes
#--------------------------------------------------
# 1. Hi ha un tauler de 8 x 8 caselles. Es comença amb quatre fitxes, dues de blanques i dues de negres, a les posicions centrals.
# 2. Els jugadors han d'anar afegint fitxes del seu color per torns. Les fitxes blanques que queden envoltades per una nova fitxa negra i una que ja hi havia, es transformen en una fitxa negra, i a l'inrevés.
# 3. En cada tirada, el jugador està obligat a girar fitxes del contrincant.
# 4. Guanya el jugador que més fitxes del seu color té en el tauler.
# 5. El joc s'acaba quan un jugador ja no pot girar les fitxes del contrincant o el tauler està ple.
#--------------------------------------------------
#Mòduls
#--------------------------------------------------
from random import random, shuffle
import types
#--------------------------------------------------
#Funcions
#--------------------------------------------------
def menuGeneric(llista): #Funció que genera un menú a través d'una llista d'opcions i retorna l'opció escollida.
opcio = ""
while opcio not in range(1, len(llista) + 1):
for element in range(1, len(llista) + 1):
print "%d) %s" % (element, llista[element - 1])
opcio = raw_input("Escull una opció: ")
try:
opcio = int(opcio)
except:
opcio = ""
if opcio not in range(1, len(llista) + 1):
print "La opció no és vàlida. Torna-ho a intentar."
return opcio
def crearTauler(files, columnes):
tauler = []
for i in range(files):
tauler.append([0] * columnes)
tauler[3][3], tauler[3][4], tauler[4][3], tauler[4][4] = 2, 1, 1, 2
return tauler
def duplicaTauler(tauler):
duplicat = crearTauler(files, columnes)
for y in range(files):
for x in range(columnes):
duplicat[y][x] = tauler[y][x]
return duplicat
def dibuixaTauler(estat):
#Guardem la representació de les línies de separació en variables.
separacioHoritzontal = " +---+---+---+---+---+---+---+---+"
separacioVertical = " | | | | | | | | |"
print " 1 2 3 4 5 6 7 8" #Numerem les columnes.
print separacioHoritzontal
for y in range(files):
print separacioVertical
print y + 1,
for x in range(columnes):
if estat[y][x] == 0:
fitxa = " " #Casella buida.
elif estat[y][x] == 1:
fitxa = "O" #Fitxa blanca.
elif estat[y][x] == 2:
fitxa = "*" #Fitxa negra.
elif estat[y][x] == 3:
fitxa = "." #Possible moviment.
print "| %s" % (fitxa),
print "|"
print separacioVertical
print separacioHoritzontal
print
def comencaUsuari():
aleatori = int(random() * 2)
if aleatori == 0:
return True
return False
def activaPistes():
pistes = raw_input("Vols que es mostrin els moviments possibles? Introdueix \"s\" o \"n\": ").lower()
if pistes == "s" or pistes == "si" or pistes == "sí":
return True
return False
def triaColorFitxes():
color = raw_input("Vols les fitxes blanques (O) o negres (*)? Introdueix \"b\" o \"n\": ").lower().strip()
if color == "b" or color == "blanc" or color == "o":
return 1
return 2
def posicioPossible(y, x):
if y >= 0 and y < columnes and x >= 0 and x < files:
return True
return False
def movimentsPossibles(tauler, fitxaJugador):
movimentsPossibles = []
if fitxaJugador == 1:
fitxaContrincant = 2
else:
fitxaContrincant = 1
posicionsFitxesJugador = []
#Busquem en quines posicions té fitxes el jugador.
for y in range(len(tauler)): #Files.
for x in range(len(tauler[y])): #Columnes.
if tauler[y][x] == fitxaJugador:
posicionsFitxesJugador.append([y, x])
#Busquem les posicions contigües.
direccions = [] #Matriu amb subllistes en forma [y, x].
for posicio in range(len(posicionsFitxesJugador)):
direccions.append([0])
if posicionsFitxesJugador[posicio][0] == 0:
if posicionsFitxesJugador[posicio][1] == 0: #Cantonada superior esquerra.
direccions[posicio] = [[1, 0], [1, 1], [0, 1]]
elif posicionsFitxesJugador[posicio][1] == files - 1: #Cantonada inferior esquerra.
direccions[posicio] = [[1, 0], [1, -1], [0, -1]]
else: #Columna esquerra.
direccions[posicio] = [[1, 0], [1, -1], [1, 1], [0, -1], [0, 1]]
elif posicionsFitxesJugador[posicio][0] == columnes - 1:
if posicionsFitxesJugador[posicio][1] == 0: #Cantonada superior dreta.
direccions[posicio] = [[-1, 0], [-1, 1], [0, 1]]
elif posicionsFitxesJugador[posicio][1] == files - 1: #Cantonada inferior dreta.
direccions[posicio] = [[-1, 0], [-1, -1], [0, -1]]
else: #Columna dreta.
direccions[posicio] = [[-1, 0], [-1, -1], [-1, 1], [0, -1], [0, 1]]
else:
if posicionsFitxesJugador[posicio][1] == 0: #Fila superior.
direccions[posicio] = [[-1, 0], [-1, 1], [0, 1], [1, 1], [1, 0]]
elif posicionsFitxesJugador[posicio][1] == files - 1: #Fila inferior.
direccions[posicio] = [[-1, 0], [-1, -1], [0, -1], [1, -1], [1, 0]]
else: #Caselles centrals.
direccions[posicio] = [[-1, 0], [-1, -1], [0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1]]
#Examinem les posicions contigües.
for posicio in range(len(posicionsFitxesJugador)):
for possibleDireccio in direccions[posicio]:
duplicat = []
for i in range(len(posicionsFitxesJugador)):
auxiliar = posicionsFitxesJugador[i][:]
duplicat.append(auxiliar)
provisional = duplicat[posicio]
provisional[0] += possibleDireccio[0] #y
provisional[1] += possibleDireccio[1] #x
while tauler[provisional[0]][provisional[1]] == fitxaContrincant:
provisional[0] += possibleDireccio[0]
provisional[1] += possibleDireccio[1]
if provisional[0] < 0 or provisional[0] >= files or provisional[1] < 0 or provisional[1] >= columnes:
break
if tauler[provisional[0]][provisional[1]] == 0:
movimentsPossibles.append(provisional)
return movimentsPossibles
def mostrarMovimentsPossibles(tauler, movimentsPossibles):
taulerMoviments = duplicaTauler(tauler)
for posicio in movimentsPossibles:
taulerMoviments[posicio[0]][posicio[1]] = 3
return taulerMoviments
def giraFitxes(tauler, ultimaFitxa, colorJugador):
taulerProvisional = duplicaTauler(tauler)
print "Tauler provisional:", taulerProvisional
print "Tauler (no hauria de canviar):", tauler
#Recorrem el tauler per buscar les fitxes del jugador.
for fila in range(len(tauler)):
for columna in range(fila):
#Reiniciem la posició de l'última fitxa.
y, x = ultimaFitxa
if tauler[fila][columna] == colorJugador: #Calculem la posició de les fitxes que ja hi havia respecte la que s'acaba de col·locar.
direccio_y = fila - y
direccio_x = columna - x
if direccio_x == 0: #Estan en línia recta (vertical).
for i in range(abs(direccio_y)):
moviment_y = direccio_y / abs(direccio_y)
y += moviment_y
taulerProvisional[y][x] = colorJugador
elif direccio_y == 0: #Estan en línia recta (horitzontal).
for i in range(abs(direccio_x)):
moviment_x = direccio_x / abs(direccio_x)
x += moviment_x
taulerProvisional[y][x] = colorJugador
elif abs(direccio_y) == abs(direccio_x): #Estan en diagonal.
for i in range(abs(direccio_x)):
moviment_x = direccio_x / abs(direccio_x)
moviment_y = direccio_y / abs(direccio_y)
x += moviment_x
y += moviment_y
taulerProvisional[y][x] = colorJugador
return taulerProvisional
def cantonada(y, x):
return (y == 0 and x == 0) or (y == 0 and x == columnes - 1) or (y == files - 1 and x == 0) or (y == files - 1 and x == columnes - 1)
def movimentOrdinador(tauler, colorOrdinador):
possibilitats = movimentsPossibles(tauler, colorOrdinador)
shuffle(possibilitats) #Desordenem els possibles moviments per donar un component aleatori al joc.
#Si és possible, tirem a les cantonades.
for i in possibilitats:
if cantonada(i[0], i[1]):
return [i[0], i[1]] #[y, x]
#Si no, tirem on poguem girar més fitxes.
millorPuntuacio = -1
for i in possibilitats:
taulerProvisional = duplicaTauler(tauler)
taulerProvisional[i[0]][i[1]] = colorOrdinador
ultima = [i[0], i[1]]
taulerProvisional = giraFitxes(taulerProvisional, ultima, colorOrdinador)
punts = puntuacio(taulerProvisional, colorOrdinador)
if punts > millorPuntuacio:
millorMoviment = [i[0], i[1]]
millorPuntuacio = punts
return millorMoviment #[y, x]
def puntuacio(tauler, colorJugador):
punts = 0
for fila in range(len(tauler)):
for columna in range(fila):
if tauler[fila][columna] == colorJugador:
punts += 1
return punts
#--------------------------------------------------
#Codi principal
#--------------------------------------------------
#Variables globals.
files = 8
columnes = 8
menu = ["Tornar a jugar.", "Sortir."]
while True:
#Creem el tauler.
tauler = crearTauler(files, columnes)
#Inicialitzem altres variables.
fitxes = 4
tiradaPossible = True
comencaUsuari = comencaUsuari()
pistes = activaPistes()
fitxaJugador = triaColorFitxes()
#Assignem les fitxes de l'ordinador.
if fitxaJugador == 1:
fitxaOrdinador = 2
else:
fitxaOrdinador = 1
#Triem aleatòriament qui comença.
if comencaUsuari:
torn = "usuari"
print "Comences tu."
else:
torn = "ordinador"
print "Comença l'ordinador."
#Bucle partida.
while fitxes < (files * columnes) and tiradaPossible:
if torn == "usuari":
moviments = movimentsPossibles(tauler, fitxaJugador)
#Mostrem el tauler.
if pistes:
dibuixaTauler(mostrarMovimentsPossibles(tauler, moviments))
else:
dibuixaTauler(tauler)
y, x = -1, -1
#Demanem on vol tirar l'usuari.
while not posicioPossible(y, x) or [y, x] not in moviments:
y = raw_input("Introdueix la coordenada vertical (fila) on vols col·locar la teva fitxa: ")
x = raw_input("Introdueix la coordenada horitzontal (columna) on vols col·locar la teva fitxa: ")
try:
y = int(y) - 1
x = int(x) - 1
except:
y, x = -1, -1
if not posicioPossible(y, x) or [y, x] not in moviments:
print "No pots col·locar una fitxa en aquesta posició."
#Hi col·loquem la fitxa.
tauler[y][x] = fitxaJugador
#Girem les fitxes que toquen.
ultima = [y, x]
print ultima
tauler = giraFitxes(tauler, ultima, fitxaJugador)
#Canvi de torn.
torn = "ordinador"
elif torn == "ordinador":
#Mostrem el tauler.
dibuixaTauler(tauler)
ultima = movimentOrdinador(tauler, fitxaOrdinador) #Calculem la posició on col·locar la fitxa.
tauler[ultima[0]][ultima[1]] = fitxaOrdinador #Col·loquem la fitxa.
tauler = giraFitxes(tauler, ultima, fitxaOrdinador) #Girem les fitxes que toquen.
#Canvi de torn.
torn = "usuari"
puntsJugador = puntuacio(tauler, fitxaJugador)
puntsOrdinador = puntuacio(tauler, fitxaOrdinador)
print "Has aconseguit acabar amb %d fitxes al tauler, davant de les %d de l'ordinador." % (puntsJugador, puntsOrdinador)
if puntsJugador > puntsOrdinador: #Victòria.
print "Has guanyat. Enhorabona!"
elif puntsJugador < puntsOrdinador: #Derrota.
print "Has perdut. Llàstima!"
else: #Empat.
print "Hi ha hagut un empat."
print "Què vols fer?"
opcio = menuGeneric(menu)
if opcio == 2:
break
print "Gràcies per jugar!"
'''
Francesc, 03/08/2011
'''
_______________________________________________
Python-es mailing list
Python-es@python.org
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/