~e93b5ae3/+junk/github-import-readonly

1 by fossilet
Initial import
1
#!/usr/bin/env python
12 by fossilet
Better pygtk import method.
2
# -*- coding: utf-8 -*-
24 by Fossilet
l10n support towards next release; hint table improvement.
3
# pylint: disable-msg=r0201
12 by fossilet
Better pygtk import method.
4
"""
5
    4digits - A guess-the-number game, aka Bulls and Cows
40 by fossilet
1.0 release.
6
    Copyright (c) 2004-2011 Yongzhi Pan <http://fourdigits.sourceforge.net>
12 by fossilet
Better pygtk import method.
7
8
    4digits is a guess-the-number puzzle game. You are given eight times
9
    to guess a four-digit number. One digit is marked A if its value and
10
    position are both correct, and marked B if only its value is correct.
11
    You win the game when you get 4A0B. Good luck!
12
13
    4digits is free software; you can redistribute it and/or
14
    modify it under the terms of the GNU General Public License as
15
    published by the Free Software Foundation; either version 2 of
16
    the License, or (at your option) any later version.
17
18
    4digits is distributed in the hope that it will be useful,
19
    but WITHOUT ANY WARRANTY; without even the implied warranty of
22 by Fossilet
0.8 release.
20
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 by fossilet
Better pygtk import method.
21
    GNU General Public License for more details.
22
23
    You should have received a copy of the GNU General Public License
24
    along with 4digits; if not, write to the Free Software Foundation,
22 by Fossilet
0.8 release.
25
    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
12 by fossilet
Better pygtk import method.
26
"""
13 by fossilet
Updated doc. Improved glade file checking. (Kraus)
27
24 by Fossilet
l10n support towards next release; hint table improvement.
28
import os
26 by Fossilet
Version 0.9 release.
29
import cPickle
25 by Fossilet
Removed i18n stuff since I do not know how to make it work.
30
import random
37 by fossilet
Version 1.0 pre-release.
31
import pango
12 by fossilet
Better pygtk import method.
32
import sys
25 by Fossilet
Removed i18n stuff since I do not know how to make it work.
33
import time
34
import webbrowser
29 by usmarshal
Internationalization, MultiLanguage Support, ie. English and Chinese(Simple).
35
36
try:
36 by fossilet
Changed logo; remove other game modes. Start over.
37
    import pygtk
38
    pygtk.require('2.0')
39
    import gtk
40
    import gtk.glade
29 by usmarshal
Internationalization, MultiLanguage Support, ie. English and Chinese(Simple).
41
except ImportError:
36 by fossilet
Changed logo; remove other game modes. Start over.
42
    print _('python-gtk2 is required to run 4digits.')
43
    print _('No python-gtk2 was found on your system.')
22 by Fossilet
0.8 release.
44
    sys.exit(1)
45
36 by fossilet
Changed logo; remove other game modes. Start over.
46
__version__ = '1.0'
37 by fossilet
Version 1.0 pre-release.
47
__appdata_dir__ = os.path.join(os.path.expanduser('~'), '.4digits')
26 by Fossilet
Version 0.9 release.
48
__config_path__ = os.path.join(__appdata_dir__, 'prefs.pickle')
36 by fossilet
Changed logo; remove other game modes. Start over.
49
__prefs__ = {
26 by Fossilet
Version 0.9 release.
50
        'show toolbar': True,
51
        'show hint table': False,
36 by fossilet
Changed logo; remove other game modes. Start over.
52
        'auto fill hints': False
26 by Fossilet
Version 0.9 release.
53
        }
36 by fossilet
Changed logo; remove other game modes. Start over.
54
55
# The first is the current directory, so you do not have to install 
22 by Fossilet
0.8 release.
56
# 4digits to play it. The second is the installation directory.
26 by Fossilet
Version 0.9 release.
57
__gladefiles__ = [os.path.join(os.path.dirname(__file__), '4digits.glade'),
19 by Fossilet
Doc, script and code cleanup.
58
    os.path.normpath(os.path.join(
13 by fossilet
Updated doc. Improved glade file checking. (Kraus)
59
    os.path.dirname(__file__), '../share/4digits/4digits.glade'))]
37 by fossilet
Version 1.0 pre-release.
60
__helpfiles__ = [os.path.join(os.path.dirname(__file__), 'doc', 'index.html'),
17 by Fossilet
Updated doc, and improved auto filling.
61
    os.path.normpath(os.path.join(
62
    os.path.dirname(__file__), '../share/doc/4digits/index.html'))]
36 by fossilet
Changed logo; remove other game modes. Start over.
63
__score_filename__ = os.path.join(__appdata_dir__, '4digits.4digits.scores')
64
26 by Fossilet
Version 0.9 release.
65
# For future gettext support. I cannot figure out i18n now.
66
# I wish someone could help me with it.
36 by fossilet
Changed logo; remove other game modes. Start over.
67
try: 
68
    _()
69
except NameError:
70
    def _(arg):
71
        """Mark translatable strings."""
72
        return arg
73
74
def load_glade(dialog = None):
75
    """Try to load dialog from the different possible glade files."""
26 by Fossilet
Version 0.9 release.
76
    for gladefile in __gladefiles__:
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
77
        try:
36 by fossilet
Changed logo; remove other game modes. Start over.
78
            return gtk.glade.XML(gladefile, dialog) 
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
79
        except RuntimeError:
21 by Fossilet
Added gnome stock icon for scores, and an XPM logo.
80
            continue # Just ignore the error, the next file will be tested
81
    # Still here
36 by fossilet
Changed logo; remove other game modes. Start over.
82
    print "Gladefile not found! Checked paths were:"
26 by Fossilet
Version 0.9 release.
83
    print __gladefiles__
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
84
    sys.exit(2)
36 by fossilet
Changed logo; remove other game modes. Start over.
85
    
26 by Fossilet
Version 0.9 release.
86
87
class MainWindow(object):
88
    """The main game window."""
1 by fossilet
Initial import
89
    def __init__(self):
26 by Fossilet
Version 0.9 release.
90
        """GUI initialization."""
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
91
        self.widget_tree = load_glade()
92
        self.toolbar = self.widget_tree.get_widget('toolbar')
93
        self.view_toolbar = self.widget_tree.get_widget('view_toolbar')
26 by Fossilet
Version 0.9 release.
94
        self.hint_table = self.widget_tree.get_widget('hint_table')
95
        self.hint_hseparator = self.widget_tree.get_widget(
36 by fossilet
Changed logo; remove other game modes. Start over.
96
                'hint_hseparator')
26 by Fossilet
Version 0.9 release.
97
        self.view_hint_table = self.widget_tree.get_widget(
36 by fossilet
Changed logo; remove other game modes. Start over.
98
                'view_hint_table')
26 by Fossilet
Version 0.9 release.
99
        self.auto_fill_hints = self.widget_tree.get_widget(
36 by fossilet
Changed logo; remove other game modes. Start over.
100
                'view_auto_fill_hints')
37 by fossilet
Version 1.0 pre-release.
101
102
        # Input box
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
103
        self.entry = self.widget_tree.get_widget('entry')
1 by fossilet
Initial import
104
        self.entry.grab_focus()
37 by fossilet
Version 1.0 pre-release.
105
        fontsize = self.entry.get_pango_context().\
106
                get_font_description().get_size()/pango.SCALE
107
        self.entry.modify_font(pango.FontDescription(str(int(fontsize*3))))
108
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
109
        self.ok_button = self.widget_tree.get_widget('ok_button')
1 by fossilet
Initial import
110
        for widget in ('g0', 'g1', 'g2', 'g3', 'g4', 'g5', 'g6', 'g7',
36 by fossilet
Changed logo; remove other game modes. Start over.
111
                'r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7'):
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
112
            setattr(self, widget, self.widget_tree.get_widget(widget))
113
        self.info_label = self.widget_tree.get_widget('info_label')
114
        self.time_label = self.widget_tree.get_widget('time_label')
115
        self.score_view = self.widget_tree.get_widget('score_view')
26 by Fossilet
Version 0.9 release.
116
117
        self.cb_hint = [] # container for check boxes in the hint table
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
118
        self.label_hint = []
15 by Fossilet
Improved hint table.
119
        self.build_hint_table()
26 by Fossilet
Version 0.9 release.
120
121
        # parse preferences
122
        self.read_preferences_file()
36 by fossilet
Changed logo; remove other game modes. Start over.
123
        if __prefs__['show toolbar']:
26 by Fossilet
Version 0.9 release.
124
            self.toolbar.show()
125
            self.view_toolbar.set_active(True)
126
        else:
127
            self.toolbar.hide()
128
            self.view_toolbar.set_active(False)
36 by fossilet
Changed logo; remove other game modes. Start over.
129
        if __prefs__['show hint table']:
26 by Fossilet
Version 0.9 release.
130
            self.hint_table.show_all()
131
            self.hint_hseparator.show()
132
            self.view_hint_table.set_active(True)
133
        else:
134
            self.hint_table.hide_all()
135
            self.hint_hseparator.hide()
136
            self.view_hint_table.set_active(False)
36 by fossilet
Changed logo; remove other game modes. Start over.
137
        if __prefs__['auto fill hints']:
26 by Fossilet
Version 0.9 release.
138
            self.auto_fill_hints.set_active(True)
139
        else:
140
            self.auto_fill_hints.set_active(False)
36 by fossilet
Changed logo; remove other game modes. Start over.
141
        
26 by Fossilet
Version 0.9 release.
142
        # connect signals and callbacks
143
        dic = {'on_main_window_destroy': self.terminate_program,
144
                'on_quit_activate': self.terminate_program,
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
145
                'on_ok_clicked': self.on_entry_activate,
146
                'on_new_game_activate': self.on_new_game_activate,
1 by fossilet
Initial import
147
                'on_view_toolbar_toggled': self.on_view_toolbar_toggled,
26 by Fossilet
Version 0.9 release.
148
                'on_view_hint_table_toggled'
149
                : self.on_view_hint_table_toggled,
150
                'on_view_auto_fill_hints_toggled'
151
                : self.on_view_auto_fill_hints_toggled,
1 by fossilet
Initial import
152
                'on_entry_activate': self.on_entry_activate,
153
                'on_entry_changed': self.on_entry_changed,
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
154
                'on_help_activate' : self.on_help_activate,
155
                'on_about_activate' : self.on_about_activate,
156
                'on_score_activate': self.on_score_activate}
157
        self.widget_tree.signal_autoconnect(dic)
1 by fossilet
Initial import
158
        # new game initialization
19 by Fossilet
Doc, script and code cleanup.
159
        self.game = NewRound()
1 by fossilet
Initial import
160
26 by Fossilet
Version 0.9 release.
161
    def read_preferences_file(self):
162
        """Read preferences data from disk.
163
        Copied from Comix.
164
        """
165
        if os.path.isfile(__config_path__):
166
            try:
167
                config = open(__config_path__)
36 by fossilet
Changed logo; remove other game modes. Start over.
168
                old___prefs__ = cPickle.load(config)
26 by Fossilet
Version 0.9 release.
169
                config.close()
170
            except Exception:
36 by fossilet
Changed logo; remove other game modes. Start over.
171
                print 'Corrupted preferences file \
172
                "%s", deleting...' % __config_path__
26 by Fossilet
Version 0.9 release.
173
                os.remove(__config_path__)
174
            else:
36 by fossilet
Changed logo; remove other game modes. Start over.
175
                for key in old___prefs__:
176
                    if key in __prefs__:
177
                        __prefs__[key] = old___prefs__[key]
26 by Fossilet
Version 0.9 release.
178
179
    def write_preferences_file(self):
180
        """Write preference data to disk.
181
        Copied from Comix.
182
        """
183
        config = open(__config_path__, 'w')
36 by fossilet
Changed logo; remove other game modes. Start over.
184
        cPickle.dump(__prefs__, config, cPickle.HIGHEST_PROTOCOL)
26 by Fossilet
Version 0.9 release.
185
        config.close()
186
15 by Fossilet
Improved hint table.
187
    def build_hint_table(self):
26 by Fossilet
Version 0.9 release.
188
        """Create the controls for the hint table."""
189
        hint_table = self.widget_tree.get_widget('hint_table')
2 by fossilet
Added high score and hint table
190
        for name in (0, 40):
15 by Fossilet
Improved hint table.
191
            table = gtk.Table(rows=11, columns=6)
26 by Fossilet
Version 0.9 release.
192
            hint_table.pack_start(table)
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
193
21 by Fossilet
Added gnome stock icon for scores, and an XPM logo.
194
            # Create row labels
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
195
            for row in range(0, 10):
196
                label = gtk.CheckButton(str(row))
197
                table.attach(label, 0, 1, row+1, row+2)
198
                label.connect('toggled', self.change_row, row+name)
15 by Fossilet
Improved hint table.
199
                self.label_hint.append(label)
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
200
201
            for col in range(1, 5):
21 by Fossilet
Added gnome stock icon for scores, and an XPM logo.
202
                # Create column labels
37 by fossilet
Version 1.0 pre-release.
203
                #label = gtk.Label(str(col))
204
                #table.attach(label, col, col+1, 0, 1)
21 by Fossilet
Added gnome stock icon for scores, and an XPM logo.
205
                # Create Checkboxes
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
206
                for row in range(0, 10):
15 by Fossilet
Improved hint table.
207
                    checkbutton = gtk.CheckButton()
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
208
                    table.attach(checkbutton, col, col+1, row+1, row+2)
15 by Fossilet
Improved hint table.
209
                    self.cb_hint.append(checkbutton)
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
210
21 by Fossilet
Added gnome stock icon for scores, and an XPM logo.
211
            if name == 0: # First table
26 by Fossilet
Version 0.9 release.
212
                hint_table.pack_start(gtk.VSeparator())
15 by Fossilet
Improved hint table.
213
        self.init_hint_table()
2 by fossilet
Added high score and hint table
214
215
    def change_row(self, widget, row):
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
216
        """Toggle a rows state."""
15 by Fossilet
Improved hint table.
217
        enable = widget.get_active()
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
218
        for col in range(0, 4):
219
            self.cb_hint[10 * col + row].set_sensitive(enable)
15 by Fossilet
Improved hint table.
220
221
    def init_hint_table(self):
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
222
        """Reset all controls in the hinttable to their default state."""
15 by Fossilet
Improved hint table.
223
        for i in range(0, 40):
224
            self.cb_hint[i].set_active(True)
225
            self.cb_hint[i+40].set_active(False)
226
            self.cb_hint[i+40].set_sensitive(False)
227
        self.cb_hint[0].set_active(False)
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
228
        for row in range(0, 10):
229
            self.label_hint[row].set_active(True)
230
            self.label_hint[row+10].set_active(False)
36 by fossilet
Changed logo; remove other game modes. Start over.
231
    
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
232
    #         1    2    3    4                   1    2    3    4
233
    #  0/0    00   10   20   30          0/10    40   50   60   70
234
    #  1/1    01   11   21   31          1/11    41   51   61   71
235
    #  2/2    02   12   22   32          2/12    42   52   62   72
236
    # ...
22 by Fossilet
0.8 release.
237
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
238
    def get_checkbox(self, row, col, tablenr=0):
26 by Fossilet
Version 0.9 release.
239
        """Get the checkbox at the specified position."""
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
240
        return self.cb_hint[tablenr * 40 + col * 10 + row]
2 by fossilet
Added high score and hint table
241
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
242
    def get_label(self, row, tablenr=0):
26 by Fossilet
Version 0.9 release.
243
        """Get the label at the specified position."""
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
244
        return self.label_hint[tablenr*10 + row]
24 by Fossilet
l10n support towards next release; hint table improvement.
245
1 by fossilet
Initial import
246
    def on_entry_activate(self, widget):
26 by Fossilet
Version 0.9 release.
247
        """when input is accepted."""
248
        bulls, cows = 0, 0
1 by fossilet
Initial import
249
        number = ''
250
        # check input
251
        if self.game.guess < 8:
252
            number = self.entry.get_text()
253
            if number == '':
26 by Fossilet
Version 0.9 release.
254
                self.process_error(_('Must input something.'))
1 by fossilet
Initial import
255
                return False
256
            elif number[0] == '0':
26 by Fossilet
Version 0.9 release.
257
                self.process_error(_('First digit cannot be zero.'))
1 by fossilet
Initial import
258
                return False
259
            try:
260
                number = repr(int(number))
261
            except ValueError:
26 by Fossilet
Version 0.9 release.
262
                self.process_error(_('Must input a number.'))
1 by fossilet
Initial import
263
                return False
36 by fossilet
Changed logo; remove other game modes. Start over.
264
            if len(number) < 4:
265
                self.process_error(_('Must input four digits.'))
1 by fossilet
Initial import
266
                return False
36 by fossilet
Changed logo; remove other game modes. Start over.
267
            elif len(set(number)) < 4:
268
                self.process_error(_('Four digits must be unique.'))
1 by fossilet
Initial import
269
                return False
270
            elif number in self.game.guesses:
26 by Fossilet
Version 0.9 release.
271
                self.process_error(_("You've already guessed it."))
1 by fossilet
Initial import
272
                return False
273
            self.game.guesses.append(number)
274
            # process input
36 by fossilet
Changed logo; remove other game modes. Start over.
275
            for i in xrange(4):
276
                for j in xrange(4):
1 by fossilet
Initial import
277
                    if self.game.answer[i] == int(number[j]):
278
                        if i == j:
26 by Fossilet
Version 0.9 release.
279
                            bulls += 1
1 by fossilet
Initial import
280
                        else:
26 by Fossilet
Version 0.9 release.
281
                            cows += 1
1 by fossilet
Initial import
282
            guess_label = getattr(self, 'g' + repr(self.game.guess))
283
            result_label = getattr(self, 'r' + repr(self.game.guess))
284
            guess_label.set_text(number)
26 by Fossilet
Version 0.9 release.
285
            result_label.set_text('%dA%dB' % (bulls, cows))
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
286
26 by Fossilet
Version 0.9 release.
287
            if self.auto_fill_hints.get_active():
288
                self.fill_hints(number, bulls, cows)
36 by fossilet
Changed logo; remove other game modes. Start over.
289
            
1 by fossilet
Initial import
290
            # win
36 by fossilet
Changed logo; remove other game modes. Start over.
291
            if bulls == 4:
1 by fossilet
Initial import
292
                self.info_label.set_text(_('You win! :)'))
293
                self.get_time_taken_till_now()
36 by fossilet
Changed logo; remove other game modes. Start over.
294
                self.time_label.set_text(_('Used %.1f s.') % 
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
295
                    self.game.time_taken)
296
                self.ok_button.set_sensitive(False)
1 by fossilet
Initial import
297
                self.entry.set_sensitive(False)
298
                if self.is_high_score(self.game.time_taken):
3 by fossilet
Minor tweaking at GUI
299
                    new_score_rank = self.write_score(self.game.time_taken)
300
                    self.show_score(new_score_rank)
1 by fossilet
Initial import
301
            # lose
302
            elif self.game.guess == 7:
303
                answer = ''
36 by fossilet
Changed logo; remove other game modes. Start over.
304
                for i in xrange(4):
1 by fossilet
Initial import
305
                    answer += repr(self.game.answer[i])
36 by fossilet
Changed logo; remove other game modes. Start over.
306
                self.info_label.set_text(_('Haha, you lose. It is %s.') % 
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
307
                    answer)
1 by fossilet
Initial import
308
                self.get_time_taken_till_now()
36 by fossilet
Changed logo; remove other game modes. Start over.
309
                self.time_label.set_text(_('Wasted %.1f s.') % 
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
310
                    self.game.time_taken)
311
                self.ok_button.set_sensitive(False)
1 by fossilet
Initial import
312
                self.entry.set_sensitive(False)
313
        self.game.guess += 1
314
        self.entry.grab_focus()
315
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
316
    def clear_row(self, row):
26 by Fossilet
Version 0.9 release.
317
        """Clear a complete row."""
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
318
        self.get_label(row, 0).set_active(False)
319
        for col in range(0, 4):
320
            self.get_checkbox(row, col, 0).set_active(False)
321
            self.get_checkbox(row, col, 1).set_active(False)
322
26 by Fossilet
Version 0.9 release.
323
    def fill_hints(self, number, bulls, cows):
324
        """Auto filling some obvious cases in the hint table."""
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
325
        number = [int(x) for x in number]
26 by Fossilet
Version 0.9 release.
326
        if bulls == 0 and cows == 0:
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
327
            for digit in number:
328
                self.clear_row(digit)
329
            return
330
26 by Fossilet
Version 0.9 release.
331
        if bulls+cows == 4:
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
332
            for digit in range(0, 10):
333
                if digit in number:
334
                    self.get_label(digit, 0).set_active(True)
335
                    self.get_label(digit, 1).set_active(True)
336
                else:
337
                    self.clear_row(digit)
338
26 by Fossilet
Version 0.9 release.
339
        if bulls == 0: # Only cows
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
340
            for digit_pos in range(0, 4):
36 by fossilet
Changed logo; remove other game modes. Start over.
341
                self.get_checkbox(number[digit_pos], digit_pos, 
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
342
                    0).set_active(False)
36 by fossilet
Changed logo; remove other game modes. Start over.
343
                self.get_checkbox(number[digit_pos], digit_pos, 
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
344
                    1).set_active(False)
345
26 by Fossilet
Version 0.9 release.
346
        if cows == 0: # Only bulls
24 by Fossilet
l10n support towards next release; hint table improvement.
347
        # Only digits which are either in the right place or completely wrong
23 by Fossilet
Final 0.8 release.
348
            for digit_pos in range(0, 4):
349
                for pos2 in range(0, 4):
350
                    if pos2 == digit_pos:
351
                        continue
24 by Fossilet
l10n support towards next release; hint table improvement.
352
                    # uncheck impossible boxes in first column
36 by fossilet
Changed logo; remove other game modes. Start over.
353
                    self.get_checkbox(number[digit_pos], pos2, 
23 by Fossilet
Final 0.8 release.
354
                        0).set_active(False)
355
1 by fossilet
Initial import
356
    def on_entry_changed(self, widget):
26 by Fossilet
Version 0.9 release.
357
        """Start timer as soon as the user enters the first digit."""
1 by fossilet
Initial import
358
        self.info_label.set_text('')
26 by Fossilet
Version 0.9 release.
359
        if self.game.on_entry_cb_first_called == True:
1 by fossilet
Initial import
360
            self.time_label.set_text(_('Timer started...'))
361
            self.game.time_start = time.time()
26 by Fossilet
Version 0.9 release.
362
            self.game.on_entry_cb_first_called = False
36 by fossilet
Changed logo; remove other game modes. Start over.
363
  
1 by fossilet
Initial import
364
    def on_view_toolbar_toggled(self, widget):
26 by Fossilet
Version 0.9 release.
365
        """Toggle toolbar visibility."""
366
        if self.toolbar.get_property('visible'):
367
            self.toolbar.hide()
36 by fossilet
Changed logo; remove other game modes. Start over.
368
            __prefs__['show toolbar'] = False
26 by Fossilet
Version 0.9 release.
369
        else:
1 by fossilet
Initial import
370
            self.toolbar.show()
36 by fossilet
Changed logo; remove other game modes. Start over.
371
            __prefs__['show toolbar'] = True
1 by fossilet
Initial import
372
2 by fossilet
Added high score and hint table
373
    def on_view_hint_table_toggled(self, widget):
26 by Fossilet
Version 0.9 release.
374
        """Toggle hint table visibility."""
375
        if self.hint_table.get_property('visible'):
376
            self.hint_table.hide_all()
377
            self.hint_hseparator.hide()
36 by fossilet
Changed logo; remove other game modes. Start over.
378
            __prefs__['show hint table'] = False
26 by Fossilet
Version 0.9 release.
379
        else:
2 by fossilet
Added high score and hint table
380
            self.hint_table.show_all()
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
381
            self.hint_hseparator.show()
36 by fossilet
Changed logo; remove other game modes. Start over.
382
            __prefs__['show hint table'] = True
383
    
26 by Fossilet
Version 0.9 release.
384
    def on_view_auto_fill_hints_toggled(self, widget):
385
        """Toggle auto filling of hint table."""
386
        if self.auto_fill_hints.get_active():
36 by fossilet
Changed logo; remove other game modes. Start over.
387
            __prefs__['auto fill hints'] = True
26 by Fossilet
Version 0.9 release.
388
        else:
36 by fossilet
Changed logo; remove other game modes. Start over.
389
            __prefs__['auto fill hints'] = False
26 by Fossilet
Version 0.9 release.
390
25 by Fossilet
Removed i18n stuff since I do not know how to make it work.
391
    @classmethod
392
    def on_help_activate(cls, widget):
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
393
        """Show help."""
26 by Fossilet
Version 0.9 release.
394
        for helpfile in __helpfiles__:
17 by Fossilet
Updated doc, and improved auto filling.
395
            try:
396
                file(helpfile)
397
            except IOError:
398
                continue
22 by Fossilet
0.8 release.
399
            webbrowser.open(helpfile)
1 by fossilet
Initial import
400
25 by Fossilet
Removed i18n stuff since I do not know how to make it work.
401
    @classmethod
402
    def on_about_activate(cls, widget):
26 by Fossilet
Version 0.9 release.
403
        """Show about dialog."""
19 by Fossilet
Doc, script and code cleanup.
404
        about = AboutDialog().about_dialog
1 by fossilet
Initial import
405
        about.run()
406
        about.destroy()
36 by fossilet
Changed logo; remove other game modes. Start over.
407
    
25 by Fossilet
Removed i18n stuff since I do not know how to make it work.
408
    @classmethod
409
    def on_score_activate(cls, new_score_rank):
26 by Fossilet
Version 0.9 release.
410
        """Show high scores."""
21 by Fossilet
Added gnome stock icon for scores, and an XPM logo.
411
        score_dialog = ScoreDialog()
412
        dlg = score_dialog.score_dialog
36 by fossilet
Changed logo; remove other game modes. Start over.
413
        score_view = score_dialog.score_view
414
        sv_selection = score_view.get_selection()
415
        sv_selection.set_mode(gtk.SELECTION_NONE)
416
        column = gtk.TreeViewColumn(
417
                _('Name'), gtk.CellRendererText(), text = 0)
418
        score_view.append_column(column)
419
        column = gtk.TreeViewColumn(
420
                _('Score'), gtk.CellRendererText(), text = 1)
421
        score_view.append_column(column)
422
        column = gtk.TreeViewColumn(
423
                _('Date'), gtk.CellRendererText(), text = 2)
424
        score_view.append_column(column)
425
        dlg.scoreList = gtk.ListStore(str, str, str)
426
        score_view.set_model(dlg.scoreList)
427
428
        try:
429
            scores = [line.split(' ', 6) 
430
                    for line in file(__score_filename__, 'r')]
431
        except IOError:
432
            scores = []
433
434
        for line in scores:
435
            score_tup = line[0], line[1], ' '.join(line[2:]).rstrip('\n')
436
            dlg.scoreList.append(score_tup)
437
        # high light the current high score entry
438
        try:
439
            sv_selection.set_mode(gtk.SELECTION_SINGLE)
440
            sv_selection.select_path(new_score_rank)
441
        except TypeError:
442
            sv_selection.set_mode(gtk.SELECTION_NONE)
443
1 by fossilet
Initial import
444
        dlg.run()
445
        dlg.destroy()
446
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
447
    def on_new_game_activate(self, widget):
26 by Fossilet
Version 0.9 release.
448
        """New game initialization."""
19 by Fossilet
Doc, script and code cleanup.
449
        self.game = NewRound()
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
450
        self.ok_button.set_sensitive(True)
1 by fossilet
Initial import
451
        self.entry.set_sensitive(True)
452
        self.entry.grab_focus()
453
        # won't start the timer when you just start a new game
26 by Fossilet
Version 0.9 release.
454
        self.game.on_entry_cb_first_called = False
1 by fossilet
Initial import
455
        self.entry.set_text('')
26 by Fossilet
Version 0.9 release.
456
        self.game.on_entry_cb_first_called = True
1 by fossilet
Initial import
457
        self.info_label.set_text(_('Ready'))
458
        self.time_label.set_text('')
459
460
        for i in xrange(8):
461
            getattr(self, 'g' + repr(i)).set_text('')
462
            getattr(self, 'r' + repr(i)).set_text('')
36 by fossilet
Changed logo; remove other game modes. Start over.
463
        
15 by Fossilet
Improved hint table.
464
        self.init_hint_table()
2 by fossilet
Added high score and hint table
465
26 by Fossilet
Version 0.9 release.
466
    def process_error(self, msg):
467
        """Show error message in statusbar."""
1 by fossilet
Initial import
468
        self.info_label.set_text(msg)
469
        self.entry.grab_focus()
470
471
    def get_time_taken_till_now(self):
26 by Fossilet
Version 0.9 release.
472
        """Get time since start of the game."""
1 by fossilet
Initial import
473
        self.game.time_end = time.time()
474
        self.game.time_taken = self.game.time_end - self.game.time_start
475
        self.game.time_taken = round(self.game.time_taken, 1)
476
25 by Fossilet
Removed i18n stuff since I do not know how to make it work.
477
    @classmethod
478
    def is_high_score(cls, time_taken):
26 by Fossilet
Version 0.9 release.
479
        """Is this time a highscore."""
15 by Fossilet
Improved hint table.
480
        try:
36 by fossilet
Changed logo; remove other game modes. Start over.
481
            scores = [line.split(' ', 6) 
482
                    for line in file(__score_filename__, 'r')]
15 by Fossilet
Improved hint table.
483
        except IOError:
21 by Fossilet
Added gnome stock icon for scores, and an XPM logo.
484
            return True # List does not exist yet
2 by fossilet
Added high score and hint table
485
        if len(scores) < 10:
486
            return True
487
        scores = sorted(scores, key = lambda x: float(x[1][:-1]))
488
        if time_taken < float(scores[-1][1][:-1]):
1 by fossilet
Initial import
489
            return True
490
        else:
491
            return False
492
25 by Fossilet
Removed i18n stuff since I do not know how to make it work.
493
    @classmethod
494
    def write_score(cls, time_taken):
26 by Fossilet
Version 0.9 release.
495
        """Write highscore file."""
36 by fossilet
Changed logo; remove other game modes. Start over.
496
        date = time.strftime("%a %b %d %H:%M:%S %Y") 
12 by fossilet
Better pygtk import method.
497
        new_score = "%s %ss %s\n" % (
19 by Fossilet
Doc, script and code cleanup.
498
                os.getenv('USERNAME'), time_taken, date)
15 by Fossilet
Improved hint table.
499
        try:
36 by fossilet
Changed logo; remove other game modes. Start over.
500
            saved_scores = open(__score_filename__, 'r').readlines()
15 by Fossilet
Improved hint table.
501
        except IOError:
36 by fossilet
Changed logo; remove other game modes. Start over.
502
            saved_scores = [] 
2 by fossilet
Added high score and hint table
503
        saved_scores.append(new_score)
504
        scores = [line.split(' ', 6) for line in saved_scores]
505
        scores = sorted(scores, key = lambda x: float(x[1][:-1]))
506
        scores = scores[:10]
3 by fossilet
Minor tweaking at GUI
507
508
        # find the index of the new score
509
        new_score = new_score.split(' ', 6)
510
        new_score_rank = scores.index(new_score)
15 by Fossilet
Improved hint table.
511
        try:
36 by fossilet
Changed logo; remove other game modes. Start over.
512
            scorefile = open(__score_filename__, 'w')
15 by Fossilet
Improved hint table.
513
        except IOError:
514
            # Most likely the directory does not exist
36 by fossilet
Changed logo; remove other game modes. Start over.
515
            new_dir = os.path.dirname(__score_filename__)
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
516
            os.mkdir(new_dir)
36 by fossilet
Changed logo; remove other game modes. Start over.
517
            scorefile = open(__score_filename__, 'w') # Try again
2 by fossilet
Added high score and hint table
518
        for score in scores:
26 by Fossilet
Version 0.9 release.
519
            scorefile.write(' '.join(score))
520
        scorefile.close()
3 by fossilet
Minor tweaking at GUI
521
        return new_score_rank
1 by fossilet
Initial import
522
3 by fossilet
Minor tweaking at GUI
523
    def show_score(self, new_score_rank):
26 by Fossilet
Version 0.9 release.
524
        """Show highscore dialog."""
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
525
        self.on_score_activate(new_score_rank)
36 by fossilet
Changed logo; remove other game modes. Start over.
526
    
26 by Fossilet
Version 0.9 release.
527
    def terminate_program(self, widget):
528
        """Run clean-up tasks and exit.
36 by fossilet
Changed logo; remove other game modes. Start over.
529
        Copied from comix.        
26 by Fossilet
Version 0.9 release.
530
        """
531
        self.write_preferences_file()
532
        gtk.main_quit()
533
36 by fossilet
Changed logo; remove other game modes. Start over.
534
25 by Fossilet
Removed i18n stuff since I do not know how to make it work.
535
class AboutDialog(object):
26 by Fossilet
Version 0.9 release.
536
    """The about dialog."""
1 by fossilet
Initial import
537
    def __init__(self):
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
538
        self.widget_tree = load_glade('about_dialog')
539
        self.about_dialog = self.widget_tree.get_widget("about_dialog")
12 by fossilet
Better pygtk import method.
540
        gtk.about_dialog_set_url_hook(
541
                lambda about_dialog, url: webbrowser.open(url))
22 by Fossilet
0.8 release.
542
        self.about_dialog.set_website(
543
                'http://fourdigits.sourceforge.net')
544
        self.about_dialog.set_website_label(
545
                'http://fourdigits.sourceforge.net')
1 by fossilet
Initial import
546
26 by Fossilet
Version 0.9 release.
547
25 by Fossilet
Removed i18n stuff since I do not know how to make it work.
548
class ScoreDialog(object):
26 by Fossilet
Version 0.9 release.
549
    """The score dialog."""
1 by fossilet
Initial import
550
    def __init__(self):
16 by Fossilet
Auto filling of hint table and code cleanup by Hermann.
551
        self.widget_tree = load_glade('score_dialog')
552
        self.score_dialog = self.widget_tree.get_widget('score_dialog')
553
        self.score_view = self.widget_tree.get_widget('score_view')
1 by fossilet
Initial import
554
26 by Fossilet
Version 0.9 release.
555
25 by Fossilet
Removed i18n stuff since I do not know how to make it work.
556
class NewRound(object):
26 by Fossilet
Version 0.9 release.
557
    """Contains data in one round of the game."""
1 by fossilet
Initial import
558
    def __init__(self):
559
        while True:
36 by fossilet
Changed logo; remove other game modes. Start over.
560
            self.answer = random.sample(range(10), 4)
26 by Fossilet
Version 0.9 release.
561
            if self.answer[0] != 0: # first digit cannot be zero
1 by fossilet
Initial import
562
                break
40 by fossilet
1.0 release.
563
        #print self.answer
17 by Fossilet
Updated doc, and improved auto filling.
564
        if self.answer == [4, 6, 1, 9]:
26 by Fossilet
Version 0.9 release.
565
            gtk.MessageDialog(message_format
566
                    ='4619: You are the luckiest guy on the planet!').show()
1 by fossilet
Initial import
567
        self.guess = 0
568
        self.guesses = []
569
        self.time_start = 0
570
        self.time_end = 0
571
        self.time_taken = 0
26 by Fossilet
Version 0.9 release.
572
        self.on_entry_cb_first_called = True
1 by fossilet
Initial import
573
574
if __name__ == "__main__":
26 by Fossilet
Version 0.9 release.
575
    MainWindow()
1 by fossilet
Initial import
576
    gtk.main()