Subversion Repositories pianoUtils

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

from collections import namedtuple
import random

class NoteTeacher:
    Level = namedtuple("Level", ("start_note", "counter", "notes", "desc"))
    Note = namedtuple("Note", ("clef", "tone"))
    
    G_NOTES = ["c1", "e1", "g1", "h1", "d2", "f2", "a2", # priority goes to notes on lines
                 "d1", "f1", "a1", "c2", "e2", "g2", "h2"]
    
    F_NOTES = ["c1", "a", "f", "d", "H", "G", "E", "C", # priority goes to notes on lines
                 "h", "g", "e", "c", "A", "F", "D"]
    
    ALL_NOTES = {"G": [Note(tone = tone, clef = "G") for tone in G_NOTES],
                 "F": [Note(tone = tone, clef = "F") for tone in F_NOTES]}
    
    LEVELS = (Level(start_note = "g1", counter = 8, notes = ALL_NOTES["G"], desc = "G clef with 2 notes at start"),
              Level(start_note = "d2", counter = 14, notes = ALL_NOTES["G"], desc = "G clef with 4 notes at start"),
              Level(start_note = "d1", counter = 20, notes = ALL_NOTES["G"], desc = "G clef with 7 notes at start"),
              Level(start_note = "e2", counter = 26, notes = ALL_NOTES["G"], desc = "G clef with 11 notes at start"),
              Level(start_note = None, counter = 32, notes = ALL_NOTES["G"], desc = "G clef with all notes at start"),
              Level(start_note = "f", counter = 8, notes = ALL_NOTES["F"], desc = "F clef with 2 notes at start"),
              Level(start_note = "H", counter = 14, notes = ALL_NOTES["F"], desc = "F clef with 4 notes at start"),
              Level(start_note = "h", counter = 20, notes = ALL_NOTES["F"], desc = "F clef with 8 notes at start"),
              Level(start_note = "A", counter = 26, notes = ALL_NOTES["F"], desc = "G clef with 12 notes at start"),
              Level(start_note = None, counter = 32, notes = ALL_NOTES["F"], desc = "G clef with all notes at start"),
              Level(start_note = None, counter = 38, notes = ALL_NOTES["G"] + ALL_NOTES["F"], desc = "both clefs with all notes at start")
             )
    
    def __init__(self, level = LEVELS[0]):
        self.counter = 0
        self.current_note = None
        self.statistics = {}
        
        self.max_count = 0 # initialized from level
        self.notes = [] # initialized from level
        self.available_notes = [] # initialized from level
        
        self.init_notes(level)
    
    def init_notes(self, level):
        if level.start_note is None:
            self.notes = []
            self.available_notes = level.notes[:]
        else:
            self.notes = level.notes[:]
            self.available_notes = []
            while self.notes[0].tone != level.start_note:
                self.available_notes.append(self.notes.pop(0))
        self.max_count = level.counter
        
        self.current_note = random.choice(self.available_notes)
    
    def next_note(self):
        self.current_note = random.choice(self.available_notes)
        
        self.counter += 1
        if self.counter == self.max_count and self.notes:
            self.available_notes.append(self.notes.pop(0))
            self.counter = 0
            self.max_count = int(self.max_count * 1.5)
    
    def check_note(self, note):
        result = note == self.current_note.tone
        
        self.statistics.setdefault(self.current_note, []).append(result)
        
        if result:
            # ak uhadnem notu 10x po sebe a ma zvysenu pravdepodobnost
            if all(self.statistics[self.current_note][-10:]) and self.available_notes.count(self.current_note) > 1:
                self.available_notes.remove(self.current_note)
            return True
        else:
            self.available_notes.append(self.current_note)
            self.max_count = int(self.max_count * 1.5)
            return False
    
    def get_progress(self):
        if not self.notes:
            return "inf"
        else:
            return "%d/%d"%(self.counter + 1, self.max_count)
    
    def output_statistics(self, statistics):
        data = self.statistics.items()
        data.sort(key = lambda x: (x[0].clef, self.ALL_NOTES[x[0].clef].index(x[0])))
        
        for note, wins in data:
            statistics.add(note.clef, note.tone, wins.count(False), len(wins))