Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ profile:
help:
PYTHONPATH=. $(PYTHON) wpm --help

redlist:
PYTHONPATH=. $(PYTHON) wpm --redlist

flush_redlist:
PYTHONPATH=. $(PYTHON) wpm --flush_redlist

dump:
PYTHONPATH=. $(PYTHON) tools/dumpdiffs.py

Expand Down
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ wpm confidence_level 0.95 The confidence level for WPM
wpm cpm 0 If positive, report CPM in stats instead of WPM
wpm tab_spaces 1 Number of spaces to expand tabs to
wpm wrap_width -1 If positive, wrap text at this width
wpm redlist_threshold 90 Minimum WPM to pass redlisted text
xterm256colors Color codes for 256-color terminals (foreground, background)
xtermcolors Color codes for ordinary terminals (foreground, background)
============== =========================== ======= =============================================================================
Expand Down
16 changes: 15 additions & 1 deletion wpm/commandline.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ def parse_args():

argp.add_argument("--monochrome", default=False, action="store_true",
help="Starts wpm with monochrome colors")

argp.add_argument("--redlist", default=False, action="store_true",
help="Starts wpm with redlisted texts. To redlist a text, press the \"up\" arrow key. To remove a texts from the redlist, complete each text fast enough or run wpm --flush_redlist.")

argp.add_argument("--flush_redlist", default=False, action="store_true",
help="Cleans the redlist.")



opts = argp.parse_args()

Expand All @@ -75,6 +83,10 @@ def parse_args():
print(wpm.__copyright__)
print("Source code (sans quotes) distributed under the %s" % wpm.__license__)
sys.exit(0)

if opts.flush_redlist:
wpm.quotes.Quotes.save_redlist({})
sys.exit(0)

opts.stats_file = os.path.expanduser(opts.stats_file)
return opts
Expand Down Expand Up @@ -243,6 +255,8 @@ def main():
if config.wpm.cpm:
opts.cpm = True

redlist_threshold = config.wpm.redlist_threshold

stats = load_stats(opts.stats_file, opts.tag)

if opts.load_json is not None:
Expand Down Expand Up @@ -274,7 +288,7 @@ def main():
sys.exit(1)

try:
with wpm.game.GameManager(quotes, stats, opts.cpm, opts.monochrome) as gm:
with wpm.game.GameManager(quotes, stats, opts.cpm, opts.monochrome, opts.redlist, redlist_threshold) as gm:
try:
gm.run(to_front=text_ids)
gm.stats.save(opts.stats_file)
Expand Down
1 change: 1 addition & 0 deletions wpm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def int_tuple(s):
"wrap_width": (int, -1, "Wrap text to this width"),
"tab_spaces": (int, 1, "Expand tabs to N spaces"),
"cpm": (int, 0, "Report CPM instead of WPM in stats"),
"redlist_threshold": (int, 90, "Minimum WPM to pass redlisted text"),
},

"xterm256colors": {
Expand Down
2 changes: 2 additions & 0 deletions wpm/data/redlist.pickle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(dp0
.
34 changes: 33 additions & 1 deletion wpm/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,26 @@
from wpm.config import Config
from wpm.record import Recorder
from wpm.screen import Screen
from wpm.quotes import Quotes

class GameManager(object):
"""The main game runner."""
def __init__(self, quotes, stats, cpm_flag, monochrome):

def __init__(self, quotes, stats, cpm_flag, monochrome, redlist_flag, redlist_threshold):

self.config = Config()
self.stats = stats
self.cpm_flag = cpm_flag
self.redlist_flag = redlist_flag
self.average = self.stats.average(self.stats.tag, last_n=10)
self.tab_spaces = None

self.redlist = Quotes.load_redlist()
self.redlist_threshold = redlist_threshold
if redlist_flag and not self.redlist:
print("Redlist is empty")
exit(0)

# Stats
self.position = 0
self.incorrect = 0
Expand All @@ -42,6 +52,9 @@ def __init__(self, quotes, stats, cpm_flag, monochrome):
self.num_quotes = len(quotes)
self.quotes = quotes.random_iterator()

if self.redlist_flag:
self.quotes.set_indices(self.redlist)

self.screen = Screen(monochrome)
self.set_quote(self.quotes.next())

Expand Down Expand Up @@ -70,6 +83,16 @@ def mark_finished(self):

self.average = self.stats.average(self.stats.tag, last_n=10)

if self.redlist_flag and self.wpm(self.elapsed) > self.redlist_threshold:
if self.quotes.text_id not in self.redlist:
return
self.redlist[self.quotes.text_id] -= 1
if self.redlist[self.quotes.text_id] <= 0:
self.redlist.pop(self.quotes.text_id)
Quotes.save_redlist(self.redlist)



def set_quote(self, quote):
"""Sets current quote."""
self.screen.redraw = True
Expand Down Expand Up @@ -242,6 +265,15 @@ def handle_key(self, key):
if key in (" ", "KEY_LEFT", "KEY_RIGHT"):
self.reset(direction=-1 if key == "KEY_LEFT" else 1)
return

if key in ("KEY_UP"):
if self.quotes.text_id in self.redlist:
self.redlist[self.quotes.text_id] += 1
else:
self.redlist[self.quotes.text_id] = 3
Quotes.save_redlist(self.redlist)
return

if Screen.is_escape(key):
# Exit program
raise KeyboardInterrupt()
Expand Down
38 changes: 36 additions & 2 deletions wpm/quotes.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import os
import random
import sys
import pickle

import pkg_resources

Expand Down Expand Up @@ -97,6 +98,10 @@ def put_to_front(self, text_ids):
random.shuffle(back)
self.indices = front + back
self.index = 0

def set_indices(self, redlist):
self.indices = list(redlist)
random.shuffle(self.indices)

@property
def database(self):
Expand All @@ -110,12 +115,12 @@ def text_id(self):

def next(self):
"""Goes to next quote."""
self.index = (self.index + 1) % len(self.quotes)
self.index = (self.index + 1) % len(self.indices)
return self.current()

def previous(self):
"""Goes back to previous quote."""
self.index = (self.index - 1) % len(self.quotes)
self.index = (self.index - 1) % len(self.indices)
return self.current()


Expand Down Expand Up @@ -206,6 +211,35 @@ def load(filename=None):
quotes = tuple(map(tuple, quotes))
return Quotes(quotes, database)

# Could have also implemented this inside the load, but I didn't want to mix JSON stuff with this.
@staticmethod
def load_redlist(filename=None):
"""Loads the dictionary of redlisted quotes."""
if filename is None:
filename = pkg_resources.resource_filename("wpm", "data/redlist.pickle")

# can also use os.open with O_CREATE etc.
try:
with open(filename, "rb") as file:
return pickle.load(file)

except IOError:
with open(filename, "wb+") as file:
pickle.dump({}, file)

with open(filename, "rb") as file:
return pickle.load(file)


@staticmethod
def save_redlist(redlist, filename=None):
"""Saves the dictionary of redlisted quotes."""
if filename is None:
filename = pkg_resources.resource_filename("wpm", "data/redlist.pickle")

with open(filename, "wb") as file:
pickle.dump(redlist, file)

def save(self, filename=None):
"""Saves current quotes to gzipped JSON file."""
if filename is None:
Expand Down