5
# Copyright (C) 2005 Laurent Lacheny
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
# The IA code comes from the project 4stattack by Jeroen Vloothuis
23
# http://forcedattack.sourceforge.net/
35
from gettext import gettext as _
38
from connect4p import rules
39
from connect4p import human
40
from connect4p import minmax
41
from connect4p import board
42
# ----------------------------------------
45
class Gcompris_connect4:
46
"""Connect 4 stones"""
49
def __init__(self, gcomprisBoard):
50
self.gcomprisBoard = gcomprisBoard
53
self.boardSize = 490.0
59
self.firstPlayer = False
64
self.machineHasPlayed = True
65
self.endAnimCallback = None
66
self.gcomprisBoard.level=1
67
self.gcomprisBoard.maxlevel=9
68
self.gcomprisBoard.sublevel=1
69
self.gcomprisBoard.number_of_sublevel=1
70
self.winnercall = None
71
gcompris.bar_set(gcompris.BAR_LEVEL)
72
gcompris.bar_set_level(self.gcomprisBoard)
74
# Create our rootitem. We put each canvas item in it so at the end we
75
# only have to kill it. The canvas deletes all the items it contains automaticaly.
76
self.rootitem = self.gcomprisBoard.canvas.root().add(
77
gnomecanvas.CanvasGroup,
82
pixmap = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("button_reload.png"))
84
gcompris.bar_set_repeat_icon(pixmap)
85
gcompris.bar_set(gcompris.BAR_LEVEL|gcompris.BAR_REPEAT_ICON)
87
gcompris.bar_set(gcompris.BAR_LEVEL|gcompris.BAR_REPEAT)
89
selector = self.rootitem.add(
90
gnomecanvas.CanvasPixbuf,
91
pixbuf = gcompris.utils.load_pixmap("connect4/back.png"),
95
selector.connect("event", self.columnItemEvent, 0)
97
self.prof = self.rootitem.add(
98
gnomecanvas.CanvasPixbuf,
99
pixbuf = gcompris.utils.load_pixmap("connect4/tux-teacher.png"),
103
self.prof.connect("event", self.profItemEvent, 0)
104
self.prof.connect("event", gcompris.utils.item_event_focus)
106
self.timericon = gcompris.anim.CanvasItem( gcompris.anim.Animation("connect4/sablier.txt"),
108
self.timericon.gnomecanvas.hide()
114
gtk.timeout_remove(self.timerAnim)
115
if self.timerMachine:
116
gtk.timeout_remove(self.timerMachine)
120
# Remove the root item removes all the others inside it
121
self.rootitem.destroy()
122
self.boardItem.destroy()
129
if self.humanVictory >= self.maxVictory:
130
if self.gcomprisBoard.level < self.maxLevel:
131
self.set_level(self.gcomprisBoard.level+1)
142
def key_press(self, keyval, commit_str, preedit_str):
143
self.timericon.gnomecanvas.hide()
146
def pause(self, pause):
149
# Called by gcompris when the user click on the level icon
150
def set_level(self, level):
151
if level > self.maxLevel: level = 1
152
self.gcomprisBoard.level=level
153
self.gcomprisBoard.sublevel=1
154
gcompris.bar_set_level(self.gcomprisBoard)
155
self.player1.setDifficulty(level)
156
self.player2.setDifficulty(level)
157
self.humanVictory = 0
160
# End of Initialisation
161
# ---------------------
164
if self.boardItem != None:
165
self.boardItem.destroy()
166
self.boardItem = self.gcomprisBoard.canvas.root().add(
167
gnomecanvas.CanvasGroup,
168
x=(gcompris.BOARD_WIDTH-self.boardSize)/2.0,
171
self.player1 = human.Human(self.gcomprisBoard.level)
172
self.player2 = minmax.MinMax(self.gcomprisBoard.level, self.refreshScreen)
173
self.board = board.Board()
175
self.machineHasPlayed = True
181
self.firstPlayer = False
184
def columnItemEvent(self, widget, event, column):
185
if event.type == gtk.gdk.BUTTON_PRESS:
186
if event.button == 1 and self.gamewon == False and self.machineHasPlayed:
187
column = int((event.x - (gcompris.BOARD_WIDTH-self.boardSize)/2.0) // self.stoneSize)
188
if not (column < 0 or column > (self.nbColumns-1)):
189
gcompris.bar_hide(True)
190
if self.play(self.player1, 1, column):
191
if self.winnercall == None:
192
self.timericon.gnomecanvas.show()
193
self.endAnimCallback = self.machinePlay
194
self.machineHasPlayed = False
198
def profItemEvent(self, widget, event, column):
199
#if event.type == gtk.gdk.BUTTON_PRESS and self.firstPlayer == False:
200
if event.type == gtk.gdk.BUTTON_PRESS:
201
self.firstPlayer = True
204
def machinePlay(self):
206
self.play(self.player2, 2, 0)
208
self.timericon.gnomecanvas.hide()
210
self.endAnimCallback = self.machinePlayed
212
def machinePlayed(self):
213
self.machineHasPlayed = True
214
gcompris.bar_hide(False)
216
def refreshScreen(self):
217
gtk.main_iteration(block=False)
220
def play(self, player, numPlayer, column):
221
move = player.doMove(self.board, numPlayer, column)
223
if type(move) is types.IntType and rules.isMoveLegal(self.board, move):
224
# self.firstPlayer = True
225
self.board.move(move, numPlayer)
226
self.drawBoard(self.board)
227
self.winLine = rules.isWinner(self.board, numPlayer)
230
self.winnercall = lambda : self.winner(numPlayer)
231
elif rules.isBoardFull(self.board):
232
self.winnercall = lambda : self.winner(0)
235
gcompris.bar_hide(False)
238
def drawBoard(self, board):
239
stone = self.board.state[self.board.last_move][-1]
240
x = self.board.last_move
241
y = len(self.board.state[self.board.last_move])-1
242
file = "connect4/stone_%d.png" % stone
244
self.stone = self.boardItem.add(
245
gnomecanvas.CanvasPixbuf,
246
pixbuf = gcompris.utils.load_pixmap(file),
247
x=x*(self.boardSize/self.nbColumns),
248
#y=(self.boardSize/self.nbColumns)*(self.nbLines-1-y)
251
self.stone.connect("event", self.columnItemEvent, 0)
252
self.countAnim = self.nbLines-y
253
self.timerAnim = gtk.timeout_add(200, self.animTimer)
257
if self.countAnim > 0:
258
y= self.stone.get_property('y')
259
self.stone.set_property('y', y + (self.boardSize/self.nbColumns))
260
self.timerAnim = gtk.timeout_add(200, self.animTimer)
265
self.endAnimCallback=None
266
if self.endAnimCallback:
267
self.endAnimCallback()
269
def winner(self, player):
272
# It's a draw, no line to draw
274
gcompris.bonus.display(gcompris.bonus.DRAW, gcompris.bonus.FLOWER)
277
# Display the winner line
278
if ((self.firstPlayer and (player==2)) or
279
((not self.firstPlayer) and (player==1))):
280
self.humanVictory += 1
282
self.humanVictory = 0
283
points = ( self.winLine[0][0]*(self.boardSize/self.nbColumns)+self.stoneSize/2,
284
(self.boardSize/self.nbColumns)*(self.nbLines-1-self.winLine[0][1])+self.stoneSize/2,
285
self.winLine[1][0]*(self.boardSize/self.nbColumns)+self.stoneSize/2,
286
(self.boardSize/self.nbColumns)*(self.nbLines-1-self.winLine[1][1])+self.stoneSize/2
289
self.redLine = self.boardItem.add(
290
gnomecanvas.CanvasLine,
291
fill_color_rgba=0xFF0000FFL,
295
self.redLine.set_property("cap-style", gtk.gdk.CAP_ROUND)
297
gcompris.bonus.display(gcompris.bonus.WIN, gcompris.bonus.FLOWER)
299
gcompris.bonus.display(gcompris.bonus.LOOSE, gcompris.bonus.FLOWER)