~ubuntu-branches/ubuntu/precise/gcompris/precise

« back to all changes in this revision

Viewing changes to src/lightsoff-activity/lightsoff.py

  • Committer: Bazaar Package Importer
  • Author(s): Yann Dirson
  • Date: 2010-06-27 22:51:30 UTC
  • mfrom: (1.1.16 upstream) (5.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100627225130-mf7h4m5r8m7bd9fb
Tags: 9.3-1
* New upstream release.
* Drop GTK_DISABLE_DEPRECATED patch, useless for now.
* Provide RELEASE_NOTE_9.3.txt downloaded from sourceforge.
* New voice package for Asturian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#  gcompris - lightsoff.py
 
2
#
 
3
# Copyright (C) 2010 Bruno and Clement Coudoin
 
4
#
 
5
#   This program is free software; you can redistribute it and/or modify
 
6
#   it under the terms of the GNU General Public License as published by
 
7
#   the Free Software Foundation; either version 3 of the License, or
 
8
#   (at your option) any later version.
 
9
#
 
10
#   This program is distributed in the hope that it will be useful,
 
11
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
#   GNU General Public License for more details.
 
14
#
 
15
#   You should have received a copy of the GNU General Public License
 
16
#   along with this program; if not, see <http://www.gnu.org/licenses/>.
 
17
#
 
18
# lightsoff Board module
 
19
import gtk
 
20
import gtk.gdk
 
21
import gcompris
 
22
import gcompris.utils
 
23
import gcompris.skin
 
24
import gcompris.bonus
 
25
import goocanvas
 
26
 
 
27
from gcompris import gcompris_gettext as _
 
28
 
 
29
class Gcompris_lightsoff:
 
30
  """Empty gcompris python class"""
 
31
 
 
32
 
 
33
  def __init__(self, gcomprisBoard):
 
34
    # Save the gcomprisBoard, it defines everything we need
 
35
    # to know from the core
 
36
    self.gcomprisBoard = gcomprisBoard
 
37
 
 
38
    self.rootitem = None
 
39
 
 
40
    # These are used to let us restart only after the bonus is displayed.
 
41
    # When the bonus is displayed, it call us first with pause(1) and then with pause(0)
 
42
    self.board_paused  = False;
 
43
    self.gamewon       = False;
 
44
 
 
45
    self.data = [
 
46
      [[0,0,0,0,0],
 
47
       [0,0,1,0,0],
 
48
       [0,1,1,1,0],
 
49
       [0,0,1,0,0],
 
50
       [0,0,0,0,0]],
 
51
      [[1,1,0,0,0],
 
52
       [1,0,0,0,0],
 
53
       [0,0,0,0,0],
 
54
       [0,0,0,0,0],
 
55
       [0,0,0,0,0]],
 
56
      [[0,0,0,0,0],
 
57
       [0,0,0,0,0],
 
58
       [0,0,0,0,0],
 
59
       [0,0,1,0,0],
 
60
       [0,1,1,1,0]],
 
61
      [[1,1,0,1,1],
 
62
       [1,0,0,0,1],
 
63
       [0,0,0,0,0],
 
64
       [0,0,0,1,0],
 
65
       [0,0,1,1,1]],
 
66
      [[0,1,1,1,0],
 
67
       [1,0,1,0,1],
 
68
       [1,1,0,1,1],
 
69
       [1,0,1,0,1],
 
70
       [0,1,1,1,0]],
 
71
      [[1,1,0,1,1],
 
72
       [1,0,1,0,1],
 
73
       [0,1,1,1,0],
 
74
       [1,0,1,0,1],
 
75
       [1,1,0,1,1]],
 
76
      [[0,1,0,1,0],
 
77
       [1,1,0,1,1],
 
78
       [0,1,0,1,0],
 
79
       [1,0,1,0,1],
 
80
       [1,0,1,0,1]],
 
81
      [[1,0,0,0,1],
 
82
       [1,1,0,1,1],
 
83
       [0,0,1,0,0],
 
84
       [1,0,1,0,0],
 
85
       [1,0,1,1,0]],
 
86
      [[1,1,0,1,1],
 
87
       [0,0,0,0,0],
 
88
       [1,1,0,1,1],
 
89
       [0,0,0,0,1],
 
90
       [1,1,0,0,0]],
 
91
      # 5
 
92
      [[1,1,1,1,1],
 
93
       [1,1,1,1,1],
 
94
       [1,1,1,1,1],
 
95
       [1,1,1,1,1],
 
96
       [1,1,1,1,1]],
 
97
      # 6
 
98
      [[0,0,0,1,1],
 
99
       [0,0,0,1,1],
 
100
       [0,0,0,0,0],
 
101
       [1,1,0,0,0],
 
102
       [1,1,0,0,0]],
 
103
      # 7
 
104
      [[0,0,0,0,0],
 
105
       [0,1,1,1,0],
 
106
       [1,1,1,1,1],
 
107
       [0,1,1,1,0],
 
108
       [0,0,0,0,0]],
 
109
      # 8
 
110
      [[0,0,0,0,0],
 
111
       [0,1,1,1,0],
 
112
       [0,1,1,1,0],
 
113
       [0,1,1,1,0],
 
114
       [0,0,0,0,0]],
 
115
      # 9
 
116
      [[1,1,0,1,1],
 
117
       [1,1,0,1,1],
 
118
       [0,0,0,0,0],
 
119
       [1,1,0,1,1],
 
120
       [1,1,0,1,1]],
 
121
      # 10
 
122
      [[1,1,1,1,1],
 
123
       [0,1,1,1,0],
 
124
       [0,0,1,0,0],
 
125
       [0,1,1,1,0],
 
126
       [1,1,1,1,1]],
 
127
      # 11
 
128
      [[1,1,1,1,1],
 
129
       [1,0,0,0,1],
 
130
       [1,0,0,0,1],
 
131
       [1,0,0,0,1],
 
132
       [1,1,1,1,1]],
 
133
      # 12
 
134
      [[0,0,1,1,1],
 
135
       [0,0,0,1,1],
 
136
       [1,0,0,0,1],
 
137
       [1,1,0,0,0],
 
138
       [1,1,1,0,0]],
 
139
      # 13
 
140
      [[1,0,0,0,1],
 
141
       [0,1,0,1,0],
 
142
       [0,0,1,0,0],
 
143
       [0,1,0,1,0],
 
144
       [1,0,0,0,1]],
 
145
      # 14
 
146
      [[1,1,1,1,1],
 
147
       [1,0,1,0,1],
 
148
       [1,1,1,1,1],
 
149
       [1,0,1,0,1],
 
150
       [1,1,1,1,1]],
 
151
      # 15
 
152
      [[1,0,0,0,0],
 
153
       [1,1,1,1,0],
 
154
       [1,1,1,1,0],
 
155
       [1,1,1,1,0],
 
156
       [1,1,1,1,1]],
 
157
      # 16
 
158
      [[1,1,1,1,1],
 
159
       [1,1,1,1,1],
 
160
       [1,1,0,1,1],
 
161
       [1,1,1,1,1],
 
162
       [1,1,1,1,1]],
 
163
      # 17
 
164
      [[1,0,1,0,1],
 
165
       [0,1,0,1,0],
 
166
       [0,0,1,0,0],
 
167
       [0,1,0,1,0],
 
168
       [1,0,1,0,1]],
 
169
      # 18
 
170
      [[1,1,1,0,1],
 
171
       [1,1,1,0,1],
 
172
       [0,0,0,0,0],
 
173
       [1,0,1,1,1],
 
174
       [1,0,1,1,1]],
 
175
      # 19
 
176
      [[1,1,0,1,1],
 
177
       [1,1,0,1,1],
 
178
       [1,1,0,1,1],
 
179
       [1,1,0,1,1],
 
180
       [1,1,0,1,1]],
 
181
      # 20
 
182
      [[1,1,1,1,1],
 
183
       [1,0,0,0,1],
 
184
       [1,1,0,1,1],
 
185
       [1,1,0,1,1],
 
186
       [1,1,1,1,1]],
 
187
      # 21
 
188
      [[1,1,1,1,1],
 
189
       [1,1,1,1,1],
 
190
       [0,0,0,1,1],
 
191
       [0,0,0,1,1],
 
192
       [0,0,0,1,1]],
 
193
      # 22
 
194
      [[1,1,1,0,1],
 
195
       [1,1,1,0,0],
 
196
       [1,1,1,0,0],
 
197
       [1,1,1,0,0],
 
198
       [1,1,1,0,1]],
 
199
      # 23
 
200
      [[1,1,1,1,1],
 
201
       [0,0,1,0,0],
 
202
       [0,0,1,0,0],
 
203
       [0,0,1,0,0],
 
204
       [1,1,1,1,1]],
 
205
      # 24
 
206
      [[0,0,0,0,0],
 
207
       [0,1,1,0,0],
 
208
       [0,1,1,1,0],
 
209
       [0,0,1,1,0],
 
210
       [0,0,0,0,0]],
 
211
      # 25
 
212
      [[0,0,0,1,1],
 
213
       [0,0,1,1,1],
 
214
       [0,0,1,0,0],
 
215
       [1,1,1,0,0],
 
216
       [1,1,0,0,0]],
 
217
      # 26
 
218
      [[0,0,0,1,1],
 
219
       [1,1,0,1,1],
 
220
       [1,1,0,0,0],
 
221
       [1,1,0,0,0],
 
222
       [1,1,0,1,1]],
 
223
      # 27
 
224
      [[1,0,0,0,1],
 
225
       [0,1,1,1,0],
 
226
       [0,1,1,1,0],
 
227
       [0,1,1,1,0],
 
228
       [1,0,0,0,1]],
 
229
      # 28
 
230
      [[1,0,1,0,1],
 
231
       [0,1,0,1,0],
 
232
       [1,0,1,0,1],
 
233
       [0,1,0,1,0],
 
234
       [1,0,1,0,1]],
 
235
      # 29
 
236
      [[0,0,1,0,0],
 
237
       [1,0,0,1,0],
 
238
       [0,1,1,1,1],
 
239
       [1,0,0,0,0],
 
240
       [1,1,0,1,0]],
 
241
      # 30
 
242
      [[0,0,0,0,1],
 
243
       [0,0,0,1,1],
 
244
       [0,0,1,0,1],
 
245
       [0,1,0,0,1],
 
246
       [1,1,1,1,1]],
 
247
      # 31
 
248
      [[1,1,0,1,1],
 
249
       [0,1,0,1,0],
 
250
       [1,1,1,1,1],
 
251
       [1,1,0,1,1],
 
252
       [1,0,0,0,1]],
 
253
      # 32
 
254
      [[0,1,1,0,0],
 
255
       [0,1,1,0,1],
 
256
       [0,1,0,0,1],
 
257
       [1,1,0,0,0],
 
258
       [1,1,1,1,0]],
 
259
      # 33
 
260
      [[0,0,0,0,1],
 
261
       [1,1,1,0,0],
 
262
       [1,0,1,1,1],
 
263
       [1,1,1,1,0],
 
264
       [1,0,0,1,0]],
 
265
      # 34
 
266
      [[1,0,1,1,1],
 
267
       [0,0,1,0,1],
 
268
       [0,0,0,0,0],
 
269
       [1,1,1,1,0],
 
270
       [1,1,0,1,0]],
 
271
      # 35
 
272
      [[1,1,0,1,1],
 
273
       [0,1,0,1,1],
 
274
       [0,0,0,1,0],
 
275
       [1,1,0,0,0],
 
276
       [1,1,1,1,0]],
 
277
      # 36
 
278
      [[1,1,1,1,1],
 
279
       [0,0,0,1,0],
 
280
       [0,1,0,1,1],
 
281
       [1,1,1,0,1],
 
282
       [1,0,1,0,0]],
 
283
      # 37
 
284
      [[0,0,0,1,1],
 
285
       [1,0,1,1,0],
 
286
       [0,0,1,0,0],
 
287
       [0,1,1,1,1],
 
288
       [1,0,0,1,0]],
 
289
      # 38
 
290
      [[0,0,0,0,1],
 
291
       [0,0,1,1,1],
 
292
       [1,1,0,0,1],
 
293
       [1,1,1,0,0],
 
294
       [0,0,1,0,0]],
 
295
      # 39
 
296
      [[0,0,1,1,1],
 
297
       [1,0,1,1,1],
 
298
       [1,1,1,0,0],
 
299
       [0,0,1,0,0],
 
300
       [1,1,0,1,1]],
 
301
      # 40
 
302
      [[0,1,1,1,1],
 
303
       [0,0,1,1,1],
 
304
       [0,0,1,1,1],
 
305
       [1,1,1,1,0],
 
306
       [0,0,0,1,0]],
 
307
      # 41
 
308
      [[1,1,1,1,1],
 
309
       [1,0,0,0,0],
 
310
       [0,1,0,0,1],
 
311
       [0,0,0,1,1],
 
312
       [1,1,1,1,1]],
 
313
      # 42
 
314
      [[1,1,1,1,1],
 
315
       [1,0,0,0,0],
 
316
       [0,0,1,0,0],
 
317
       [0,1,1,1,0],
 
318
       [0,1,0,0,1]],
 
319
      # 43
 
320
      [[0,0,0,0,0],
 
321
       [0,0,0,1,0],
 
322
       [1,1,0,1,1],
 
323
       [0,1,1,0,0],
 
324
       [1,1,1,1,1]],
 
325
      # 44
 
326
      [[0,0,0,1,1],
 
327
       [0,1,1,0,0],
 
328
       [0,1,0,0,0],
 
329
       [1,1,1,1,0],
 
330
       [1,1,1,1,0]],
 
331
      # 45
 
332
      [[0,0,0,1,0],
 
333
       [1,1,1,1,1],
 
334
       [0,0,0,0,0],
 
335
       [0,0,1,0,0],
 
336
       [1,1,1,1,0]],
 
337
      # 46
 
338
      [[0,1,0,1,0],
 
339
       [0,0,0,1,0],
 
340
       [0,1,0,1,0],
 
341
       [0,0,1,0,0],
 
342
       [0,1,1,1,0]],
 
343
      # 47
 
344
      [[1,0,0,1,0],
 
345
       [0,0,0,0,1],
 
346
       [0,1,0,0,0],
 
347
       [0,0,0,0,0],
 
348
       [1,0,1,0,0]],
 
349
      # 48
 
350
      [[1,1,0,0,1],
 
351
       [0,1,0,0,1],
 
352
       [0,1,1,1,1],
 
353
       [0,1,0,1,0],
 
354
       [1,1,1,1,1]],
 
355
      # 49
 
356
      [[1,1,1,1,1],
 
357
       [0,0,1,0,0],
 
358
       [0,1,1,0,0],
 
359
       [0,0,1,1,0],
 
360
       [1,1,1,0,1]],
 
361
      # 50
 
362
      [[1,0,1,0,1],
 
363
       [1,0,1,0,0],
 
364
       [0,0,0,1,1],
 
365
       [0,1,0,1,0],
 
366
       [1,0,0,1,0]],
 
367
      # 51
 
368
      [[0,1,0,1,0],
 
369
       [1,0,0,1,0],
 
370
       [0,1,1,1,1],
 
371
       [1,0,1,0,0],
 
372
       [0,1,1,0,0]],
 
373
      # 52
 
374
      [[1,1,1,1,1],
 
375
       [1,1,0,0,0],
 
376
       [0,0,0,1,1],
 
377
       [0,1,1,1,0],
 
378
       [0,0,1,0,0]],
 
379
      ]
 
380
 
 
381
 
 
382
  def start(self):
 
383
    self.gcomprisBoard.level=1
 
384
    self.gcomprisBoard.maxlevel=len(self.data)
 
385
    self.gcomprisBoard.sublevel=1
 
386
    self.gcomprisBoard.number_of_sublevel=1
 
387
 
 
388
    # Create our rootitem. We put each canvas item in it so at the end we
 
389
    # only have to kill it. The canvas deletes all the items it contains
 
390
    # automaticaly.
 
391
    self.backroot = goocanvas.Group(parent = \
 
392
                                      self.gcomprisBoard.canvas.get_root_item())
 
393
 
 
394
    # A color changing background
 
395
    self.background = goocanvas.Rect(
 
396
      parent = self.backroot,
 
397
      x = 0,
 
398
      y = 0,
 
399
      width = gcompris.BOARD_WIDTH,
 
400
      height = 200,
 
401
      fill_color_rgba = 0xFFFFFFFFL
 
402
      )
 
403
 
 
404
    svghandle = gcompris.utils.load_svg("lightsoff/back.svgz")
 
405
    goocanvas.Svg(
 
406
      parent = self.backroot,
 
407
      svg_handle = svghandle,
 
408
      svg_id = "#BACKGROUND",
 
409
      pointer_events = goocanvas.EVENTS_NONE
 
410
      )
 
411
 
 
412
    # The Sun
 
413
    self.sunitem = goocanvas.Svg(
 
414
      parent = self.backroot,
 
415
      svg_handle = svghandle,
 
416
      svg_id = "#SUN",
 
417
      )
 
418
    self.sunitem_offset = 0
 
419
 
 
420
    # TUX
 
421
    self.tuxitem = goocanvas.Svg(
 
422
      parent = self.backroot,
 
423
      svg_handle = svghandle,
 
424
      svg_id = "#TUX",
 
425
      )
 
426
    self.tuxitem.connect("button_press_event", self.solve_event)
 
427
    gcompris.utils.item_focus_init(self.tuxitem, None)
 
428
 
 
429
    # The Buble
 
430
    self.bubbleitem = goocanvas.Svg(
 
431
      parent = self.backroot,
 
432
      svg_handle = svghandle,
 
433
      svg_id = "#BUBBLE1",
 
434
      )
 
435
 
 
436
    self.textitem = goocanvas.Text(
 
437
      parent = self.backroot,
 
438
      x = gcompris.BOARD_WIDTH/2 + 80,
 
439
      y = gcompris.BOARD_HEIGHT - 80,
 
440
      width = 400,
 
441
      font = gcompris.skin.get_font("gcompris/content"),
 
442
      text = _("Switch off all the lights, I have to go to sleep.\n"
 
443
               "If you need help, click on me."),
 
444
      fill_color = "black",
 
445
      anchor = gtk.ANCHOR_CENTER
 
446
      )
 
447
 
 
448
    # The Tipi
 
449
    self.tipiitem = goocanvas.Svg(
 
450
      parent = self.backroot,
 
451
      svg_handle = svghandle,
 
452
      svg_id = "#TIPI",
 
453
      )
 
454
 
 
455
    # The image foreground
 
456
    goocanvas.Svg(
 
457
      parent = self.backroot,
 
458
      svg_handle = svghandle,
 
459
      svg_id = "#FOREGROUND",
 
460
      pointer_events = goocanvas.EVENTS_NONE
 
461
      )
 
462
 
 
463
    # Set the buttons we want in the bar
 
464
    gcompris.bar_set(gcompris.BAR_LEVEL|gcompris.BAR_REPEAT)
 
465
    gcompris.bar_location(gcompris.BOARD_WIDTH/2 - 90, -1, 0.6)
 
466
    gcompris.bar_set_level(self.gcomprisBoard)
 
467
 
 
468
    self.display_game()
 
469
 
 
470
  def end(self):
 
471
    self.backroot.remove()
 
472
    self.backroot = None
 
473
    self.rootitem = None
 
474
 
 
475
 
 
476
  def ok(self):
 
477
    print("lightsoff ok.")
 
478
 
 
479
 
 
480
  def repeat(self):
 
481
    self.display_game()
 
482
 
 
483
  def config(self):
 
484
    print("lightsoff config.")
 
485
 
 
486
 
 
487
  def key_press(self, keyval, commit_str, preedit_str):
 
488
   pass
 
489
 
 
490
  def pause(self, pause):
 
491
    self.board_paused = pause
 
492
 
 
493
    # When the bonus is displayed, it call us first
 
494
    # with pause(1) and then with pause(0)
 
495
    # the game is won
 
496
    if(self.gamewon == True and pause == False):
 
497
      self.gamewon = False
 
498
      if(self.increment_level()):
 
499
        self.display_game()
 
500
 
 
501
 
 
502
 
 
503
  def set_level(self, level):
 
504
    self.gcomprisBoard.level = level
 
505
    gcompris.bar_set_level(self.gcomprisBoard)
 
506
    self.display_game()
 
507
 
 
508
 
 
509
  # Code that increments the sublevel and level
 
510
  # And bail out if no more levels are available
 
511
  # return 1 if continue, 0 if bail out
 
512
  def increment_level(self):
 
513
    self.gcomprisBoard.sublevel += 1
 
514
 
 
515
    if(self.gcomprisBoard.sublevel>self.gcomprisBoard.number_of_sublevel):
 
516
      # Try the next level
 
517
      self.gcomprisBoard.sublevel=1
 
518
      self.gcomprisBoard.level += 1
 
519
      gcompris.bar_set_level(self.gcomprisBoard)
 
520
 
 
521
      if(self.gcomprisBoard.level>self.gcomprisBoard.maxlevel):
 
522
        self.gcomprisBoard.level = self.gcomprisBoard.maxlevel
 
523
 
 
524
    return 1
 
525
 
 
526
  def create_empty_list(self):
 
527
    items = []
 
528
    for x in range(5):
 
529
      items.append(range(5))
 
530
    for y in range(len(items)):
 
531
      for x in range(len(items[0])):
 
532
        items[y][x] = 0
 
533
    return items
 
534
 
 
535
  # Display the board game
 
536
  def display_game(self):
 
537
      # The grid we display
 
538
      # It contains all the graphic items
 
539
      self.items = self.create_empty_list()
 
540
 
 
541
      # The grid of hints items
 
542
      self.hints = self.create_empty_list()
 
543
 
 
544
      # Do we display the hints
 
545
      self.hints_mode = False
 
546
 
 
547
      if self.rootitem:
 
548
        self.rootitem.remove()
 
549
 
 
550
      self.tipiitem.props.visibility = goocanvas.ITEM_INVISIBLE
 
551
      self.textitem.props.visibility = goocanvas.ITEM_VISIBLE
 
552
      self.tuxitem.props.visibility = goocanvas.ITEM_VISIBLE
 
553
      self.bubbleitem.props.visibility = goocanvas.ITEM_VISIBLE
 
554
 
 
555
      # Create our rootitem. We put each canvas item in it so at the end we
 
556
      # only have to kill it. The canvas deletes all the items it contains
 
557
      # automaticaly.
 
558
      self.rootitem =  \
 
559
          goocanvas.Group(parent = self.backroot)
 
560
 
 
561
      svghandle = gcompris.utils.load_svg("lightsoff/onoff.svgz")
 
562
      iwidth = svghandle.props.width
 
563
      iheight = svghandle.props.height
 
564
 
 
565
      gap = 10
 
566
      x_start = (gcompris.BOARD_WIDTH - len(self.items) * (iwidth + gap) ) / 2
 
567
      y_start = (gcompris.BOARD_HEIGHT - len(self.items[0]) \
 
568
                   * (iheight + gap) ) / 2 - 40
 
569
 
 
570
      goocanvas.Rect(
 
571
        parent = self.rootitem,
 
572
        x = x_start - gap,
 
573
        y = y_start - gap,
 
574
        width = len(self.items) * (iwidth + gap) + gap,
 
575
        height = len(self.items[0]) * (iheight + gap) + gap,
 
576
        fill_color_rgba = 0x445533AAL,
 
577
        stroke_color_rgba = 0xC0C0C0AAL,
 
578
        radius_x = 10,
 
579
        radius_y = 10,
 
580
        line_width = 2
 
581
        )
 
582
 
 
583
      data = self.data[self.gcomprisBoard.level - 1]
 
584
      for y in range(len(self.items)):
 
585
        for x in range(len(self.items[0])):
 
586
          item = goocanvas.Rect(
 
587
            parent = self.rootitem,
 
588
            x = x_start + (iwidth + gap) * x - gap/2,
 
589
            y = y_start + (iheight + gap) * y - gap/2,
 
590
            width = iwidth + gap,
 
591
            height = iheight + gap,
 
592
            stroke_color_rgba = 0xC0C0C0FAL,
 
593
            fill_color_rgba = 0x5050509AL,
 
594
            line_width = 2,
 
595
            radius_x = 10,
 
596
            radius_y = 10,
 
597
            )
 
598
          self.hints[y][x] = item
 
599
          item.props.visibility = goocanvas.ITEM_INVISIBLE
 
600
 
 
601
          state = data[y][x]
 
602
          svg_id = "#off"
 
603
          if state:
 
604
            svg_id = "#on"
 
605
          item = goocanvas.Svg(
 
606
            parent = self.rootitem,
 
607
            svg_handle = svghandle,
 
608
            svg_id = svg_id,
 
609
            )
 
610
          item.set_data("state", state)
 
611
          item.translate(x_start + (iwidth + gap) * x,
 
612
                         y_start + (iheight + gap) * y)
 
613
          item.connect("button_press_event", self.button_press_event, [y,x])
 
614
          self.items[y][x] = item
 
615
 
 
616
      self.solve_it()
 
617
 
 
618
  def is_on(self, item):
 
619
    return item.get_data("state")
 
620
 
 
621
  def switch(self, item):
 
622
    if not item:
 
623
      return
 
624
    mystate =  self.is_on(item)
 
625
    if mystate == False:
 
626
      item.set_properties(svg_id = "#on")
 
627
    else:
 
628
      item.set_properties(svg_id = "#off")
 
629
    item.set_data("state", not mystate)
 
630
 
 
631
  def get_item_up(self, y, x):
 
632
    if y == 0:
 
633
      return None
 
634
    return self.items[y-1][x]
 
635
 
 
636
  def get_item_down(self, y, x):
 
637
    if y == len(self.items[0])-1:
 
638
      return None
 
639
    return self.items[y+1][x]
 
640
 
 
641
  def get_item_left(self, y, x):
 
642
    if x == 0:
 
643
      return None
 
644
    return self.items[y][x-1]
 
645
 
 
646
  def get_item_right(self, y, x):
 
647
    if x == len(self.items)-1:
 
648
      return None
 
649
    return self.items[y][x+1]
 
650
 
 
651
  # Returns True when complete
 
652
  def is_done(self):
 
653
    for y in range(len(self.items)):
 
654
      for x in range(len(self.items[0])):
 
655
        if self.is_on(self.items[y][x]):
 
656
          return False
 
657
 
 
658
    return True
 
659
 
 
660
  def button_press_event(self, widget, target, event, spot):
 
661
    self.switch(target)
 
662
    self.switch(self.get_item_up(spot[0], spot[1]))
 
663
    self.switch(self.get_item_left(spot[0], spot[1]))
 
664
    self.switch(self.get_item_right(spot[0], spot[1]))
 
665
    self.switch(self.get_item_down(spot[0], spot[1]))
 
666
 
 
667
    self.solve_it()
 
668
 
 
669
    if self.is_done():
 
670
      self.tipiitem.props.visibility = goocanvas.ITEM_VISIBLE
 
671
      self.textitem.props.visibility = goocanvas.ITEM_INVISIBLE
 
672
      self.tuxitem.props.visibility = goocanvas.ITEM_INVISIBLE
 
673
      self.bubbleitem.props.visibility = goocanvas.ITEM_INVISIBLE
 
674
      self.gamewon = True
 
675
      gcompris.bonus.display(gcompris.bonus.WIN, gcompris.bonus.FLOWER)
 
676
 
 
677
  def solution_switch(self, items, clicks, y, x):
 
678
    items[y][x] = not items[y][x]
 
679
    clicks[y][x] = not clicks[y][x]
 
680
    if y >= 1:
 
681
      items[y-1][x] = not items[y-1][x]
 
682
    if y <= 3:
 
683
      items[y+1][x] = not items[y+1][x]
 
684
    if x >= 1:
 
685
      items[y][x-1] = not items[y][x-1]
 
686
    if x <= 3:
 
687
      items[y][x+1] = not items[y][x+1]
 
688
 
 
689
 
 
690
  def chase_light(self, items, clicks):
 
691
    for y in range(1, len(items)):
 
692
      for x in range(len(items[0])):
 
693
        if items[y-1][x]:
 
694
          self.solution_switch(items, clicks, y, x)
 
695
 
 
696
  def is_solution_pattern(self, s, a, b, c, d, e):
 
697
    if s[4][0] == a and \
 
698
          s[4][1] == b and \
 
699
          s[4][2] == c and \
 
700
          s[4][3] == d and \
 
701
          s[4][4] == e:
 
702
      return True
 
703
    return False
 
704
 
 
705
 
 
706
  # Return False if the is no solution
 
707
  def solution_wrap(self, solution, clicks):
 
708
    if self.is_solution_pattern(solution, 1, 0, 0 , 0, 1):
 
709
      self.solution_switch(solution, clicks, 0, 0)
 
710
      self.solution_switch(solution, clicks, 0, 1)
 
711
    elif self.is_solution_pattern(solution, 0, 1, 0, 1, 0):
 
712
      self.solution_switch(solution, clicks, 0, 0)
 
713
      self.solution_switch(solution, clicks, 0, 3)
 
714
    elif self.is_solution_pattern(solution, 1, 1, 1, 0, 0):
 
715
      self.solution_switch(solution, clicks, 0, 1)
 
716
    elif self.is_solution_pattern(solution, 0, 0, 1, 1 , 1):
 
717
      self.solution_switch(solution, clicks, 0, 3)
 
718
    elif self.is_solution_pattern(solution, 1, 0, 1, 1, 0):
 
719
      self.solution_switch(solution, clicks, 0, 4)
 
720
    elif self.is_solution_pattern(solution, 0, 1, 1, 0, 1):
 
721
      self.solution_switch(solution, clicks, 0, 0)
 
722
    elif self.is_solution_pattern(solution, 1, 1, 0, 1, 1):
 
723
      self.solution_switch(solution, clicks, 0, 2)
 
724
    else:
 
725
      return False
 
726
    return True
 
727
 
 
728
  def items2list(self, items):
 
729
    list = []
 
730
    for y in range(len(items[0])):
 
731
      line = []
 
732
      for x in range(len(items)):
 
733
        if self.is_on(items[y][x]):
 
734
          line.append(1)
 
735
        else:
 
736
          line.append(0)
 
737
      list.append(line)
 
738
    return list
 
739
 
 
740
  # We check only the last line
 
741
  def solution_found(self, solution):
 
742
    for x in range(len(solution[0])):
 
743
      if solution[4][x]:
 
744
        return False
 
745
    return True
 
746
 
 
747
  def solution_length(self, clicks):
 
748
    click = 0
 
749
    for y in range(0, len(clicks)):
 
750
      for x in range(len(clicks[0])):
 
751
        if clicks[y][x]:
 
752
          click += 1
 
753
    return click
 
754
 
 
755
  def solve_one(self, solution, clicks):
 
756
    found = False
 
757
    for index in range(0, 5):
 
758
 
 
759
      self.chase_light( solution, clicks )
 
760
 
 
761
      if self.solution_found(solution):
 
762
        found = True
 
763
        break
 
764
 
 
765
      if not self.solution_wrap(solution, clicks):
 
766
        break
 
767
 
 
768
    if found:
 
769
      return clicks
 
770
    else:
 
771
      return None
 
772
 
 
773
  # Solving algorithm is the one described here:
 
774
  # http://www.haar.clara.co.uk/Lights/solving.html To begin, you turn
 
775
  # out all the lights on the top row, by pressing the buttons on the
 
776
  # second row that are directly underneath any lit buttons on the top
 
777
  # row. The top row will then have all it's lights off.  Repeat this
 
778
  # step for the second, third and fourth row. (i.e. chase the lights
 
779
  # all the way down to the bottom row). This may have solved the
 
780
  # puzzle already ( click here for an example of this ), but is more
 
781
  # likely that there will now be some lights left on in the bottom
 
782
  # row. If so, there are only 7 posible configurations. Depending on
 
783
  # which configuration you are left with, you need to press some
 
784
  # buttons in the top row. You can determine which buttons you need
 
785
  # to press from the following table.
 
786
  # Light on bottom row     Press on this on top row
 
787
  # 10001                   11000
 
788
  # 01010                   10010
 
789
  # 11100                   01000
 
790
  # 00111                   00010
 
791
  # 10110                   00001
 
792
  # 01101                   10000
 
793
  # 11011                   00100
 
794
 
 
795
  def solve_it(self):
 
796
    clicks = None
 
797
 
 
798
    # Our solving algorithm does not find the shortest solution. We
 
799
    # don't really care but we'd like to keep the proposed solution
 
800
    # stable (not propose a complete new solution when one light
 
801
    # changes).  To achieve this (closely), we test here all the
 
802
    # combination of the first line, trying to find the shortest
 
803
    # solution.
 
804
    for x in range(64):
 
805
      solution = self.items2list(self.items)
 
806
      clicks2 = self.create_empty_list()
 
807
      if x & 1:
 
808
        self.solution_switch(solution, clicks2, 0, 0)
 
809
      if x & 2:
 
810
        self.solution_switch(solution, clicks2, 0, 1)
 
811
      if x & 4:
 
812
        self.solution_switch(solution, clicks2, 0, 2)
 
813
      if x & 8:
 
814
        self.solution_switch(solution, clicks2, 0, 3)
 
815
      if x & 16:
 
816
        self.solution_switch(solution, clicks2, 0, 4)
 
817
 
 
818
      clicks2 = self.solve_one(solution, clicks2)
 
819
      if clicks == None and clicks2:
 
820
        clicks = clicks2
 
821
      elif clicks2 and \
 
822
            self.solution_length(clicks2) < self.solution_length(clicks):
 
823
        clicks = clicks2
 
824
 
 
825
    if self.hints_mode:
 
826
      self.show_hints(clicks)
 
827
    self.update_background(clicks)
 
828
 
 
829
 
 
830
 
 
831
  def solve_event(self, widget, target, event):
 
832
    clicks = self.create_empty_list()
 
833
    self.hints_mode = not self.hints_mode
 
834
    if not self.hints_mode:
 
835
      self.show_hints(clicks)
 
836
    else:
 
837
      self.solve_it()
 
838
 
 
839
 
 
840
  def update_background(self, clicks):
 
841
    length = self.solution_length(clicks)
 
842
    c = int(length * 0xFF / 18.0)
 
843
    color = 0X33 << 24 | 0x11 << 16 | c << 8 | 0xFFL
 
844
    self.background.set_properties(fill_color_rgba = color)
 
845
 
 
846
    self.sunitem.translate(0, self.sunitem_offset)
 
847
    self.sunitem_offset = length * 10
 
848
    self.sunitem.translate(0, self.sunitem_offset * -1)
 
849
 
 
850
 
 
851
  def show_hints(self, clicks):
 
852
    for y in range(len(clicks)):
 
853
      for x in range(len(clicks[0])):
 
854
        if clicks[y][x]:
 
855
          self.hints[y][x].props.visibility = goocanvas.ITEM_VISIBLE
 
856
        else:
 
857
          self.hints[y][x].props.visibility = goocanvas.ITEM_INVISIBLE
 
858
 
 
859
  def print_sol(self, clicks):
 
860
    for y in range(len(clicks)):
 
861
      s = ""
 
862
      for x in range(len(clicks[0])):
 
863
        if clicks[y][x]:
 
864
          s += "1"
 
865
        else:
 
866
          s += "0"
 
867
      print s
 
868
    print ""