diff options
author | Pablo Moleri <pmoleri@PABLOMOLERI-PC.(none)> | 2009-08-26 05:06:11 (GMT) |
---|---|---|
committer | Pablo Moleri <pmoleri@PABLOMOLERI-PC.(none)> | 2009-08-26 05:06:11 (GMT) |
commit | 6678b5b4b0b1115089e6280ce329b37389da126a (patch) | |
tree | dac78786bbdcca320d32aa83fba2a8a00a7c918b | |
parent | 86915957fe8ec6b001b45c667ec0fe44274520be (diff) |
Juego colaborativo completo.
Ahora World pasa la lista de barcos para que ambos sepan donde están los barcos enemigos.
-rw-r--r-- | BatallaNaval.activity/BatallaNaval.py | 308 | ||||
-rw-r--r-- | BatallaNaval.activity/BatallaNavalActivity.py | 9 | ||||
-rw-r--r-- | BatallaNaval.activity/Collaboration.py | 45 |
3 files changed, 342 insertions, 20 deletions
diff --git a/BatallaNaval.activity/BatallaNaval.py b/BatallaNaval.activity/BatallaNaval.py new file mode 100644 index 0000000..ceee1ee --- /dev/null +++ b/BatallaNaval.activity/BatallaNaval.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python +# -*- coding: cp1252 -*- + +import pygtk +pygtk.require('2.0') +import gtk +import logging +import random + +try: + from sugar.activity.activity import Activity, ActivityToolbox +except: + pass + +log = logging.getLogger('BatallaNaval') +log.setLevel(logging.DEBUG) + +lista_barcos = { + "Portaaviones": 5, + "Acorazado": 4, + "Crucero": 3, + "Submarino": 3, + "Destructor": 2} + +class PanelPrincipal(gtk.HBox): + + 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.name, 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])) + + self.add(self.tablero1) + self.add(self.tablero2) + + self.show_all() + + self.jugadas_enemigas = [] # Lleva un registro de las jugadas hechas por la computadora + + # Carga barcos remotos + def cargar_barcos(self, barcos): + 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])) + + # Cuando el enemigo juega sobre mi tablero, hago la judada y le respondo si fue tocado + def jugada_red(self, x, y): + 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: + self.colaboracion.Play(x, y) + return + + # Sinó, la computadora hace una jugada al azar sobre el tablero propio + if len(self.jugadas_enemigas) == 100: + 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.filas[x-1][y-1].clicked() + +def crear_barcos(): + barcos = [Barco(b[0], b[1], None) for b in lista_barcos.items()] + + celdas_ocupadas = [] + + for barco in barcos: + 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) + ok = True + for celda in barco.get_celdas(): + if celda in celdas_ocupadas: + ok = False + if ok: + celdas_ocupadas.extend(barco.get_celdas()) + return barcos + +class Celda(gtk.Button): + + def __init__(self, pos, clicked_cb): + gtk.Button.__init__(self) + self.pos = pos + + self.connect("clicked", clicked_cb) + + def ocultar(self): + self.set_no_show_all(True) + self.hide() + + def tocado(self): + color = gtk.gdk.Color(65535,65535/2,0) + 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 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 + +class Tablero(gtk.Frame): + + 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 el tablero + self.tabla = gtk.Table(2, 2, False) + self.add(self.tabla) + + opciones = gtk.SHRINK|gtk.FILL + + label = gtk.Label(" ") + 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) + + for i in range(1, 11): + row = [] + 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) + + self.barcos = [] # Los barcos que hay en el tablero + + self.llamada_jugada_hecha = llamada_jugada_hecha + + def agregar_barco(self, barco, show): + 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) + + 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 + 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): + tocado = False + for barco in self.barcos: + if celda.pos in barco.get_celdas(): + tocado = True + celda.tocado() + if not tocado: + celda.agua() + + 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): + + 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 + 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 es el procedimiento principal en modo standalone +def main(): + 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 1c77416..1a0f153 100644 --- a/BatallaNaval.activity/BatallaNavalActivity.py +++ b/BatallaNaval.activity/BatallaNavalActivity.py @@ -14,14 +14,7 @@ class BatallaNavalActivity(Activity): self.connect('focus_in_event', self._focus_in) self.connect('focus_out_event', self._focus_out) - self.colaboracion = CollaborationWrapper(self, None, None, None) - self.connect('shared', self.colaboracion._shared_cb) - if self._shared_activity: - # We are joining the activity - self.connect('joined', self.colaboracion._joined_cb) - if self.get_shared(): - # We've already joined - self.colaboracion._joined_cb() + self.colaboracion = CollaborationWrapper(self) # The activity is a subclass of Window, so it passses itself to the init function BatallaNaval.init(False, self) diff --git a/BatallaNaval.activity/Collaboration.py b/BatallaNaval.activity/Collaboration.py index 2e7d4e9..5d5d79c 100644 --- a/BatallaNaval.activity/Collaboration.py +++ b/BatallaNaval.activity/Collaboration.py @@ -18,7 +18,6 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import logging -import sugar.logger from sugar.presence import presenceservice import telepathy @@ -41,21 +40,36 @@ IFACE = SERVICE PATH = "/org/ceibaljam/BatallaNaval" logger = logging.getLogger('BatallaNaval') +logger.setLevel(logging.DEBUG) class CollaborationWrapper(ExportedGObject): ''' A wrapper for the collaboration bureaucracy Recibe la actividad y los callbacks necesarios ''' - def __init__(self, activity, buddy_joined_cb, buddy_left_cb, play_cb): + def __init__(self, activity): self.activity = activity + self.presence_service = presenceservice.get_instance() + self.owner = self.presence_service.get_owner() + + def set_up(self, buddy_joined_cb, buddy_left_cb, World_cb, Play_cb, mis_barcos): + self.activity.connect('shared', self._shared_cb) + if self.activity._shared_activity: + # We are joining the activity + self.activity.connect('joined', self._joined_cb) + if self.activity.get_shared(): + # We've already joined + self._joined_cb() + self.buddy_joined = buddy_joined_cb self.buddy_left = buddy_left_cb - self.Play_cb = play_cb + self.World_cb = World_cb # Llamado cuando alguien me pasa el estado del tablero + self.Play_cb = Play_cb # Llamado cuando alguien me informa de una jugada + + # Enviado al hacer World sobre un nuevo compañero + self.mis_barcos = [(b.nombre, b.orientacion, b.largo, b.pos[0], b.pos[1]) for b in mis_barcos] self.world = False self.entered = False - self.presence_service = presenceservice.get_instance() - self.owner = self.presence_service.get_owner() - + def _shared_cb(self, activity): #self.activity.gameToolbar.grey_out_size_change() #self.activity.gameToolbar.grey_out_restart() @@ -131,13 +145,14 @@ class CollaborationWrapper(ExportedGObject): # This method receives the current game state and puts us in sync # with the rest of the participants. # The current game state is represented by the game object - @method(dbus_interface=IFACE, in_signature='', out_signature='') - def World(self): + @method(dbus_interface=IFACE, in_signature='a(ssiii)', out_signature='a(ssiii)') + def World(self, barcos): """To be called on the incoming XO after they Hello.""" if not self.world: logger.debug('Somebody called World on me') #self.activity.board_size_change(None, size) self.world = True # En vez de cargar el mundo, lo voy recibiendo jugada a jugada. + self.World_cb(barcos) #self.activity.set_player_color(self.activity.invert_color(taken_color)) #self.players = players # now I can World others @@ -145,12 +160,13 @@ class CollaborationWrapper(ExportedGObject): else: self.world = True logger.debug("I've already been welcomed, doing nothing") + return self.mis_barcos @signal(dbus_interface=IFACE, signature='ii') def Play(self, x, y): """Say Hello to whoever else is in the tube.""" - logger.debug('Signaling players of stone placement at:%s x %s.', x, y) - + logger.debug('Ejecutando jugada remota:%s x %s.', x, y) + def add_hello_handler(self): logger.debug('Adding hello handler.') self.tube.add_signal_receiver(self.hello_signal_cb, 'Hello', IFACE, @@ -166,8 +182,13 @@ class CollaborationWrapper(ExportedGObject): logger.debug('Newcomer %s has joined', sender) logger.debug('Welcoming newcomer and sending them the game state') - # No le mandamos nada, la solo interesa mandar jugadas y reflejar el resultado {tocado, agua, hundido} - self.tube.get_object(sender, PATH).World(dbus_interface=IFACE) + self.other = sender # SerÃa práctico cuando juego contra uno solo y quiero ejecutar métodos sobre él + + # Le mando mis barcos y me devuelve los suyos + barcos_enemigos = self.tube.get_object(self.other, PATH).World(self.mis_barcos, dbus_interface=IFACE) + + # Llamo al callback de World, para que cargue los barcos enemigos + self.World_cb(barcos_enemigos) def play_signal_cb(self, x, y, sender=None): """Somebody placed a stone. """ |