Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Moleri <pmoleri@PABLOMOLERI-PC.(none)>2009-08-28 04:37:26 (GMT)
committer Pablo Moleri <pmoleri@PABLOMOLERI-PC.(none)>2009-08-28 04:37:26 (GMT)
commitf8c647e53f49f1cc96c55814eb29d8c32e71c3f6 (patch)
tree59a31a3aa028e178c4d4e8902b3ec4babcd56c99
parent6678b5b4b0b1115089e6280ce329b37389da126a (diff)
Versión final para ceibalJAM 4
Se agregan los 5 pasos del taller y un archivo que muestra que cambios hay.
-rw-r--r--BatallaNaval.activity/BatallaNaval.py249
-rw-r--r--BatallaNaval.activity/BatallaNavalActivity.py28
-rw-r--r--BatallaNaval.activity/Collaboration.py21
-rw-r--r--BatallaNaval.activity/activity/activity.info2
-rw-r--r--BatallaNaval.activity/activity/batalla-naval-icon.svg25
-rw-r--r--taller/BatallaNaval-1.py151
-rw-r--r--taller/BatallaNaval-2.py224
-rw-r--r--taller/BatallaNaval-3.py228
-rw-r--r--taller/BatallaNaval-4.py284
-rw-r--r--taller/BatallaNaval-5.py325
-rw-r--r--taller/pasos.txt55
11 files changed, 1437 insertions, 155 deletions
diff --git a/BatallaNaval.activity/BatallaNaval.py b/BatallaNaval.activity/BatallaNaval.py
index ceee1ee..ea99a1d 100644
--- a/BatallaNaval.activity/BatallaNaval.py
+++ b/BatallaNaval.activity/BatallaNaval.py
@@ -7,14 +7,11 @@ import gtk
import logging
import random
-try:
- from sugar.activity.activity import Activity, ActivityToolbox
-except:
- pass
-
+# Permite definir un Log que filtra mensajes a la salida estándar dependiendo de nivel elegido.
log = logging.getLogger('BatallaNaval')
log.setLevel(logging.DEBUG)
+# Diccionario que contiene el nombre y largo de cada barco
lista_barcos = {
"Portaaviones": 5,
"Acorazado": 4,
@@ -23,6 +20,8 @@ lista_barcos = {
"Destructor": 2}
class PanelPrincipal(gtk.HBox):
+ ''' Panel Principal es un Widget que contiene ambos tableros y se encarga
+ de crear los barcos en posiciones al azar para cada tablero '''
def __init__(self):
gtk.HBox.__init__(self, True)
@@ -34,23 +33,25 @@ class PanelPrincipal(gtk.HBox):
barcos_propios = crear_barcos()
for barco in barcos_propios:
self.tablero1.agregar_barco(barco, True)
- log.debug("barco:%s, %s (%s, %s)" % (barco.name, barco.orientacion, barco.pos[0], barco.pos[1]))
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
log.debug("Barcos Enemigos")
self.barcos_enemigos = crear_barcos()
for barco in self.barcos_enemigos:
self.tablero2.agregar_barco(barco, False)
- log.debug("barco:%s, %s (%s, %s)" % (barco.name, barco.orientacion, barco.pos[0], barco.pos[1]))
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
self.add(self.tablero1)
self.add(self.tablero2)
- self.show_all()
-
self.jugadas_enemigas = [] # Lleva un registro de las jugadas hechas por la computadora
+
+ self.show_all()
# Carga barcos remotos
def cargar_barcos(self, barcos):
+ ''' Esta función es llamada cuando me conecto en red con otro usuario, recibo
+ una tupla con los datos de los barcos enemigos. '''
log.debug("Cargando barcos enemigos")
self.tablero2.barcos = []
for dato in barcos:
@@ -64,19 +65,25 @@ class PanelPrincipal(gtk.HBox):
self.tablero2.agregar_barco(barco, False)
log.debug("barco:%s, %s (%s, %s)" % (barco.name, barco.orientacion, barco.pos[0], barco.pos[1]))
- # Cuando el enemigo juega sobre mi tablero, hago la judada y le respondo si fue tocado
def jugada_red(self, x, y):
+ ''' Callback de colaboración para la señal Play.
+ Cuando el enemigo juega sobre mi tablero, reflejo la judada y le respondo si fue tocado '''
return self.tablero1.jugada(self.tablero1.filas[x-1][y-1])
- # Cuando yo mismo hice una jugada sobre el tablero enemigo, si hay colaboración actualizo según la respuesta
def jugada_hecha(self, x, y):
- # Si hay colaboración, indico al oponente la jugada que hice
- if self.colaboracion:
+ ''' Cuando yo mismo hice una jugada sobre el tablero enemigo
+ si la actividad está compartida indico al oponente la jugada que hice,
+ en caso contrario me simulo una jugada random del enemigo. '''
+
+ # Si estoy compartiendo con alguien, indico al oponente la jugada que hice
+ if self.colaboracion and self.colaboracion.entered:
+ log.debug("Señalo jugada a los participantes")
self.colaboracion.Play(x, y)
return
# Sinó, la computadora hace una jugada al azar sobre el tablero propio
if len(self.jugadas_enemigas) == 100:
+ log.error("Alcanzó las 100 jugadas.")
return
ok = False
@@ -86,14 +93,64 @@ class PanelPrincipal(gtk.HBox):
ok = True
self.jugadas_enemigas.append((x, y))
- self.tablero1.filas[x-1][y-1].clicked()
+ self.tablero1.jugada(self.tablero1.filas[x-1][y-1])
+
+class Barco(gtk.Frame):
+ ''' Esta clase representa un barco, tiene nombre, largo, orientación y posición.
+ Como es un widget puede ser mostrado en la pantalla y tiene un texto con el nombre del barco '''
+ horizontal = 'H'
+ vertical = 'V'
+
+ def __init__(self, nombre, largo, pos, orientacion = horizontal):
+ gtk.Frame.__init__(self)
+ self.nombre = nombre
+ self.largo = largo
+ self.pos = pos
+
+ # Agrega una etiqueta con el nombre del barco
+ self.label = gtk.Label(nombre)
+ self.add(self.label)
+
+ self.set_orientacion(orientacion) # Graba la orientación y ajusta la etiqueta a dicha orientación.
+
+ def set_orientacion(self, orientacion):
+ ''' Graba la orientación y ajusta la etiqueta a dicha orientación. '''
+ self.orientacion = orientacion
+ if self.orientacion == Barco.horizontal:
+ self.label.set_angle(0)
+ else:
+ self.label.set_angle(90)
+
+ def get_inicio(self):
+ return self.pos
+
+ def get_fin(self):
+ if self.orientacion == Barco.horizontal:
+ return self.pos[0], self.pos[1] + self.largo - 1
+ else:
+ return self.pos[0] + self.largo - 1, self.pos[1]
+
+ def get_filas(self):
+ return range(self.get_inicio()[0], self.get_fin()[0]+1)
+
+ def get_cols(self):
+ return range(self.get_inicio()[1], self.get_fin()[1]+1)
+
+ def get_celdas(self):
+ return [(f, c) for f in self.get_filas() for c in self.get_cols()]
+
def crear_barcos():
- barcos = [Barco(b[0], b[1], None) for b in lista_barcos.items()]
+ ''' Parte de la lista_barcos para crear un conjunto de barcos en posiciones al azar. '''
- celdas_ocupadas = []
+ # Convierte la lista de definición en una lista de objetos Barco sin posición definida
+ barcos = [Barco(nombre, largo, None) for nombre, largo in lista_barcos.items()]
+
+ celdas_ocupadas = [] # Llevo una lista de las celdas ya ocupadas por los barcos
for barco in barcos:
+ # Para cada barco me mantengo en un loop hasta que encuentre coordenadas al azar que no
+ # intersecten con ningún barco ya ubicado.
ok = False
while not ok:
# Determino al azar si es horizontal o vertical
@@ -107,41 +164,46 @@ def crear_barcos():
barco.set_orientacion(Barco.vertical)
posx = random.randint(1, 10-barco.largo+1)
posy = random.randint(1, 10)
-
barco.pos = (posx, posy)
- ok = True
- for celda in barco.get_celdas():
- if celda in celdas_ocupadas:
- ok = False
- if ok:
+
+ # Verifico si la posición elegida no intersecciona con las celdas ya ocupadas por otros barcos
+ # Convierto las listas en sets y aplico intersección
+ interseccion = set(barco.get_celdas()) & set(celdas_ocupadas)
+ if not interseccion:
+ ok = True
celdas_ocupadas.extend(barco.get_celdas())
return barcos
class Celda(gtk.Button):
-
- def __init__(self, pos, clicked_cb):
+ ''' Esta clase representa una celda del tablero, como es subclase de button se le puede
+ conectar la señal "clicked".
+ También presenta funciones para ocultar y colorearse dependiendo de si tocó un barco o dió agua. '''
+
+ def __init__(self, pos):
gtk.Button.__init__(self)
self.pos = pos
-
- self.connect("clicked", clicked_cb)
def ocultar(self):
+ ''' Oculta permanentemente la celda, de modo que show_all no la muestre '''
self.set_no_show_all(True)
self.hide()
- def tocado(self):
- color = gtk.gdk.Color(65535,65535/2,0)
+ def colorear(self, color):
self.modify_bg(gtk.STATE_NORMAL, color)
self.modify_bg(gtk.STATE_PRELIGHT, color)
self.show() # Por si está oculta atrás de un barco
+
+ def tocado(self):
+ self.colorear( gtk.gdk.Color(65535,65535/2,0) )
def agua(self):
- color = gtk.gdk.Color(0,0,65535/2)
- self.modify_bg(gtk.STATE_NORMAL, color)
- self.modify_bg(gtk.STATE_PRELIGHT, color)
- self.show() # Por si está oculta atrás de un barco
-
+ self.colorear( gtk.gdk.Color(0,0,65535/2) )
+
+
class Tablero(gtk.Frame):
+ ''' Define un tablero, el tablero está definido con una tabla exterior que permite poner
+ los títulos de las filas y las columnas (que a su vez son tablas) y una tabla interior
+ que tiene todas las celdas del tablero (tabla_celdas). '''
def __init__(self, llamada_jugada_hecha):
gtk.Frame.__init__(self)
@@ -159,62 +221,65 @@ class Tablero(gtk.Frame):
label = gtk.Label(char)
tabla_letras.attach(label, 0, 1, i-1, i)
- # Se hace una tabla para ubicar las letras, los números y el tablero
+ # Se hace una tabla para ubicar las letras, los números y la tabla de celdas
self.tabla = gtk.Table(2, 2, False)
self.add(self.tabla)
+ # Opciones para las tablas de letras y números.
opciones = gtk.SHRINK|gtk.FILL
- label = gtk.Label(" ")
+ label = gtk.Label(" ") # Para dar más espacio a la columna de letras
self.tabla.attach(label, 0, 1, 0, 1, xoptions=opciones, yoptions=opciones)
-
self.tabla.attach(tabla_numeros, 1, 2, 0, 1, xoptions=opciones, yoptions=opciones)
self.tabla.attach(tabla_letras, 0, 1, 1, 2, xoptions=opciones, yoptions=opciones)
- self.filas = []
-
# El tablero es otra tabla
self.tabla_celdas = gtk.Table(10, 10, True)
self.tabla.attach(self.tabla_celdas, 1, 2, 1, 2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL|gtk.EXPAND)
-
+
+ self.filas = []
+ # Creo todas las celdas, las guardo en la colección de filas y las adjunto al tablero
for i in range(1, 11):
- row = []
+ fila = []
for j in range(1, 11):
- left = j - 1
- top = i - 1
- celda = Celda((i, j), self.celda_clickeada)
- row.append(celda)
- self.tabla_celdas.attach(celda, left, j, top, i)
- #print label.get_text()
- self.filas.append(row)
+ celda = Celda((i, j))
+ celda.connect("clicked", self.celda_clickeada)
+ fila.append(celda)
+ self.tabla_celdas.attach(celda, j-1, j, i-1, i)
+ self.filas.append(fila)
- self.barcos = [] # Los barcos que hay en el tablero
+ # Los barcos que hay en el tablero
+ self.barcos = []
+ # Callback para cuando el jugador hace una jugada en el tablero
self.llamada_jugada_hecha = llamada_jugada_hecha
- def agregar_barco(self, barco, show):
+ def agregar_barco(self, barco, mostrar):
+ ''' Agrega un barco al tablero, si mostrar=True sustituye las celdas que ocupa por el barco. '''
self.barcos.append(barco)
- if show:
- for i in barco.get_filas():
- for j in barco.get_cols():
- self.ocultar_celda(i, j)
- izq = barco.get_inicio()[1]-1
- der = barco.get_fin()[1]
- arr = barco.get_inicio()[0]-1
- aba = barco.get_fin()[0]
- self.tabla_celdas.attach(barco, izq, der, arr, aba)
-
+ if mostrar:
+ # Oculta las celdas que ocupa el barco
+ for i, j in barco.get_celdas():
+ self.ocultar_celda(i, j)
+
+ # Obtiene los extremos del barco y lo adjunta a la tabla
+ arr, izq = barco.get_inicio()
+ aba, der = barco.get_fin()
+ self.tabla_celdas.attach(barco, izq-1, der, arr-1, aba)
+
def ocultar_celda(self, i, j):
self.filas[i-1][j-1].ocultar()
def celda_clickeada(self, celda):
- # Cuando hay definido un callback de jugadas hechas, significa que es el tablero en el que puedo jugar
+ ''' Cuando hay definido un callback de jugadas hechas, significa que en este tablero puedo jugar.
+ Realizo la jugada y notifico al callback '''
if self.llamada_jugada_hecha:
# Este es el callback para cuando clickean una celda
self.jugada(celda)
self.llamada_jugada_hecha(celda.pos[0], celda.pos[1])
def jugada(self, celda):
+ ''' verifica si la jugada da en algún barco o en el agua y manda la señal correcta a la celda '''
tocado = False
for barco in self.barcos:
if celda.pos in barco.get_celdas():
@@ -222,59 +287,16 @@ class Tablero(gtk.Frame):
celda.tocado()
if not tocado:
celda.agua()
-
+
+ log.debug("Pos:%s Tocado:%s", str(celda.pos), tocado)
return tocado
-class Barco(gtk.Frame):
-
- horizontal = 'H'
- vertical = 'V'
-
- def __init__(self, nombre, largo, pos, orientacion = horizontal):
- #gtk.Label.__init__(self, nombre)
- gtk.Frame.__init__(self)
- self.nombre = nombre
- self.largo = largo
- self.pos = pos
- self.label = gtk.Label(nombre)
- self.add(self.label)
- self.set_orientacion(orientacion)
-
- def set_orientacion(self, orientacion):
- self.orientacion = orientacion
- if self.orientacion == Barco.horizontal:
- self.label.set_angle(0)
- else:
- self.label.set_angle(90)
-
- def get_inicio(self):
- return self.pos
-
- def get_fin(self):
- if self.orientacion == Barco.horizontal:
- return self.pos[0], self.pos[1] + self.largo - 1
- else:
- return self.pos[0] + self.largo - 1, self.pos[1]
-
- def get_filas(self):
- return range(self.get_inicio()[0], self.get_fin()[0]+1)
-
- def get_cols(self):
- return range(self.get_inicio()[1], self.get_fin()[1]+1)
-
- def get_celdas(self):
- return [(f, c) for f in self.get_filas() for c in self.get_cols()]
-
-# Esta función es el punto de entrada común para sugar y modo standalone
-# standalone es un boolean que indica si es Standalone o se ejecuta desde Sugar
def init(standalone, ventana_principal):
-
+ ''' Esta función es el punto de entrada común para sugar y modo standalone
+ standalone es un boolean que indica si es Standalone o se ejecuta desde Sugar '''
panel_principal = PanelPrincipal()
if not standalone:
- toolbox = ActivityToolbox(ventana_principal)
- ventana_principal.set_toolbox(toolbox)
- toolbox.show()
ventana_principal.set_canvas(panel_principal)
# Colaboración
@@ -285,24 +307,19 @@ def init(standalone, ventana_principal):
panel_principal.cargar_barcos, # World
panel_principal.jugada_red, # Play
panel_principal.tablero1.barcos)# Mis barcos
-
else:
ventana_principal.add(panel_principal)
panel_principal.colaboracion = None
-
+
ventana_principal.set_title("Batalla Naval - ceibalJAM")
ventana_principal.connect("destroy", lambda wid: gtk.main_quit())
ventana_principal.connect("delete_event", lambda a1, a2: gtk.main_quit())
ventana_principal.show()
-# Este es el procedimiento principal en modo standalone
-def main():
+# Este código se ejecuta sólo cuando se ejecuta directo ese módulo (no cuando se importa desde sugar)
+if __name__ == "__main__":
+ log.addHandler(logging.StreamHandler())
ventana_principal = gtk.Window(gtk.WINDOW_TOPLEVEL)
init(True, ventana_principal)
gtk.main()
- return 0
-
-# Este código se ejecuta sólo cuando se ejecuta directo ese módulo (no cuando se importa desde sugar)
-if __name__ == "__main__":
- main()
diff --git a/BatallaNaval.activity/BatallaNavalActivity.py b/BatallaNaval.activity/BatallaNavalActivity.py
index 1a0f153..2e8db11 100644
--- a/BatallaNaval.activity/BatallaNavalActivity.py
+++ b/BatallaNaval.activity/BatallaNavalActivity.py
@@ -1,31 +1,25 @@
+# -*- coding: cp1252 -*-
+
from sugar.activity.activity import Activity, ActivityToolbox
import BatallaNaval
from Collaboration import CollaborationWrapper
class BatallaNavalActivity(Activity):
+ ''' Clase llamada por sugar cuando se ejecuta la actividad.
+ El nombre de esta clase está señalada en el archivo activity/activity.info '''
+
def __init__(self, handle):
Activity.__init__(self, handle)
- self.connect('destroy', self._cleanup_cb)
self.gamename = 'BatallaNaval'
- self.set_title("Batalla Naval")
-
- # connect to the in/out events
- self.connect('focus_in_event', self._focus_in)
- self.connect('focus_out_event', self._focus_out)
+ # Crea la barra de herramientas básica de Sugar
+ toolbox = ActivityToolbox(self)
+ self.set_toolbox(toolbox)
+ toolbox.show()
+
+ # Crea una instancia de Colaboración por si se quiere compartir la actividad
self.colaboracion = CollaborationWrapper(self)
# The activity is a subclass of Window, so it passses itself to the init function
BatallaNaval.init(False, self)
- # It never returns, gtk.main()
-
- def _cleanup_cb(self, data=None):
- return
-
- # We could use these methods to conserve power by having the activity stop processing when it is in the background.
- def _focus_in(self, event, data=None):
- return
-
- def _focus_out(self, event, data=None):
- return
diff --git a/BatallaNaval.activity/Collaboration.py b/BatallaNaval.activity/Collaboration.py
index 5d5d79c..38ddda1 100644
--- a/BatallaNaval.activity/Collaboration.py
+++ b/BatallaNaval.activity/Collaboration.py
@@ -29,11 +29,19 @@ except:
from sugar.presence.tubeconn import TubeConnection as SugarTubeConnection
from dbus.gobject_service import ExportedGObject
+''' En todas las actividades colaborativas Sugar nos matiene al tanto cuando entra o sale un Jugador
+ Para que todos conozcan el estado de la Actividad se maneja la técnica Hello World,
+ donde cuando un participante entra se emite una señal Hello que llega a todos los participantes
+ y los participantes responden directamente al nuevo el método "World", mediante la cual
+ se le pasa el estado actual de la actividad.
+ Luego las actualizaciones se dan con señal Play, mediante la cual cada participante comunica al
+ resto su jugada.
-# Todas las actividades colaborativas de sugar deben tener implentadas las señales "Hello" y "World"
-# Cuando alguien entra a la colaboración sugar automáticamente emite la señal Hello
-# Este wrapper automáticamente responde con la señal World, que sirve para informarle al nuevo
-# participante el estado actual.
+ En resumen en este módulo se encapsula la lógica de la "colaboración" con el siguiente funcionamiento:
+ - Cuando alguien entra a la colaboración se emite la señal Hello
+ - Quien recibe la señal automáticamente responde con la señal World
+ - Cada vez que alguien juega emite la señal Play
+'''
SERVICE = "org.ceibaljam.BatallaNaval"
IFACE = SERVICE
@@ -111,7 +119,7 @@ class CollaborationWrapper(ExportedGObject):
for buddy in self.activity._shared_activity.get_joined_buddies():
logger.debug('Buddy %s is already in the activity',
buddy.props.nick)
-
+
def participant_change_cb(self, added, removed):
logger.debug('Tube: Added participants: %r', added)
logger.debug('Tube: Removed participants: %r', removed)
@@ -126,8 +134,7 @@ class CollaborationWrapper(ExportedGObject):
logger.debug('Buddy %s was removed' % buddy.props.nick)
if not self.entered:
if self.is_initiator:
- logger.debug("I'm initiating the tube, will "
- "watch for hellos.")
+ logger.debug("I'm initiating the tube, will watch for hellos.")
self.add_hello_handler()
else:
logger.debug('Hello, everyone! What did I miss?')
diff --git a/BatallaNaval.activity/activity/activity.info b/BatallaNaval.activity/activity/activity.info
index 7cb17e8..fa8b0b2 100644
--- a/BatallaNaval.activity/activity/activity.info
+++ b/BatallaNaval.activity/activity/activity.info
@@ -3,7 +3,7 @@ name = BatallaNaval
bundle_id = org.ceibaljam.BatallaNaval
class = BatallaNavalActivity.BatallaNavalActivity
icon = batalla-naval-icon
-activity_version = 2
+activity_version = 1
host_version = 1
show_launcher = no
license = GPLv2+
diff --git a/BatallaNaval.activity/activity/batalla-naval-icon.svg b/BatallaNaval.activity/activity/batalla-naval-icon.svg
index 432bd56..3c288f8 100644
--- a/BatallaNaval.activity/activity/batalla-naval-icon.svg
+++ b/BatallaNaval.activity/activity/batalla-naval-icon.svg
@@ -12,8 +12,7 @@
height="55"
id="svg4502"
style="display:inline">
- <defs
- id="defs4504" />
+ <defs id="defs4504" />
<g
transform="translate(-0.2226721,0.2016908)"
@@ -21,21 +20,20 @@
style="opacity:0.5">
<g
transform="translate(0,-1.8115502)"
- id="barras_horizontales">
+ id="barras_horizontales"
+ fill="&fill_color;">
<rect
width="51.214573"
height="3.7854252"
x="2.4493928"
y="22.482435"
- id="rect2398"
- style="opacity:1;fill:&stroke_color;fill-opacity:1;" />
+ id="rect2398" />
<rect
width="51.214573"
height="3.7854252"
x="2.4493928"
y="39.06778"
- id="rect2404"
- style="opacity:1;fill:&stroke_color;fill-opacity:1;" />
+ id="rect2404" />
</g>
<use
transform="matrix(0,0.9057751,-1.1040268,0,62.122828,5.4432283)"
@@ -48,21 +46,20 @@
</g>
<g id="terron">
<path
- d="M 38.822128,44.108722 C 38.822128,44.108722 38.445765,44.108722 38.092819,44.108722 C 38.092819,42.747378 38.097001,38.459638 38.097001,37.325183 C 38.097001,37.325183 38.097001,37.325183 38.097001,37.323527 L 38.097001,24.562988 L 38.089474,16.811436 C 38.086128,15.932855 37.361837,15.224857 36.48031,15.228997 C 36.052928,15.228997 35.648965,15.396267 35.347873,15.696856 C 35.045946,15.999101 34.882019,16.399058 34.883691,16.823857 C 34.883691,16.863604 34.885364,19.358576 34.887873,21.45773 L 22.071438,21.45773 C 20.330965,21.45773 18.920019,22.854682 18.920019,24.575409 L 18.920019,26.300276 L 13.265364,26.303588 C 12.377982,26.309384 11.663728,27.024008 11.667074,27.896793 C 11.668746,28.321592 11.837691,28.719892 12.141291,29.017998 C 12.446565,29.316931 12.850528,29.479232 13.277073,29.477576 C 13.326419,29.477576 16.696965,29.47592 18.919182,29.474263 L 18.919182,37.014658 C 18.919182,37.02625 18.915837,37.036187 18.915837,37.046952 C 18.915837,37.104917 18.919182,42.545329 18.919182,44.107894 C 18.567073,44.107894 18.189873,44.107894 18.189873,44.107894 C 17.285765,44.125284 16.584055,44.849844 16.59911,45.724285 C 16.61751,46.601209 17.351837,47.296787 18.234201,47.279397 L 20.537546,47.277741 C 21.439146,47.26118 22.145037,46.535792 22.126637,45.661352 L 22.123292,40.442034 L 34.887873,40.442034 L 34.882019,45.661352 C 34.865292,46.53662 35.571182,47.262009 36.472783,47.277741 L 38.774455,47.279397 C 39.661,47.296787 40.393656,46.601209 40.411219,45.724285 C 40.428782,44.849844 39.723728,44.126112 38.822128,44.108722 z M 30.604855,25.673428 C 31.197837,25.590621 31.748164,25.999687 31.832637,26.587615 C 31.917946,27.174716 31.50311,27.720413 30.910128,27.804876 C 30.3138,27.887683 29.76431,27.476962 29.680673,26.890689 C 29.595365,26.301932 30.010201,25.756235 30.604855,25.673428 z M 24.950201,26.467545 C 25.542346,26.384739 26.09351,26.793805 26.177147,27.381734 C 26.262455,27.97049 25.847619,28.513703 25.255473,28.598995 C 24.659146,28.683458 24.109656,28.272735 24.026019,27.684807 C 23.941546,27.096049 24.353874,26.552009 24.950201,26.467545 z M 26.384565,35.548148 C 25.364201,34.827728 23.744165,32.814693 24.326273,31.447552 C 24.532019,30.966443 24.984492,31.265376 25.47711,31.509657 C 26.653037,32.10421 28.05311,32.180392 29.308492,31.805277 C 29.946637,31.614821 30.491946,31.305951 31.012165,30.893574 C 31.328309,30.641012 32.191437,29.636565 32.666491,30.090346 C 33.037837,30.445588 33.101401,30.886121 33.101401,30.890261 C 33.634164,34.258844 29.418891,37.688706 26.384565,35.548148 z"
id="cuerpo"
- style="fill:&stroke_color;fill-opacity:1;overflow:visible" />
+ d="M 38.822128,44.108722 C 38.822128,44.108722 38.445765,44.108722 38.092819,44.108722 C 38.092819,42.747378 38.097001,38.459638 38.097001,37.325183 C 38.097001,37.325183 38.097001,37.325183 38.097001,37.323527 L 38.097001,24.562988 L 38.089474,16.811436 C 38.086128,15.932855 37.361837,15.224857 36.48031,15.228997 C 36.052928,15.228997 35.648965,15.396267 35.347873,15.696856 C 35.045946,15.999101 34.882019,16.399058 34.883691,16.823857 C 34.883691,16.863604 34.885364,19.358576 34.887873,21.45773 L 22.071438,21.45773 C 20.330965,21.45773 18.920019,22.854682 18.920019,24.575409 L 18.920019,26.300276 L 13.265364,26.303588 C 12.377982,26.309384 11.663728,27.024008 11.667074,27.896793 C 11.668746,28.321592 11.837691,28.719892 12.141291,29.017998 C 12.446565,29.316931 12.850528,29.479232 13.277073,29.477576 C 13.326419,29.477576 16.696965,29.47592 18.919182,29.474263 L 18.919182,37.014658 C 18.919182,37.02625 18.915837,37.036187 18.915837,37.046952 C 18.915837,37.104917 18.919182,42.545329 18.919182,44.107894 C 18.567073,44.107894 18.189873,44.107894 18.189873,44.107894 C 17.285765,44.125284 16.584055,44.849844 16.59911,45.724285 C 16.61751,46.601209 17.351837,47.296787 18.234201,47.279397 L 20.537546,47.277741 C 21.439146,47.26118 22.145037,46.535792 22.126637,45.661352 L 22.123292,40.442034 L 34.887873,40.442034 L 34.882019,45.661352 C 34.865292,46.53662 35.571182,47.262009 36.472783,47.277741 L 38.774455,47.279397 C 39.661,47.296787 40.393656,46.601209 40.411219,45.724285 C 40.428782,44.849844 39.723728,44.126112 38.822128,44.108722 z M 30.604855,25.673428 C 31.197837,25.590621 31.748164,25.999687 31.832637,26.587615 C 31.917946,27.174716 31.50311,27.720413 30.910128,27.804876 C 30.3138,27.887683 29.76431,27.476962 29.680673,26.890689 C 29.595365,26.301932 30.010201,25.756235 30.604855,25.673428 z M 24.950201,26.467545 C 25.542346,26.384739 26.09351,26.793805 26.177147,27.381734 C 26.262455,27.97049 25.847619,28.513703 25.255473,28.598995 C 24.659146,28.683458 24.109656,28.272735 24.026019,27.684807 C 23.941546,27.096049 24.353874,26.552009 24.950201,26.467545 z M 26.384565,35.548148 C 25.364201,34.827728 23.744165,32.814693 24.326273,31.447552 C 24.532019,30.966443 24.984492,31.265376 25.47711,31.509657 C 26.653037,32.10421 28.05311,32.180392 29.308492,31.805277 C 29.946637,31.614821 30.491946,31.305951 31.012165,30.893574 C 31.328309,30.641012 32.191437,29.636565 32.666491,30.090346 C 33.037837,30.445588 33.101401,30.886121 33.101401,30.890261 C 33.634164,34.258844 29.418891,37.688706 26.384565,35.548148 z"
+ fill="&stroke_color;"/>
<path
- d="M 17.233073,11.642631 C 18.971874,8.6971904 24.424965,8.6756607 25.411873,12.233044 C 25.743073,13.428775 25.717147,16.000757 24.39151,16.697991 C 23.925655,16.943099 23.764237,16.42804 23.540092,15.929543 C 23.003146,14.736296 21.969401,13.79975 20.755837,13.307049 C 20.139437,13.055317 19.519691,12.950152 18.853946,12.946839 C 18.446637,12.943527 17.137728,13.184495 17.060783,12.532805 C 17.000564,12.027683 17.233073,11.644287 17.233073,11.642631 z"
id="pelo_oscuro"
- style="fill:&stroke_color;fill-opacity:1;overflow:visible" />
+ d="M 17.233073,11.642631 C 18.971874,8.6971904 24.424965,8.6756607 25.411873,12.233044 C 25.743073,13.428775 25.717147,16.000757 24.39151,16.697991 C 23.925655,16.943099 23.764237,16.42804 23.540092,15.929543 C 23.003146,14.736296 21.969401,13.79975 20.755837,13.307049 C 20.139437,13.055317 19.519691,12.950152 18.853946,12.946839 C 18.446637,12.943527 17.137728,13.184495 17.060783,12.532805 C 17.000564,12.027683 17.233073,11.644287 17.233073,11.642631 z"
+ fill="&stroke_color;"/>
<g
transform="matrix(0.8363636,0,0,0.8280687,4.3773279,7.643887)"
- id="pelo_claro"
- style="fill:&stroke_color;fill-opacity:1;overflow:visible">
+ id="pelo_claro">
<path
d="M 30.514,13.666 C 25.959,9.955 27.36,0.759 33.675,0.043 C 35.799,-0.198 40.171,0.537 41.006,2.954 C 41.299,3.802 40.382,3.936 39.473,4.18 C 37.299,4.765 35.434,6.261 34.273,8.172 C 33.681,9.144 33.342,10.161 33.16,11.281 C 33.047,11.964 33.108,14.236 31.982,14.194 C 31.107,14.162 30.516,13.668 30.514,13.666 z"
id="path2674"
- style="fill:&stroke_color;fill-opacity:1" />
+ fill="&stroke_color;"/>
</g>
</g>
</svg>
diff --git a/taller/BatallaNaval-1.py b/taller/BatallaNaval-1.py
new file mode 100644
index 0000000..7591e37
--- /dev/null
+++ b/taller/BatallaNaval-1.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+# -*- coding: cp1252 -*-
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import logging
+import random
+
+# Permite definir un Log que filtra mensajes a la salida estándar dependiendo de nivel elegido.
+log = logging.getLogger('BatallaNaval')
+log.setLevel(logging.DEBUG)
+
+# Diccionario que contiene el nombre y largo de cada barco
+lista_barcos = {
+ "Portaaviones": 5,
+ "Acorazado": 4,
+ "Crucero": 3,
+ "Submarino": 3,
+ "Destructor": 2}
+
+class PanelPrincipal():
+ ''' Panel Principal es un Widget que contiene ambos tableros y se encarga
+ de crear los barcos en posiciones al azar para cada tablero '''
+
+ def __init__(self):
+ self.tablero = Tablero()
+
+ log.debug("Carga barcos")
+ barcos = crear_barcos()
+ for barco in barcos:
+ self.tablero.agregar_barco(barco)
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
+
+ def mostrar_informacion(self):
+ for fila in self.tablero.filas:
+ print "-".join([str(celda.pos) for celda in fila])
+
+ print ""
+
+ print "barcos:"
+ for barco in self.tablero.barcos:
+ str_celdas = "-".join([str(celda) for celda in barco.get_celdas()])
+ print "%s : %s" % (barco.nombre, str_celdas)
+
+class Barco():
+ ''' Esta clase representa un barco, tiene nombre, largo, orientación y posición.
+ Como es un widget puede ser mostrado en la pantalla y tiene un texto con el nombre del barco '''
+
+ horizontal = 'H'
+ vertical = 'V'
+
+ def __init__(self, nombre, largo, pos, orientacion = horizontal):
+ self.nombre = nombre
+ self.largo = largo
+ self.pos = pos
+ self.orientacion = orientacion
+
+ def set_orientacion(self, orientacion):
+ ''' Graba la orientación '''
+
+ def get_inicio(self):
+ return self.pos
+
+ def get_fin(self):
+ if self.orientacion == Barco.horizontal:
+ return self.pos[0], self.pos[1] + self.largo - 1
+ else:
+ return self.pos[0] + self.largo - 1, self.pos[1]
+
+ def get_filas(self):
+ return range(self.get_inicio()[0], self.get_fin()[0]+1)
+
+ def get_cols(self):
+ return range(self.get_inicio()[1], self.get_fin()[1]+1)
+
+ def get_celdas(self):
+ return [(f, c) for f in self.get_filas() for c in self.get_cols()]
+
+def crear_barcos():
+ ''' Parte de la lista_barcos para crear un conjunto de barcos en posiciones al azar. '''
+
+ # Convierte la lista de definición en una lista de objetos Barco sin posición definida
+ barcos = [Barco(nombre, largo, None) for nombre, largo in lista_barcos.items()]
+
+ celdas_ocupadas = [] # Llevo una lista de las celdas ya ocupadas por los barcos
+
+ for barco in barcos:
+ # Para cada barco me mantengo en un loop hasta que encuentre coordenadas al azar que no
+ # intersecten con ningún barco ya ubicado.
+ ok = False
+ while not ok:
+ # Determino al azar si es horizontal o vertical
+ if random.randint(0, 1):
+ # Calculo coordenadas random - horizontal
+ barco.set_orientacion(Barco.horizontal)
+ posx = random.randint(1, 10)
+ posy = random.randint(1, 10-barco.largo+1)
+ else:
+ # Calculo coordenadas random - vertical
+ barco.set_orientacion(Barco.vertical)
+ posx = random.randint(1, 10-barco.largo+1)
+ posy = random.randint(1, 10)
+ barco.pos = (posx, posy)
+
+ # Verifico si la posición elegida no intersecciona con las celdas ya ocupadas por otros barcos
+ # Convierto las listas en sets y aplico intersección
+ interseccion = set(barco.get_celdas()) & set(celdas_ocupadas)
+ if not interseccion:
+ ok = True
+ celdas_ocupadas.extend(barco.get_celdas())
+ return barcos
+
+class Celda():
+ ''' Esta clase representa una celda del tablero. '''
+
+ def __init__(self, pos):
+ self.pos = pos
+
+class Tablero():
+ ''' Define un tablero con celdas y una función para agregar barcos '''
+
+ def __init__(self):
+
+ self.filas = []
+ # Creo todas las celdas, las guardo en la colección de filas y las adjunto al tablero
+ for i in range(1, 11):
+ fila = []
+ for j in range(1, 11):
+ celda = Celda((i, j))
+ fila.append(celda)
+ self.filas.append(fila)
+
+ # Los barcos que hay en el tablero
+ self.barcos = []
+
+ def agregar_barco(self, barco):
+ ''' Agrega un barco al tablero, si mostrar=True sustituye las celdas que ocupa por el barco. '''
+ self.barcos.append(barco)
+
+ def ocultar_celda(self, i, j):
+ self.filas[i-1][j-1].ocultar()
+
+def init():
+ panel_principal = PanelPrincipal()
+ panel_principal.mostrar_informacion()
+
+# Este código se ejecuta sólo cuando se ejecuta directo ese módulo (no cuando se importa desde sugar)
+if __name__ == "__main__":
+ log.addHandler(logging.StreamHandler())
+ init()
diff --git a/taller/BatallaNaval-2.py b/taller/BatallaNaval-2.py
new file mode 100644
index 0000000..365cfdc
--- /dev/null
+++ b/taller/BatallaNaval-2.py
@@ -0,0 +1,224 @@
+#!/usr/bin/env python
+# -*- coding: cp1252 -*-
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import logging
+import random
+
+# Permite definir un Log que filtra mensajes a la salida estándar dependiendo de nivel elegido.
+log = logging.getLogger('BatallaNaval')
+log.setLevel(logging.DEBUG)
+
+# Diccionario que contiene el nombre y largo de cada barco
+lista_barcos = {
+ "Portaaviones": 5,
+ "Acorazado": 4,
+ "Crucero": 3,
+ "Submarino": 3,
+ "Destructor": 2}
+
+class PanelPrincipal(gtk.HBox):
+ ''' Panel Principal es un Widget que contiene ambos tableros y se encarga
+ de crear los barcos en posiciones al azar para cada tablero '''
+
+ def __init__(self):
+ gtk.HBox.__init__(self, True)
+
+ self.tablero1 = Tablero() # tablero propio
+ self.tablero2 = Tablero() # tablero enemigo
+
+ log.debug("Barcos Propios")
+ barcos_propios = crear_barcos()
+ for barco in barcos_propios:
+ self.tablero1.agregar_barco(barco, True)
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
+
+ log.debug("Barcos Enemigos")
+ self.barcos_enemigos = crear_barcos()
+ for barco in self.barcos_enemigos:
+ self.tablero2.agregar_barco(barco, False)
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
+
+ self.add(self.tablero1)
+ self.add(self.tablero2)
+
+ self.show_all()
+
+class Barco(gtk.Frame):
+ ''' Esta clase representa un barco, tiene nombre, largo, orientación y posición.
+ Como es un widget puede ser mostrado en la pantalla y tiene un texto con el nombre del barco '''
+
+ horizontal = 'H'
+ vertical = 'V'
+
+ def __init__(self, nombre, largo, pos, orientacion = horizontal):
+ gtk.Frame.__init__(self)
+ self.nombre = nombre
+ self.largo = largo
+ self.pos = pos
+
+ # Agrega una etiqueta con el nombre del barco
+ self.label = gtk.Label(nombre)
+ self.add(self.label)
+
+ self.set_orientacion(orientacion) # Graba la orientación y ajusta la etiqueta a dicha orientación.
+
+ def set_orientacion(self, orientacion):
+ ''' Graba la orientación y ajusta la etiqueta a dicha orientación. '''
+ self.orientacion = orientacion
+ if self.orientacion == Barco.horizontal:
+ self.label.set_angle(0)
+ else:
+ self.label.set_angle(90)
+
+ def get_inicio(self):
+ return self.pos
+
+ def get_fin(self):
+ if self.orientacion == Barco.horizontal:
+ return self.pos[0], self.pos[1] + self.largo - 1
+ else:
+ return self.pos[0] + self.largo - 1, self.pos[1]
+
+ def get_filas(self):
+ return range(self.get_inicio()[0], self.get_fin()[0]+1)
+
+ def get_cols(self):
+ return range(self.get_inicio()[1], self.get_fin()[1]+1)
+
+ def get_celdas(self):
+ return [(f, c) for f in self.get_filas() for c in self.get_cols()]
+
+def crear_barcos():
+ ''' Parte de la lista_barcos para crear un conjunto de barcos en posiciones al azar. '''
+
+ # Convierte la lista de definición en una lista de objetos Barco sin posición definida
+ barcos = [Barco(nombre, largo, None) for nombre, largo in lista_barcos.items()]
+
+ celdas_ocupadas = [] # Llevo una lista de las celdas ya ocupadas por los barcos
+
+ for barco in barcos:
+ # Para cada barco me mantengo en un loop hasta que encuentre coordenadas al azar que no
+ # intersecten con ningún barco ya ubicado.
+ ok = False
+ while not ok:
+ # Determino al azar si es horizontal o vertical
+ if random.randint(0, 1):
+ # Calculo coordenadas random - horizontal
+ barco.set_orientacion(Barco.horizontal)
+ posx = random.randint(1, 10)
+ posy = random.randint(1, 10-barco.largo+1)
+ else:
+ # Calculo coordenadas random - vertical
+ barco.set_orientacion(Barco.vertical)
+ posx = random.randint(1, 10-barco.largo+1)
+ posy = random.randint(1, 10)
+ barco.pos = (posx, posy)
+
+ # Verifico si la posición elegida no intersecciona con las celdas ya ocupadas por otros barcos
+ # Convierto las listas en sets y aplico intersección
+ interseccion = set(barco.get_celdas()) & set(celdas_ocupadas)
+ if not interseccion:
+ ok = True
+ celdas_ocupadas.extend(barco.get_celdas())
+ return barcos
+
+class Celda(gtk.Button):
+ ''' Esta clase representa una celda del tablero. '''
+
+ def __init__(self, pos):
+ gtk.Button.__init__(self)
+ self.pos = pos
+
+ def ocultar(self):
+ ''' Oculta permanentemente la celda, de modo que show_all no la muestre '''
+ self.set_no_show_all(True)
+ self.hide()
+
+
+class Tablero(gtk.Frame):
+ ''' Define un tablero, el tablero está definido con una tabla exterior que permite poner
+ los títulos de las filas y las columnas (que a su vez son tablas) y una tabla interior
+ que tiene todas las celdas del tablero (tabla_celdas). '''
+
+ def __init__(self):
+ gtk.Frame.__init__(self)
+
+ # Números
+ tabla_numeros = gtk.Table(1, 10, True)
+ for i in range(1, 11):
+ label = gtk.Label(str(i))
+ tabla_numeros.attach(label, i-1, i, 0, 1)
+
+ # Letras
+ tabla_letras = gtk.Table(10, 1, True)
+ for i in range(1, 11):
+ char = chr( ord('A') + i - 1 )
+ label = gtk.Label(char)
+ tabla_letras.attach(label, 0, 1, i-1, i)
+
+ # Se hace una tabla para ubicar las letras, los números y la tabla de celdas
+ self.tabla = gtk.Table(2, 2, False)
+ self.add(self.tabla)
+
+ # Opciones para las tablas de letras y números.
+ opciones = gtk.SHRINK|gtk.FILL
+
+ label = gtk.Label(" ") # Para dar más espacio a la columna de letras
+ self.tabla.attach(label, 0, 1, 0, 1, xoptions=opciones, yoptions=opciones)
+ self.tabla.attach(tabla_numeros, 1, 2, 0, 1, xoptions=opciones, yoptions=opciones)
+ self.tabla.attach(tabla_letras, 0, 1, 1, 2, xoptions=opciones, yoptions=opciones)
+
+ # El tablero es otra tabla
+ self.tabla_celdas = gtk.Table(10, 10, True)
+ self.tabla.attach(self.tabla_celdas, 1, 2, 1, 2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL|gtk.EXPAND)
+
+ self.filas = []
+ # Creo todas las celdas, las guardo en la colección de filas y las adjunto al tablero
+ for i in range(1, 11):
+ fila = []
+ for j in range(1, 11):
+ celda = Celda((i, j))
+ fila.append(celda)
+ self.tabla_celdas.attach(celda, j-1, j, i-1, i)
+ self.filas.append(fila)
+
+ # Los barcos que hay en el tablero
+ self.barcos = []
+
+ def agregar_barco(self, barco, mostrar):
+ ''' Agrega un barco al tablero, si mostrar=True sustituye las celdas que ocupa por el barco. '''
+ self.barcos.append(barco)
+ if mostrar:
+ # Oculta las celdas que ocupa el barco
+ for i, j in barco.get_celdas():
+ self.ocultar_celda(i, j)
+
+ # Obtiene los extremos del barco y lo adjunta a la tabla
+ arr, izq = barco.get_inicio()
+ aba, der = barco.get_fin()
+ self.tabla_celdas.attach(barco, izq-1, der, arr-1, aba)
+
+ def ocultar_celda(self, i, j):
+ self.filas[i-1][j-1].ocultar()
+
+def init(ventana_principal):
+ ''' Esta función es el punto de entrada común para sugar y modo standalone
+ standalone es un boolean que indica si es Standalone o se ejecuta desde Sugar '''
+ panel_principal = PanelPrincipal()
+ ventana_principal.add(panel_principal)
+
+ ventana_principal.set_title("Batalla Naval - ceibalJAM")
+ ventana_principal.connect("destroy", lambda wid: gtk.main_quit())
+ ventana_principal.connect("delete_event", lambda a1, a2: gtk.main_quit())
+
+ ventana_principal.show()
+
+# Este código se ejecuta sólo cuando se ejecuta directo ese módulo (no cuando se importa desde sugar)
+if __name__ == "__main__":
+ log.addHandler(logging.StreamHandler())
+ ventana_principal = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ init(ventana_principal)
+ gtk.main()
diff --git a/taller/BatallaNaval-3.py b/taller/BatallaNaval-3.py
new file mode 100644
index 0000000..776a766
--- /dev/null
+++ b/taller/BatallaNaval-3.py
@@ -0,0 +1,228 @@
+#!/usr/bin/env python
+# -*- coding: cp1252 -*-
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import logging
+import random
+
+# Permite definir un Log que filtra mensajes a la salida estándar dependiendo de nivel elegido.
+log = logging.getLogger('BatallaNaval')
+log.setLevel(logging.DEBUG)
+
+# Diccionario que contiene el nombre y largo de cada barco
+lista_barcos = {
+ "Portaaviones": 5,
+ "Acorazado": 4,
+ "Crucero": 3,
+ "Submarino": 3,
+ "Destructor": 2}
+
+class PanelPrincipal(gtk.HBox):
+ ''' Panel Principal es un Widget que contiene ambos tableros y se encarga
+ de crear los barcos en posiciones al azar para cada tablero '''
+
+ def __init__(self):
+ gtk.HBox.__init__(self, True)
+
+ self.tablero1 = Tablero() # tablero propio
+ self.tablero2 = Tablero() # tablero enemigo
+
+ log.debug("Barcos Propios")
+ barcos_propios = crear_barcos()
+ for barco in barcos_propios:
+ self.tablero1.agregar_barco(barco, True)
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
+
+ log.debug("Barcos Enemigos")
+ self.barcos_enemigos = crear_barcos()
+ for barco in self.barcos_enemigos:
+ self.tablero2.agregar_barco(barco, False)
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
+
+ self.add(self.tablero1)
+ self.add(self.tablero2)
+
+ self.show_all()
+
+class Barco(gtk.Frame):
+ ''' Esta clase representa un barco, tiene nombre, largo, orientación y posición.
+ Como es un widget puede ser mostrado en la pantalla y tiene un texto con el nombre del barco '''
+
+ horizontal = 'H'
+ vertical = 'V'
+
+ def __init__(self, nombre, largo, pos, orientacion = horizontal):
+ gtk.Frame.__init__(self)
+ self.nombre = nombre
+ self.largo = largo
+ self.pos = pos
+
+ # Agrega una etiqueta con el nombre del barco
+ self.label = gtk.Label(nombre)
+ self.add(self.label)
+
+ self.set_orientacion(orientacion) # Graba la orientación y ajusta la etiqueta a dicha orientación.
+
+ def set_orientacion(self, orientacion):
+ ''' Graba la orientación y ajusta la etiqueta a dicha orientación. '''
+ self.orientacion = orientacion
+ if self.orientacion == Barco.horizontal:
+ self.label.set_angle(0)
+ else:
+ self.label.set_angle(90)
+
+ def get_inicio(self):
+ return self.pos
+
+ def get_fin(self):
+ if self.orientacion == Barco.horizontal:
+ return self.pos[0], self.pos[1] + self.largo - 1
+ else:
+ return self.pos[0] + self.largo - 1, self.pos[1]
+
+ def get_filas(self):
+ return range(self.get_inicio()[0], self.get_fin()[0]+1)
+
+ def get_cols(self):
+ return range(self.get_inicio()[1], self.get_fin()[1]+1)
+
+ def get_celdas(self):
+ return [(f, c) for f in self.get_filas() for c in self.get_cols()]
+
+def crear_barcos():
+ ''' Parte de la lista_barcos para crear un conjunto de barcos en posiciones al azar. '''
+
+ # Convierte la lista de definición en una lista de objetos Barco sin posición definida
+ barcos = [Barco(nombre, largo, None) for nombre, largo in lista_barcos.items()]
+
+ celdas_ocupadas = [] # Llevo una lista de las celdas ya ocupadas por los barcos
+
+ for barco in barcos:
+ # Para cada barco me mantengo en un loop hasta que encuentre coordenadas al azar que no
+ # intersecten con ningún barco ya ubicado.
+ ok = False
+ while not ok:
+ # Determino al azar si es horizontal o vertical
+ if random.randint(0, 1):
+ # Calculo coordenadas random - horizontal
+ barco.set_orientacion(Barco.horizontal)
+ posx = random.randint(1, 10)
+ posy = random.randint(1, 10-barco.largo+1)
+ else:
+ # Calculo coordenadas random - vertical
+ barco.set_orientacion(Barco.vertical)
+ posx = random.randint(1, 10-barco.largo+1)
+ posy = random.randint(1, 10)
+ barco.pos = (posx, posy)
+
+ # Verifico si la posición elegida no intersecciona con las celdas ya ocupadas por otros barcos
+ # Convierto las listas en sets y aplico intersección
+ interseccion = set(barco.get_celdas()) & set(celdas_ocupadas)
+ if not interseccion:
+ ok = True
+ celdas_ocupadas.extend(barco.get_celdas())
+ return barcos
+
+class Celda(gtk.Button):
+ ''' Esta clase representa una celda del tablero. '''
+
+ def __init__(self, pos):
+ gtk.Button.__init__(self)
+ self.pos = pos
+
+ def ocultar(self):
+ ''' Oculta permanentemente la celda, de modo que show_all no la muestre '''
+ self.set_no_show_all(True)
+ self.hide()
+
+
+class Tablero(gtk.Frame):
+ ''' Define un tablero, el tablero está definido con una tabla exterior que permite poner
+ los títulos de las filas y las columnas (que a su vez son tablas) y una tabla interior
+ que tiene todas las celdas del tablero (tabla_celdas). '''
+
+ def __init__(self):
+ gtk.Frame.__init__(self)
+
+ # Números
+ tabla_numeros = gtk.Table(1, 10, True)
+ for i in range(1, 11):
+ label = gtk.Label(str(i))
+ tabla_numeros.attach(label, i-1, i, 0, 1)
+
+ # Letras
+ tabla_letras = gtk.Table(10, 1, True)
+ for i in range(1, 11):
+ char = chr( ord('A') + i - 1 )
+ label = gtk.Label(char)
+ tabla_letras.attach(label, 0, 1, i-1, i)
+
+ # Se hace una tabla para ubicar las letras, los números y la tabla de celdas
+ self.tabla = gtk.Table(2, 2, False)
+ self.add(self.tabla)
+
+ # Opciones para las tablas de letras y números.
+ opciones = gtk.SHRINK|gtk.FILL
+
+ label = gtk.Label(" ") # Para dar más espacio a la columna de letras
+ self.tabla.attach(label, 0, 1, 0, 1, xoptions=opciones, yoptions=opciones)
+ self.tabla.attach(tabla_numeros, 1, 2, 0, 1, xoptions=opciones, yoptions=opciones)
+ self.tabla.attach(tabla_letras, 0, 1, 1, 2, xoptions=opciones, yoptions=opciones)
+
+ # El tablero es otra tabla
+ self.tabla_celdas = gtk.Table(10, 10, True)
+ self.tabla.attach(self.tabla_celdas, 1, 2, 1, 2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL|gtk.EXPAND)
+
+ self.filas = []
+ # Creo todas las celdas, las guardo en la colección de filas y las adjunto al tablero
+ for i in range(1, 11):
+ fila = []
+ for j in range(1, 11):
+ celda = Celda((i, j))
+ fila.append(celda)
+ self.tabla_celdas.attach(celda, j-1, j, i-1, i)
+ self.filas.append(fila)
+
+ # Los barcos que hay en el tablero
+ self.barcos = []
+
+ def agregar_barco(self, barco, mostrar):
+ ''' Agrega un barco al tablero, si mostrar=True sustituye las celdas que ocupa por el barco. '''
+ self.barcos.append(barco)
+ if mostrar:
+ # Oculta las celdas que ocupa el barco
+ for i, j in barco.get_celdas():
+ self.ocultar_celda(i, j)
+
+ # Obtiene los extremos del barco y lo adjunta a la tabla
+ arr, izq = barco.get_inicio()
+ aba, der = barco.get_fin()
+ self.tabla_celdas.attach(barco, izq-1, der, arr-1, aba)
+
+ def ocultar_celda(self, i, j):
+ self.filas[i-1][j-1].ocultar()
+
+def init(standalone, ventana_principal):
+ ''' Esta función es el punto de entrada común para sugar y modo standalone
+ standalone es un boolean que indica si es Standalone o se ejecuta desde Sugar '''
+ panel_principal = PanelPrincipal()
+
+ if not standalone:
+ ventana_principal.set_canvas(panel_principal)
+ else:
+ ventana_principal.add(panel_principal)
+
+ ventana_principal.set_title("Batalla Naval - ceibalJAM")
+ ventana_principal.connect("destroy", lambda wid: gtk.main_quit())
+ ventana_principal.connect("delete_event", lambda a1, a2: gtk.main_quit())
+
+ ventana_principal.show()
+
+# Este código se ejecuta sólo cuando se ejecuta directo ese módulo (no cuando se importa desde sugar)
+if __name__ == "__main__":
+ log.addHandler(logging.StreamHandler())
+ ventana_principal = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ init(True, ventana_principal)
+ gtk.main()
diff --git a/taller/BatallaNaval-4.py b/taller/BatallaNaval-4.py
new file mode 100644
index 0000000..a3b5a83
--- /dev/null
+++ b/taller/BatallaNaval-4.py
@@ -0,0 +1,284 @@
+#!/usr/bin/env python
+# -*- coding: cp1252 -*-
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import logging
+import random
+
+# Permite definir un Log que filtra mensajes a la salida estándar dependiendo de nivel elegido.
+log = logging.getLogger('BatallaNaval')
+log.setLevel(logging.DEBUG)
+
+# Diccionario que contiene el nombre y largo de cada barco
+lista_barcos = {
+ "Portaaviones": 5,
+ "Acorazado": 4,
+ "Crucero": 3,
+ "Submarino": 3,
+ "Destructor": 2}
+
+class PanelPrincipal(gtk.HBox):
+ ''' Panel Principal es un Widget que contiene ambos tableros y se encarga
+ de crear los barcos en posiciones al azar para cada tablero '''
+
+ def __init__(self):
+ gtk.HBox.__init__(self, True)
+
+ self.tablero1 = Tablero(None) # tablero propio
+ self.tablero2 = Tablero(self.jugada_hecha) # tablero enemigo
+
+ log.debug("Barcos Propios")
+ barcos_propios = crear_barcos()
+ for barco in barcos_propios:
+ self.tablero1.agregar_barco(barco, True)
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
+
+ log.debug("Barcos Enemigos")
+ self.barcos_enemigos = crear_barcos()
+ for barco in self.barcos_enemigos:
+ self.tablero2.agregar_barco(barco, False)
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
+
+ self.add(self.tablero1)
+ self.add(self.tablero2)
+
+ self.jugadas_enemigas = [] # Lleva un registro de las jugadas hechas por la computadora
+
+ self.show_all()
+
+ def jugada_hecha(self, x, y):
+ ''' Cuando hice una jugada sobre el tablero enemigo, simulo una jugada random del enemigo. '''
+
+ if len(self.jugadas_enemigas) == 100:
+ log.error("Alcanzó las 100 jugadas.")
+ return
+
+ ok = False
+ while not ok:
+ x, y = random.randint(1, 10), random.randint(1, 10)
+ if not (x, y) in self.jugadas_enemigas:
+ ok = True
+
+ self.jugadas_enemigas.append((x, y))
+ self.tablero1.jugada(self.tablero1.filas[x-1][y-1])
+
+class Barco(gtk.Frame):
+ ''' Esta clase representa un barco, tiene nombre, largo, orientación y posición.
+ Como es un widget puede ser mostrado en la pantalla y tiene un texto con el nombre del barco '''
+
+ horizontal = 'H'
+ vertical = 'V'
+
+ def __init__(self, nombre, largo, pos, orientacion = horizontal):
+ gtk.Frame.__init__(self)
+ self.nombre = nombre
+ self.largo = largo
+ self.pos = pos
+
+ # Agrega una etiqueta con el nombre del barco
+ self.label = gtk.Label(nombre)
+ self.add(self.label)
+
+ self.set_orientacion(orientacion) # Graba la orientación y ajusta la etiqueta a dicha orientación.
+
+ def set_orientacion(self, orientacion):
+ ''' Graba la orientación y ajusta la etiqueta a dicha orientación. '''
+ self.orientacion = orientacion
+ if self.orientacion == Barco.horizontal:
+ self.label.set_angle(0)
+ else:
+ self.label.set_angle(90)
+
+ def get_inicio(self):
+ return self.pos
+
+ def get_fin(self):
+ if self.orientacion == Barco.horizontal:
+ return self.pos[0], self.pos[1] + self.largo - 1
+ else:
+ return self.pos[0] + self.largo - 1, self.pos[1]
+
+ def get_filas(self):
+ return range(self.get_inicio()[0], self.get_fin()[0]+1)
+
+ def get_cols(self):
+ return range(self.get_inicio()[1], self.get_fin()[1]+1)
+
+ def get_celdas(self):
+ return [(f, c) for f in self.get_filas() for c in self.get_cols()]
+
+def crear_barcos():
+ ''' Parte de la lista_barcos para crear un conjunto de barcos en posiciones al azar. '''
+
+ # Convierte la lista de definición en una lista de objetos Barco sin posición definida
+ barcos = [Barco(nombre, largo, None) for nombre, largo in lista_barcos.items()]
+
+ celdas_ocupadas = [] # Llevo una lista de las celdas ya ocupadas por los barcos
+
+ for barco in barcos:
+ # Para cada barco me mantengo en un loop hasta que encuentre coordenadas al azar que no
+ # intersecten con ningún barco ya ubicado.
+ ok = False
+ while not ok:
+ # Determino al azar si es horizontal o vertical
+ if random.randint(0, 1):
+ # Calculo coordenadas random - horizontal
+ barco.set_orientacion(Barco.horizontal)
+ posx = random.randint(1, 10)
+ posy = random.randint(1, 10-barco.largo+1)
+ else:
+ # Calculo coordenadas random - vertical
+ barco.set_orientacion(Barco.vertical)
+ posx = random.randint(1, 10-barco.largo+1)
+ posy = random.randint(1, 10)
+ barco.pos = (posx, posy)
+
+ # Verifico si la posición elegida no intersecciona con las celdas ya ocupadas por otros barcos
+ # Convierto las listas en sets y aplico intersección
+ interseccion = set(barco.get_celdas()) & set(celdas_ocupadas)
+ if not interseccion:
+ ok = True
+ celdas_ocupadas.extend(barco.get_celdas())
+ return barcos
+
+class Celda(gtk.Button):
+ ''' Esta clase representa una celda del tablero, como es subclase de button se le puede
+ conectar la señal "clicked".
+ También presenta funciones para ocultar y colorearse dependiendo de si tocó un barco o dió agua. '''
+
+ def __init__(self, pos):
+ gtk.Button.__init__(self)
+ self.pos = pos
+
+ def ocultar(self):
+ ''' Oculta permanentemente la celda, de modo que show_all no la muestre '''
+ self.set_no_show_all(True)
+ self.hide()
+
+ def colorear(self, color):
+ self.modify_bg(gtk.STATE_NORMAL, color)
+ self.modify_bg(gtk.STATE_PRELIGHT, color)
+ self.show() # Por si está oculta atrás de un barco
+
+ def tocado(self):
+ self.colorear( gtk.gdk.Color(65535,65535/2,0) )
+
+ def agua(self):
+ self.colorear( gtk.gdk.Color(0,0,65535/2) )
+
+
+class Tablero(gtk.Frame):
+ ''' Define un tablero, el tablero está definido con una tabla exterior que permite poner
+ los títulos de las filas y las columnas (que a su vez son tablas) y una tabla interior
+ que tiene todas las celdas del tablero (tabla_celdas). '''
+
+ def __init__(self, llamada_jugada_hecha):
+ gtk.Frame.__init__(self)
+
+ # Números
+ tabla_numeros = gtk.Table(1, 10, True)
+ for i in range(1, 11):
+ label = gtk.Label(str(i))
+ tabla_numeros.attach(label, i-1, i, 0, 1)
+
+ # Letras
+ tabla_letras = gtk.Table(10, 1, True)
+ for i in range(1, 11):
+ char = chr( ord('A') + i - 1 )
+ label = gtk.Label(char)
+ tabla_letras.attach(label, 0, 1, i-1, i)
+
+ # Se hace una tabla para ubicar las letras, los números y la tabla de celdas
+ self.tabla = gtk.Table(2, 2, False)
+ self.add(self.tabla)
+
+ # Opciones para las tablas de letras y números.
+ opciones = gtk.SHRINK|gtk.FILL
+
+ label = gtk.Label(" ") # Para dar más espacio a la columna de letras
+ self.tabla.attach(label, 0, 1, 0, 1, xoptions=opciones, yoptions=opciones)
+ self.tabla.attach(tabla_numeros, 1, 2, 0, 1, xoptions=opciones, yoptions=opciones)
+ self.tabla.attach(tabla_letras, 0, 1, 1, 2, xoptions=opciones, yoptions=opciones)
+
+ # El tablero es otra tabla
+ self.tabla_celdas = gtk.Table(10, 10, True)
+ self.tabla.attach(self.tabla_celdas, 1, 2, 1, 2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL|gtk.EXPAND)
+
+ self.filas = []
+ # Creo todas las celdas, las guardo en la colección de filas y las adjunto al tablero
+ for i in range(1, 11):
+ fila = []
+ for j in range(1, 11):
+ celda = Celda((i, j))
+ celda.connect("clicked", self.celda_clickeada)
+ fila.append(celda)
+ self.tabla_celdas.attach(celda, j-1, j, i-1, i)
+ self.filas.append(fila)
+
+ # Los barcos que hay en el tablero
+ self.barcos = []
+
+ # Callback para cuando el jugador hace una jugada en el tablero
+ self.llamada_jugada_hecha = llamada_jugada_hecha
+
+ def agregar_barco(self, barco, mostrar):
+ ''' Agrega un barco al tablero, si mostrar=True sustituye las celdas que ocupa por el barco. '''
+ self.barcos.append(barco)
+ if mostrar:
+ # Oculta las celdas que ocupa el barco
+ for i, j in barco.get_celdas():
+ self.ocultar_celda(i, j)
+
+ # Obtiene los extremos del barco y lo adjunta a la tabla
+ arr, izq = barco.get_inicio()
+ aba, der = barco.get_fin()
+ self.tabla_celdas.attach(barco, izq-1, der, arr-1, aba)
+
+ def ocultar_celda(self, i, j):
+ self.filas[i-1][j-1].ocultar()
+
+ def celda_clickeada(self, celda):
+ ''' Cuando hay definido un callback de jugadas hechas, significa que en este tablero puedo jugar.
+ Realizo la jugada y notifico al callback '''
+ if self.llamada_jugada_hecha:
+ # Este es el callback para cuando clickean una celda
+ self.jugada(celda)
+ self.llamada_jugada_hecha(celda.pos[0], celda.pos[1])
+
+ def jugada(self, celda):
+ ''' verifica si la jugada da en algún barco o en el agua y manda la señal correcta a la celda '''
+ tocado = False
+ for barco in self.barcos:
+ if celda.pos in barco.get_celdas():
+ tocado = True
+ celda.tocado()
+ if not tocado:
+ celda.agua()
+
+ log.debug("Pos:%s Tocado:%s", str(celda.pos), tocado)
+ return tocado
+
+def init(standalone, ventana_principal):
+ ''' Esta función es el punto de entrada común para sugar y modo standalone
+ standalone es un boolean que indica si es Standalone o se ejecuta desde Sugar '''
+ panel_principal = PanelPrincipal()
+
+ if not standalone:
+ ventana_principal.set_canvas(panel_principal)
+ else:
+ ventana_principal.add(panel_principal)
+
+ ventana_principal.set_title("Batalla Naval - ceibalJAM")
+ ventana_principal.connect("destroy", lambda wid: gtk.main_quit())
+ ventana_principal.connect("delete_event", lambda a1, a2: gtk.main_quit())
+
+ ventana_principal.show()
+
+# Este código se ejecuta sólo cuando se ejecuta directo ese módulo (no cuando se importa desde sugar)
+if __name__ == "__main__":
+ log.addHandler(logging.StreamHandler())
+ ventana_principal = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ init(True, ventana_principal)
+ gtk.main()
diff --git a/taller/BatallaNaval-5.py b/taller/BatallaNaval-5.py
new file mode 100644
index 0000000..ea99a1d
--- /dev/null
+++ b/taller/BatallaNaval-5.py
@@ -0,0 +1,325 @@
+#!/usr/bin/env python
+# -*- coding: cp1252 -*-
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import logging
+import random
+
+# Permite definir un Log que filtra mensajes a la salida estándar dependiendo de nivel elegido.
+log = logging.getLogger('BatallaNaval')
+log.setLevel(logging.DEBUG)
+
+# Diccionario que contiene el nombre y largo de cada barco
+lista_barcos = {
+ "Portaaviones": 5,
+ "Acorazado": 4,
+ "Crucero": 3,
+ "Submarino": 3,
+ "Destructor": 2}
+
+class PanelPrincipal(gtk.HBox):
+ ''' Panel Principal es un Widget que contiene ambos tableros y se encarga
+ de crear los barcos en posiciones al azar para cada tablero '''
+
+ def __init__(self):
+ gtk.HBox.__init__(self, True)
+
+ self.tablero1 = Tablero(None) # tablero propio
+ self.tablero2 = Tablero(self.jugada_hecha) # tablero enemigo
+
+ log.debug("Barcos Propios")
+ barcos_propios = crear_barcos()
+ for barco in barcos_propios:
+ self.tablero1.agregar_barco(barco, True)
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
+
+ log.debug("Barcos Enemigos")
+ self.barcos_enemigos = crear_barcos()
+ for barco in self.barcos_enemigos:
+ self.tablero2.agregar_barco(barco, False)
+ log.debug("barco:%s, %s (%s, %s)" % (barco.nombre, barco.orientacion, barco.pos[0], barco.pos[1]))
+
+ self.add(self.tablero1)
+ self.add(self.tablero2)
+
+ self.jugadas_enemigas = [] # Lleva un registro de las jugadas hechas por la computadora
+
+ self.show_all()
+
+ # Carga barcos remotos
+ def cargar_barcos(self, barcos):
+ ''' Esta función es llamada cuando me conecto en red con otro usuario, recibo
+ una tupla con los datos de los barcos enemigos. '''
+ log.debug("Cargando barcos enemigos")
+ self.tablero2.barcos = []
+ for dato in barcos:
+ log.debug("Dato: %s" % str(dato))
+ nombre = dato[0]
+ orientacion = dato[1]
+ largo = dato[2]
+ pos = dato[3:5]
+
+ barco = Barco(nombre, largo, pos, orientacion)
+ self.tablero2.agregar_barco(barco, False)
+ log.debug("barco:%s, %s (%s, %s)" % (barco.name, barco.orientacion, barco.pos[0], barco.pos[1]))
+
+ def jugada_red(self, x, y):
+ ''' Callback de colaboración para la señal Play.
+ Cuando el enemigo juega sobre mi tablero, reflejo la judada y le respondo si fue tocado '''
+ return self.tablero1.jugada(self.tablero1.filas[x-1][y-1])
+
+ def jugada_hecha(self, x, y):
+ ''' Cuando yo mismo hice una jugada sobre el tablero enemigo
+ si la actividad está compartida indico al oponente la jugada que hice,
+ en caso contrario me simulo una jugada random del enemigo. '''
+
+ # Si estoy compartiendo con alguien, indico al oponente la jugada que hice
+ if self.colaboracion and self.colaboracion.entered:
+ log.debug("Señalo jugada a los participantes")
+ self.colaboracion.Play(x, y)
+ return
+
+ # Sinó, la computadora hace una jugada al azar sobre el tablero propio
+ if len(self.jugadas_enemigas) == 100:
+ log.error("Alcanzó las 100 jugadas.")
+ return
+
+ ok = False
+ while not ok:
+ x, y = random.randint(1, 10), random.randint(1, 10)
+ if not (x, y) in self.jugadas_enemigas:
+ ok = True
+
+ self.jugadas_enemigas.append((x, y))
+ self.tablero1.jugada(self.tablero1.filas[x-1][y-1])
+
+class Barco(gtk.Frame):
+ ''' Esta clase representa un barco, tiene nombre, largo, orientación y posición.
+ Como es un widget puede ser mostrado en la pantalla y tiene un texto con el nombre del barco '''
+
+ horizontal = 'H'
+ vertical = 'V'
+
+ def __init__(self, nombre, largo, pos, orientacion = horizontal):
+ gtk.Frame.__init__(self)
+ self.nombre = nombre
+ self.largo = largo
+ self.pos = pos
+
+ # Agrega una etiqueta con el nombre del barco
+ self.label = gtk.Label(nombre)
+ self.add(self.label)
+
+ self.set_orientacion(orientacion) # Graba la orientación y ajusta la etiqueta a dicha orientación.
+
+ def set_orientacion(self, orientacion):
+ ''' Graba la orientación y ajusta la etiqueta a dicha orientación. '''
+ self.orientacion = orientacion
+ if self.orientacion == Barco.horizontal:
+ self.label.set_angle(0)
+ else:
+ self.label.set_angle(90)
+
+ def get_inicio(self):
+ return self.pos
+
+ def get_fin(self):
+ if self.orientacion == Barco.horizontal:
+ return self.pos[0], self.pos[1] + self.largo - 1
+ else:
+ return self.pos[0] + self.largo - 1, self.pos[1]
+
+ def get_filas(self):
+ return range(self.get_inicio()[0], self.get_fin()[0]+1)
+
+ def get_cols(self):
+ return range(self.get_inicio()[1], self.get_fin()[1]+1)
+
+ def get_celdas(self):
+ return [(f, c) for f in self.get_filas() for c in self.get_cols()]
+
+def crear_barcos():
+ ''' Parte de la lista_barcos para crear un conjunto de barcos en posiciones al azar. '''
+
+ # Convierte la lista de definición en una lista de objetos Barco sin posición definida
+ barcos = [Barco(nombre, largo, None) for nombre, largo in lista_barcos.items()]
+
+ celdas_ocupadas = [] # Llevo una lista de las celdas ya ocupadas por los barcos
+
+ for barco in barcos:
+ # Para cada barco me mantengo en un loop hasta que encuentre coordenadas al azar que no
+ # intersecten con ningún barco ya ubicado.
+ ok = False
+ while not ok:
+ # Determino al azar si es horizontal o vertical
+ if random.randint(0, 1):
+ # Calculo coordenadas random - horizontal
+ barco.set_orientacion(Barco.horizontal)
+ posx = random.randint(1, 10)
+ posy = random.randint(1, 10-barco.largo+1)
+ else:
+ # Calculo coordenadas random - vertical
+ barco.set_orientacion(Barco.vertical)
+ posx = random.randint(1, 10-barco.largo+1)
+ posy = random.randint(1, 10)
+ barco.pos = (posx, posy)
+
+ # Verifico si la posición elegida no intersecciona con las celdas ya ocupadas por otros barcos
+ # Convierto las listas en sets y aplico intersección
+ interseccion = set(barco.get_celdas()) & set(celdas_ocupadas)
+ if not interseccion:
+ ok = True
+ celdas_ocupadas.extend(barco.get_celdas())
+ return barcos
+
+class Celda(gtk.Button):
+ ''' Esta clase representa una celda del tablero, como es subclase de button se le puede
+ conectar la señal "clicked".
+ También presenta funciones para ocultar y colorearse dependiendo de si tocó un barco o dió agua. '''
+
+ def __init__(self, pos):
+ gtk.Button.__init__(self)
+ self.pos = pos
+
+ def ocultar(self):
+ ''' Oculta permanentemente la celda, de modo que show_all no la muestre '''
+ self.set_no_show_all(True)
+ self.hide()
+
+ def colorear(self, color):
+ self.modify_bg(gtk.STATE_NORMAL, color)
+ self.modify_bg(gtk.STATE_PRELIGHT, color)
+ self.show() # Por si está oculta atrás de un barco
+
+ def tocado(self):
+ self.colorear( gtk.gdk.Color(65535,65535/2,0) )
+
+ def agua(self):
+ self.colorear( gtk.gdk.Color(0,0,65535/2) )
+
+
+class Tablero(gtk.Frame):
+ ''' Define un tablero, el tablero está definido con una tabla exterior que permite poner
+ los títulos de las filas y las columnas (que a su vez son tablas) y una tabla interior
+ que tiene todas las celdas del tablero (tabla_celdas). '''
+
+ def __init__(self, llamada_jugada_hecha):
+ gtk.Frame.__init__(self)
+
+ # Números
+ tabla_numeros = gtk.Table(1, 10, True)
+ for i in range(1, 11):
+ label = gtk.Label(str(i))
+ tabla_numeros.attach(label, i-1, i, 0, 1)
+
+ # Letras
+ tabla_letras = gtk.Table(10, 1, True)
+ for i in range(1, 11):
+ char = chr( ord('A') + i - 1 )
+ label = gtk.Label(char)
+ tabla_letras.attach(label, 0, 1, i-1, i)
+
+ # Se hace una tabla para ubicar las letras, los números y la tabla de celdas
+ self.tabla = gtk.Table(2, 2, False)
+ self.add(self.tabla)
+
+ # Opciones para las tablas de letras y números.
+ opciones = gtk.SHRINK|gtk.FILL
+
+ label = gtk.Label(" ") # Para dar más espacio a la columna de letras
+ self.tabla.attach(label, 0, 1, 0, 1, xoptions=opciones, yoptions=opciones)
+ self.tabla.attach(tabla_numeros, 1, 2, 0, 1, xoptions=opciones, yoptions=opciones)
+ self.tabla.attach(tabla_letras, 0, 1, 1, 2, xoptions=opciones, yoptions=opciones)
+
+ # El tablero es otra tabla
+ self.tabla_celdas = gtk.Table(10, 10, True)
+ self.tabla.attach(self.tabla_celdas, 1, 2, 1, 2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL|gtk.EXPAND)
+
+ self.filas = []
+ # Creo todas las celdas, las guardo en la colección de filas y las adjunto al tablero
+ for i in range(1, 11):
+ fila = []
+ for j in range(1, 11):
+ celda = Celda((i, j))
+ celda.connect("clicked", self.celda_clickeada)
+ fila.append(celda)
+ self.tabla_celdas.attach(celda, j-1, j, i-1, i)
+ self.filas.append(fila)
+
+ # Los barcos que hay en el tablero
+ self.barcos = []
+
+ # Callback para cuando el jugador hace una jugada en el tablero
+ self.llamada_jugada_hecha = llamada_jugada_hecha
+
+ def agregar_barco(self, barco, mostrar):
+ ''' Agrega un barco al tablero, si mostrar=True sustituye las celdas que ocupa por el barco. '''
+ self.barcos.append(barco)
+ if mostrar:
+ # Oculta las celdas que ocupa el barco
+ for i, j in barco.get_celdas():
+ self.ocultar_celda(i, j)
+
+ # Obtiene los extremos del barco y lo adjunta a la tabla
+ arr, izq = barco.get_inicio()
+ aba, der = barco.get_fin()
+ self.tabla_celdas.attach(barco, izq-1, der, arr-1, aba)
+
+ def ocultar_celda(self, i, j):
+ self.filas[i-1][j-1].ocultar()
+
+ def celda_clickeada(self, celda):
+ ''' Cuando hay definido un callback de jugadas hechas, significa que en este tablero puedo jugar.
+ Realizo la jugada y notifico al callback '''
+ if self.llamada_jugada_hecha:
+ # Este es el callback para cuando clickean una celda
+ self.jugada(celda)
+ self.llamada_jugada_hecha(celda.pos[0], celda.pos[1])
+
+ def jugada(self, celda):
+ ''' verifica si la jugada da en algún barco o en el agua y manda la señal correcta a la celda '''
+ tocado = False
+ for barco in self.barcos:
+ if celda.pos in barco.get_celdas():
+ tocado = True
+ celda.tocado()
+ if not tocado:
+ celda.agua()
+
+ log.debug("Pos:%s Tocado:%s", str(celda.pos), tocado)
+ return tocado
+
+def init(standalone, ventana_principal):
+ ''' Esta función es el punto de entrada común para sugar y modo standalone
+ standalone es un boolean que indica si es Standalone o se ejecuta desde Sugar '''
+ panel_principal = PanelPrincipal()
+
+ if not standalone:
+ ventana_principal.set_canvas(panel_principal)
+
+ # Colaboración
+ panel_principal.colaboracion = ventana_principal.colaboracion
+ panel_principal.colaboracion.set_up(
+ None, # Nuevo compañero
+ None, # Salió Compañero
+ panel_principal.cargar_barcos, # World
+ panel_principal.jugada_red, # Play
+ panel_principal.tablero1.barcos)# Mis barcos
+ else:
+ ventana_principal.add(panel_principal)
+ panel_principal.colaboracion = None
+
+ ventana_principal.set_title("Batalla Naval - ceibalJAM")
+ ventana_principal.connect("destroy", lambda wid: gtk.main_quit())
+ ventana_principal.connect("delete_event", lambda a1, a2: gtk.main_quit())
+
+ ventana_principal.show()
+
+# Este código se ejecuta sólo cuando se ejecuta directo ese módulo (no cuando se importa desde sugar)
+if __name__ == "__main__":
+ log.addHandler(logging.StreamHandler())
+ ventana_principal = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ init(True, ventana_principal)
+ gtk.main()
diff --git a/taller/pasos.txt b/taller/pasos.txt
new file mode 100644
index 0000000..b4b3a7d
--- /dev/null
+++ b/taller/pasos.txt
@@ -0,0 +1,55 @@
+'''
+BatallaNaval-1 (python-básico):
+ * Main
+ * init
+ * PanelPrincipal
+ * Celda
+ * Tablero
+ * Barco
+ * crearBarcos
+
+BatallaNaval-2 (gtk-básico):
+ * Agregar código en main e init() y parámetro ventana_principal
+ * PanelPrincipal gtk.HBox (agregar init)
+ * Ambos tableros
+ * show_all
+ * comentar barcos
+
+ * Celda gtk.Button (agregar init)
+ * Tablero gtk.Frame (agregar init)
+ * Nuevas tablas
+ * Atachar celdas al tablero
+ * MOSTRAR
+
+ * Barco gtk.Frame (agregar init)
+ * Agrega set_orientacion
+
+ * PanelPrincipal
+ * Agregar Ambos barcos
+ * Tablero
+ * Agregar código para mostrar barco
+ * MOSTRAR
+
+BatallaNaval-3 (Sugarizar):
+ * Agrega módulo de Actividad
+ * Agrega carpeta activity
+ * Agrega setup.py
+ * Agrega parámetro standalone
+ * Agrega código en el init
+
+BatallaNaval-4 (gtk-avanzado):
+ * Agrega jugadas_enemigas
+ * Agrega jugada_hecha
+ * Agrega callback de jugada_hecha al crear tableros
+ * Guarda el callback en el init del tablero
+ * Agrega funciones de colorear a celda
+ * Agrega connect a la celda
+
+BatallaNaval (colaboración):
+ * Agrega módulo de colaboración
+ * Crea colaboración en la Actividad
+ * Inicializa colaboración en el init
+ * Agrega código en jugada_hecha para manejar colaboración
+ * Agrega jugada_red para reflejar las jugadas que hace el oponente
+ * Agrega cargar_barcos
+''' \ No newline at end of file