[Commits] typing-turtle branch master updated.

Wade Brainerd wadetb at gmail.com
Sun Jan 25 20:36:32 EST 2009


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "/home/olpc-code/git/activities/typing-turtle".

The branch, master has been updated
       via  fb0c2407556aa277601f3ba56714f7248b81998d (commit)
      from  4db028f22a08705880ea03342718cbecf05126c0 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

 TODO                       |   62 +++++++++++------------------
 balloongame.py             |   94 +++++++++++++++++++++++++++++---------------
 lessonbuilder              |    7 ++-
 lessons/en_US/MAKELESSONS  |    6 +++
 lessons/en_US/badwords.txt |    2 +
 lessonscreen.py            |   62 +++++++++++++++-------------
 6 files changed, 130 insertions(+), 103 deletions(-)

- Log -----------------------------------------------------------------
commit fb0c2407556aa277601f3ba56714f7248b81998d
Author: Wade Brainerd <wadetb at gmail.com>
Date:   Sun Jan 25 03:48:08 2009 +0000

    Fixed balloon flickering.
    Make WPM only count when you are typing.
    Wrote notes about how to handle capitals and punctuation.

diff --git a/TODO b/TODO
index 3fd9d08..5858c1c 100644
--- a/TODO
+++ b/TODO
@@ -1,47 +1,38 @@
 Typing Turtle
 
+Notes
+
+How to handle capitals and punctuation?
+
+Are capitals and punctuation universal concepts?  Certainly for all Roman languages.  
+Do other languages have capital-like and punctuation-like concepts with different rules?
+Is there a generic way that punctuation could just be handled naturally?
+  It depends on how nicely we want them to work.  For example knowing that you put quotes
+  around words, we can randomly enquote words.  Knowing that semicolons, periods and 
+  commas appear after words also allows us to randomly append them.
+  If we don't care, we can just suggest that a) punctuation be taught after the rest
+  of the alphabet, and b) native text be given which includes plenty of punctuation.
+Is there a generic way that we can handle capitalization?
+  It would be nice to just be able to capitalize the beginning of any word.
+  OTOH, acronyms and stuff would be nice to include and those will only come from 
+  wordlists.
+
+The answer to both: Right now, I think it's best to just encourage expansive word lists.
+Note that this means that we have top *stop* stripping non-alpha characters from words
+as we read them in!
+
+BTW, after all that work, when are we going to teach Enter?
+
 First Release
-- Write to Loser, Wes about developing artwork.
-- Draw incorrect characters in red.
-- Support backspace, backspace to previous lines.
-- Scrolling TextView in lesson.
-- Missing spaces at the end of some lines thanks to dodgy word wrap.
-- Handle ends of line in a sane manner.
-- Implement two step types: key learning and text copying.
-- Split text into lines for long lessons.
-- Try out an insensitive gtk.Entry instead of the gtk.Label.
-- Better flow at the end of a level.  Report the result on the Lesson screen: Need more work, Medal received, etc.
-- Ability of lessons to list medals in other lessons as prerequisites.  Disable unavailable lessons.
-- Some sort of lesson sorting criteria.
-- Split into file-per-screen.
-- Scroll lessons list to the first non-medaled lesson at startup.  Or just remember scroll position.
 + Status message on the main screen.  "You unlocked a new lesson!" for example.  Eventually have the turtle 'say' it.
-- Implement a long text copying lesson and fix bugs in the scrolling and typing.
 + Graphical WPM and accuracy meters.
-- WPM meter updated in 1sec timer in addition to on keypress.
-- Working medals assignment: "You got a medal!" popup, display next to lesson.
-- Nice looking keyboard.
-- Highlighted keyboard keys when pressed.
-- Support for displaying modifier keys in Keyboard.
-- Change key shown when modified is held.
-- Indicate next key to press on keyboard.
-- Translate keyboard to native key layout.
 + Make medal WPM adjustable somehow?  Perhaps a settable Goal WPM?
 + Highlight regions of keyboard, color by finger.
-+ Artwork and animations.
-  + Speed meter picture?
-  + Accuracy meter picture?
 + Sound effects.
   + Welcome to the activity sound.
   + Speed up / slow down sounds when WPM crosses threshold: Slow, Medium, Fast.
   + Medal award sounds for each medal type: None, Bronze, Silver, Gold.  Applause sound.
   + Incorrect key pressed tick sound. 
-+ Develop lessons.
-  - Continue to develop lessons for all keys on the keyboard.
-  - Develop 'focus' lessons e.g. fj.
-  - Mark some lessons as "locational" versus "textual" and translate from the English keyboard to native.  Ex: Home row, Left hand, Numbers, etc.
-  - Give each lesson criteria for each medal type based on Accuracy, WPM.
-- Automatically generate lessons similar to 'home row' based on a list of keys.
 
 Future Release
 + Goal support with progress reporting.  WPM, Accuracy, Entire keyboard learned, etc.
@@ -52,13 +43,6 @@ Future Release
 
 Balloon Game
 
-- Create BalloonGameScreen class (use gtk.Layout?).
-- Generate a list of random words, or read from lesson dictionary.
-- Score display.
-- Floating balloons with words on them.  Random velocities, "floaty" look.
-- Balloon letters disappear when typed.
-- Balloon pops when word typed, score increased.
-- Rate of balloons increases over time.
 + Game finished popup, displays score and medal text.
 + Fix flickering
 + Improve graphics.
diff --git a/balloongame.py b/balloongame.py
index 2550a0b..65ea6f8 100644
--- a/balloongame.py
+++ b/balloongame.py
@@ -23,9 +23,8 @@ import gobject, pygtk, gtk, pango
 # parameters about them.
 BALLOON_STAGES = [
     { 'count': 10, 'delay': 80 },
-#    { 'count': 20, 'delay': 40 },
-#    { 'count': 80, 'delay': 20 },
-#    { 'count': 100, 'delay': 10 },
+    { 'count': 20, 'delay': 60 },
+    { 'count': 70, 'delay': 40 },
 ]
 
 class Balloon:
@@ -35,7 +34,8 @@ class Balloon:
         self.vx = vx
         self.vy = vy
         self.word = word
-    
+        self.size = 100
+
 class BalloonGame(gtk.VBox):
     def __init__(self, lesson, activity):
         gtk.VBox.__init__(self)
@@ -84,17 +84,17 @@ class BalloonGame(gtk.VBox):
         self.finished = False
 
         # Start the animation loop running.        
-        self.update_timer = gobject.timeout_add(20, self.tick)
+        self.update_timer = gobject.timeout_add(20, self.tick, priority=gobject.PRIORITY_HIGH_IDLE+30)
     
     def realize_cb(self, widget):
         self.activity.add_events(gtk.gdk.KEY_PRESS_MASK)
         self.key_press_cb_id = self.activity.connect('key-press-event', self.key_cb)
 
         # Clear the mouse cursor. 
-        #pixmap = gtk.gdk.Pixmap(self.activity.window, 1, 1)
+        #pixmap = gtk.gdk.Pixmap(widget.window, 10, 10)
         #color = gtk.gdk.Color()
-        #cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 0, 0)
-        #self.area.window.set_cursor(cursor)
+        #cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 5, 5)
+        #widget.window.set_cursor(cursor)
         
     def unrealize_cb(self, widget):
         self.activity.disconnect(self.key_press_cb_id)
@@ -124,16 +124,22 @@ class BalloonGame(gtk.VBox):
             for b in self.balloons:
                 if b.word[0] == key:
                     b.word = b.word[1:]
-                    self.score += 10
+                    self.add_score(10)
 
                     # Pop the balloon if it's been typed.
                     if len(b.word) == 0:
                         self.balloons.remove(b)
-                        self.score += 100
+                        self.add_score(100)
+
+                    self.queue_draw_balloon(b)
+
+                    break
         
         return False
     
     def update_balloon(self, b):
+        self.queue_draw_balloon(b)
+        
         b.x += b.vx
         b.y += b.vy 
 
@@ -142,6 +148,8 @@ class BalloonGame(gtk.VBox):
 
         if b.y < -100:
             self.balloons.remove(b)
+
+        self.queue_draw_balloon(b)
     
     def tick(self):
         if self.finished:
@@ -170,7 +178,7 @@ class BalloonGame(gtk.VBox):
                 y = self.bounds.height + 100
 
                 vx = random.uniform(-2, 2)
-                vy = random.uniform(-5, -3)
+                vy = -3 #random.uniform(-5, -3)
 
                 b = Balloon(x, y, vx, vy, word)
                 self.balloons.append(b)
@@ -180,10 +188,8 @@ class BalloonGame(gtk.VBox):
 
         if len(self.balloons) == 0 and self.stage_idx >= len(BALLOON_STAGES):
             self.finished = True
+            self.queue_draw()
  
-        #self.queue_draw()
-        self.draw()
-
         return True
 
     def draw_results(self, gc):
@@ -210,13 +216,20 @@ class BalloonGame(gtk.VBox):
         ty = y+h/2-(size[1]/pango.SCALE)/2
         self.area.window.draw_layout(gc, tx, ty, layout)
 
+    def queue_draw_balloon(self, b):
+        x1 = int(b.x - b.size/2)
+        y1 = int(b.y - b.size/2)
+        x2 = int(b.x + b.size/2)
+        y2 = int(b.y + b.size/2)
+        self.queue_draw_area(x1, y1, x2, y2)
+
     def draw_balloon(self, gc, b):
         x = int(b.x)
         y = int(b.y)
         
         # Draw the balloon.
         gc.foreground = self.area.get_colormap().alloc_color(65535,0,0)
-        self.area.window.draw_arc(gc, True, x-50, y-50, 100, 100, 0, 360*64)
+        self.area.window.draw_arc(gc, True, x-b.size/2, y-b.size/2, b.size, b.size, 0, 360*64)
     
         # Draw the text.
         gc.foreground = self.area.get_colormap().alloc_color(0,0,0)
@@ -225,6 +238,37 @@ class BalloonGame(gtk.VBox):
         tx = x-(size[0]/pango.SCALE)/2
         ty = y-(size[1]/pango.SCALE)/2
         self.area.window.draw_layout(gc, tx, ty, layout)
+    
+    def add_score(self, num):
+        self.score += num
+        self.queue_draw_score()
+
+    def queue_draw_score(self):
+        layout = self.area.create_pango_layout(_('SCORE: %d') % self.score)
+        layout.set_font_description(pango.FontDescription('Times 14'))    
+        size = layout.get_size()
+        x = self.bounds.width-20-size[0]/pango.SCALE
+        y = 20
+        self.queue_draw_area(x, y, x+size[0], y+size[1])
+
+    def draw_score(self, gc):
+        layout = self.area.create_pango_layout(_('SCORE: %d') % self.score)
+        layout.set_font_description(pango.FontDescription('Times 14'))    
+        size = layout.get_size()
+        x = self.bounds.width-20-size[0]/pango.SCALE
+        y = 20
+        self.area.window.draw_layout(gc, x, y, layout)
+
+    def draw_instructions(self, gc):
+        # Draw instructions.
+        gc.foreground = self.area.get_colormap().alloc_color(0,0,0)
+
+        layout = self.area.create_pango_layout(_('Type the words to pop the balloons!'))
+        layout.set_font_description(pango.FontDescription('Times 14'))    
+        size = layout.get_size()
+        x = (self.bounds.width - size[0]/pango.SCALE)/2
+        y = self.bounds.height-20 - size[1]/pango.SCALE 
+        self.area.window.draw_layout(gc, x, y, layout)
 
     def draw(self):
         self.bounds = self.area.get_allocation()
@@ -243,23 +287,9 @@ class BalloonGame(gtk.VBox):
             self.draw_results(gc)
 
         else:
-            # Draw instructions.
-            gc.foreground = self.area.get_colormap().alloc_color(0,0,0)
-
-            layout = self.area.create_pango_layout(_('Type the words to pop the balloons!'))
-            layout.set_font_description(pango.FontDescription('Times 14'))    
-            size = layout.get_size()
-            x = (self.bounds.width - size[0]/pango.SCALE)/2
-            y = self.bounds.height-20 - size[1]/pango.SCALE 
-            self.area.window.draw_layout(gc, x, y, layout)
-
-            # Draw score.
-            layout = self.area.create_pango_layout(_('SCORE: %d') % self.score)
-            layout.set_font_description(pango.FontDescription('Times 14'))    
-            size = layout.get_size()
-            x = self.bounds.width-20-size[0]/pango.SCALE
-            y = 20
-            self.area.window.draw_layout(gc, x, y, layout)
+            self.draw_instructions(gc)
+
+            self.draw_score(gc)
 
     def expose_cb(self, area, event):
         self.draw()
diff --git a/lessonbuilder b/lessonbuilder
index df35fa1..83cc40b 100755
--- a/lessonbuilder
+++ b/lessonbuilder
@@ -202,8 +202,9 @@ def filter_pairs(pairs, required_keys, keys):
     return good_pairs
     
 def get_weighted_random_pair(pairs):
-    # TODO: I'm currently ignoring the weighting because it's preventing keys from
-    # ever appearing, for example j never appears in the home row lesson.
+    # TODO: I'm currently ignoring the weighting because it's preventing certain keys 
+    # from ever appearing due to their unpopularity, for example j never appears in the 
+    # home row lesson.
     return random.choice(pairs)
     #n = random.uniform(0, 1)
     #for p in pairs:
@@ -387,7 +388,7 @@ def build_intro_steps():
     steps = []
 
     text = ''
-    text += _('Hihowareyah!  Ready to learn the secret of fast typing?\n')
+    text += _('Hihowahyah!  Ready to learn the secret of fast typing?\n')
     text += _('Always use the correct finger to press each key!\n\n')
     text += _('Now, place your hands on the keyboard just like the picture below.\n')
     text += _('When you\'re ready, press the SPACE bar with your thumb!')
diff --git a/lessons/en_US/MAKELESSONS b/lessons/en_US/MAKELESSONS
index c5d4718..b5b8a23 100755
--- a/lessons/en_US/MAKELESSONS
+++ b/lessons/en_US/MAKELESSONS
@@ -12,6 +12,7 @@
     --desc="This lesson teaches you the a, s, d, f, g, h, j, k and l keys \nin the middle of the keyboard.\nThese keys are called the Home Row." \
     --keys="asdfghjkl" \
     --wordlist=2of12.txt \
+    --badwordlist=badwords.txt \
     --order=1 \
     --output=homerow.lesson
     
@@ -21,6 +22,7 @@
     --keys="asdfghjkl" \
     --game='balloon' \
     --wordlist=2of12.txt \
+    --badwordlist=badwords.txt \
     --order=2 \
     --output=homerowballoon.lesson
     
@@ -29,6 +31,7 @@
     --desc="This lesson teaches you the q, w, e, r, t, y, u, i, o and p keys \non the top row of the keyboard." \
     --keys="qwertyuiop" --base-keys="asdfghjkl" \
     --wordlist=2of12.txt \
+    --badwordlist=badwords.txt \
     --order=3 \
     --output=toprow.lesson
 
@@ -37,6 +40,7 @@
     --desc="This lesson teaches you the z, x, c, v, b, n and m keys \non the bottom row of the keyboard." \
     --keys="zxcvbnm" --base-keys="asdfghjklqwertyuiop" \
     --wordlist=2of12.txt \
+    --badwordlist=badwords.txt \
     --order=4 \
     --output=bottomrow.lesson
 
@@ -47,6 +51,7 @@
     --keys="QWERTASDFGZXCVB" \
     --base-keys="abcdefghijklmnopqrstuvwxyz" \
     --wordlist=2of12.txt \
+    --badwordlist=badwords.txt \
     --order=5 \
     --output=leftcapital.lesson
 
@@ -56,5 +61,6 @@
     --keys="YUIOPHJKLBNM" \
     --base-keys="abcdefghijklmnopqrstuvwxyzQWERTASDFGZXCVB" \
     --wordlist=2of12.txt \
+    --badwordlist=badwords.txt \
     --order=6 \
     --output=rightcapital.lesson
diff --git a/lessons/en_US/badwords.txt b/lessons/en_US/badwords.txt
index 2a549a7..ba09943 100644
--- a/lessons/en_US/badwords.txt
+++ b/lessons/en_US/badwords.txt
@@ -1,2 +1,4 @@
 coitus
 ass
+re
+ll
diff --git a/lessonscreen.py b/lessonscreen.py
index 7facc55..2fb9435 100644
--- a/lessonscreen.py
+++ b/lessonscreen.py
@@ -112,7 +112,6 @@ class LessonScreen(gtk.VBox):
         self.lessontext.set_right_margin(20)
         self.lessontext.set_wrap_mode(gtk.WRAP_WORD)
         self.lessontext.modify_base(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#ffffcc'))
-        #self.lessontext.modify_bg(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#ffff80'))
         
         self.lessonscroll = gtk.ScrolledWindow()
         self.lessonscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
@@ -134,17 +133,11 @@ class LessonScreen(gtk.VBox):
         self.connect('unrealize', self.unrealize_cb)
         
         self.show_all()
-        
-        # Load hand overlay SVGs.
-        bundle_path = sugar.activity.activity.get_bundle_path()
-        #for o in KEY_OVERLAYS.keys():
-        #    pass
+
+        self.timer_id = None
         
         self.begin_lesson()
         
-        # Initialize stats update timer.        
-        gobject.timeout_add(1000, self.timer_cb)
-
     def realize_cb(self, widget):
         self.activity.add_events(gtk.gdk.KEY_PRESS_MASK|gtk.gdk.KEY_RELEASE_MASK)
         self.key_press_cb_id = self.activity.connect('key-press-event', self.key_cb)
@@ -153,33 +146,41 @@ class LessonScreen(gtk.VBox):
     def unrealize_cb(self, widget):
         self.activity.disconnect(self.key_press_cb_id)
         self.activity.disconnect(self.key_release_cb_id)
-        
+
+    def start_timer(self):
+        self.start_time = time.time()
+        self.timer_id = gobject.timeout_add(1000, self.timer_cb)
+
+    def stop_timer(self):
+        if self.timer_id:
+            gobject.source_remove(self.timer_id)
+        self.start_time = None
+        self.timer_id = None
+
+    def timer_cb(self):
+        self.update_stats()
+        return True
+    
     def update_stats(self):
         if self.lesson_finished:
             return
         
         if self.start_time:
-            self.total_time = time.time() - self.start_time
-            
-            if self.total_time >= 1.0:
-                self.wpm = 60 * (self.correct_keys / 5) / self.total_time
-            else:
-                self.wpm = 1.0
-                
+            self.total_time += time.time() - self.start_time
+        self.start_time = time.time()
+
+        if self.total_time >= 1.0:
+            self.wpm = 60 * (self.correct_keys / 5) / self.total_time
             self.wpmlabel.set_markup(_('<b>WPM:</b> %(wpm)d') % { 'wpm': int(self.wpm) } )
+
         else:
-            self.total_time = 0.0
-            self.wpm = 100.0
-        
+            self.wpm = 1.0
+                
         if self.total_keys:                
             self.accuracy = 100.0 * self.correct_keys / self.total_keys
             
             self.accuracylabel.set_markup(_('<b>Accuracy:</b> %(accuracy)d%%') % { 'accuracy' : int(self.accuracy) } )
     
-    def timer_cb(self):
-        self.update_stats()
-        return True
-    
     def begin_lesson(self):
         self.lesson_finished = False
         
@@ -190,7 +191,8 @@ class LessonScreen(gtk.VBox):
         self.incorrect_keys = 0
         
         self.start_time = None
-        
+        self.total_time = 0
+
         self.step = None
         
         self.next_step_idx = 0
@@ -216,6 +218,9 @@ class LessonScreen(gtk.VBox):
         return new_lines
 
     def advance_step(self):
+        # Stop the WPM timer.
+        self.stop_timer()
+
         # Clear step related variables.
         self.step = None
         
@@ -324,7 +329,6 @@ class LessonScreen(gtk.VBox):
         self.line_idx = 0
         self.begin_line()
 
-            
     def begin_line(self):
         self.line = self.lines[self.line_idx]
         self.line_mark = self.line_marks[self.line_idx]
@@ -373,9 +377,9 @@ class LessonScreen(gtk.VBox):
                 self.total_keys += 1
         
         elif self.mode == 'text':
-            # Timer starts with first text mode keypress.
-            if not self.start_time:
-                self.start_time = time.time()
+            # WPM timer starts with first text mode keypress.
+            if not self.timer_id:
+                self.start_timer()
             
             # Handle backspace by deleting text and optionally moving up lines.
             if key_name == 'BackSpace':
-----------------------------------------------------------------------


--
/home/olpc-code/git/activities/typing-turtle


More information about the Commits mailing list