Documentation
¶
Index ¶
- Constants
- Variables
- func DedupCleanLetters(str string) string
- func InitQuoteTrainingResults(userAnswerStr string, realAnswerStr string) (displayedResults string, corrects int, total int)
- func NewLetterModel(trainingLetters string, lettersUsed string, speed float64, backRef tea.Model) *letterModel
- func NewQuoteModel(quote string, speed float64, backReference tea.Model) *quoteModel
- func NewWordModel(words []string, maxLen uint16, charGap uint16, speed float64, ...) *wordModel
Constants ¶
View Source
const ( PLAYING_STOP playingSignal = iota PLAYING_START )
Variables ¶
View Source
var Cmd = &cobra.Command{
Use: "decode",
Short: "Drills for decoding the morse code alphabet",
Long: `This is the subcommand for decoding the morse code alphabet, from letters to sentences.
These are the three things the user can do in here:
- 'dihdah decode letters': Gives the user drills to decode the morse code alphabet.
- 'dihdah decode words': Gives the user drills to be proficient on decoding morse code words.
- 'dihdah decode quotes': Gives the user drills to be proficient on decoding morse code sentences.
Run either 'dihdah decode letters --help', 'dihdah decode words --help', or
'dihdah decode quotes --help' for more details.`,
}
View Source
var LetterCmd = &cobra.Command{ Use: "letter", Short: "Train for decoding letters.", Aliases: []string{"letters"}, RunE: func(cmd *cobra.Command, args []string) error { detectedNonAlphabet := false letters, _ := cmd.Flags().GetString("letters") if len(letters) != 0 { letters = DedupCleanLetters(letters) } if detectedNonAlphabet { if len(letters) == 0 { return fmt.Errorf("Error: --letters has effectively nothing in it.") } else { cmd.PrintErrln("Warning: Detected non-alphabet characters in --letters, removing...") } } if len(letters) == 0 { levelArg, _ := cmd.Flags().GetUint16("level") if int(levelArg) > len(NewLettersPerLevel) { cmd.PrintErrf("Warning: Level is at most %v. Will be set to max.\n", len(NewLettersPerLevel)) levelArg = uint16(len(NewLettersPerLevel)) } if levelArg == 0 { return fmt.Errorf("Error: --letters is empty.") } for i := range levelArg { letters += NewLettersPerLevel[i] } } dedupedLetters := DedupCleanLetters(letters) speed, _ := cmd.Flags().GetFloat64("speed") doAllLetters, _ := cmd.Flags().GetBool("recap") if doAllLetters { allLettersRand := []rune(dedupedLetters) rand.Shuffle(len(allLettersRand), func(i, j int) { allLettersRand[i], allLettersRand[j] = allLettersRand[j], allLettersRand[i] }) p := tea.NewProgram(NewLetterModel(string(allLettersRand), dedupedLetters, speed, nil)) if _, err := p.Run(); err != nil { return fmt.Errorf("Error running the program: %v", err) } return nil } iterations, _ := cmd.Flags().GetUint("iterations") if iterations == 0 { iterations = max(uint(len(dedupedLetters)/2), 3) } trainingLetters := "" for range iterations { randomLetter := letters[rand.Intn(len(letters))] trainingLetters += string(randomLetter) } p := tea.NewProgram(NewLetterModel(trainingLetters, dedupedLetters, speed, nil)) if _, err := p.Run(); err != nil { return fmt.Errorf("Error running the program: %v", err) } return nil }, Long: `The 'decode letters' command gives the user drills to decode the morse code alphabet. The flags in this command should be self-explanatory. # How it works For each item, you will be given a sound clip to listen. Input the letter corresponding to the sound. Pressing space or hitting enter when empty will repeat the sound. Enter to confirm the answer. ==================================================================== Decode training (3 letters) (1 of 3) > t (escape/ctrl+c to go back, space to repeat sound, enter to confirm) ==================================================================== At the end of the training session, you will be presented with the correct characters played. Use that as learning and/or feedback for the next training. ===================================================== Decoding training results (3 letters, 3 iterations): # Character Correct? Answered 1 t yes t 2 e yes e 3 e yes e (all correct!) (escape / ctrl+c / enter to go back) ===================================================== # Extras This is the default letter pool if you specify --level/-l: ======================================== | Level | Letter Pool | | ----- | ---------------------------- | | 1 | the | | 2 | thedog | | 3 | thedogbrown | | 4 | thedogbrownjumps | | 5 | thedogbrownjumpsfoxover | | 6 | thedogbrownjumpsfoxoverquick | | 7+ | (everything) | ======================================== NOTES: - If the user is having difficulty differentiating letters, it is recommended to run this command with --letters. - After being comfortable with a certain --level, it is also recommended to run --level with --recap before proceeding with the next --level. - For the convenience and the challenge for the user, --speed can be used to slow down or speed up the sound being played.`, }
View Source
var NewLettersPerLevel = [...]string{
"the",
"dog",
"brown",
"jumps",
"foxover",
"quick",
"lazy",
}
View Source
var QuoteCmd = &cobra.Command{ Use: "quote", Short: "Train for decoding quotes.", Aliases: []string{"quotes"}, RunE: func(cmd *cobra.Command, args []string) error { quotesFile, _ := cmd.Flags().GetString("quotes") fileReader := io.Reader(strings.NewReader(assets.Quotes)) if len(quotesFile) != 0 { file, err := os.Open(quotesFile) if err != nil { return fmt.Errorf("Error reading %v: %v", quotesFile, err) } defer file.Close() fileReader = io.Reader(file) } else { quotesFile = "(the default quotes file)" } quotes := []string(nil) scanner := bufio.NewScanner(fileReader) for scanner.Scan() { quote := strings.TrimSpace(scanner.Text()) hasContent := false for _, r := range quote { if r >= 'a' && r <= 'z' { hasContent = true break } if r >= 'A' && r <= 'Z' { hasContent = true break } } if hasContent { quotes = append(quotes, quote) } } if err := scanner.Err(); err != nil { return fmt.Errorf("Error scanning %v: %v", quotesFile, err) } if len(quotes) == 0 { return fmt.Errorf("Error reading %v: File is empty", quotesFile) } randomQuote := quotes[rand.Intn(len(quotes))] speed, _ := cmd.Flags().GetFloat64("speed") if speed == 0 { return fmt.Errorf("Speed must not be zero.") } p := tea.NewProgram(NewQuoteModel(randomQuote, speed, nil)) if _, err := p.Run(); err != nil { return fmt.Errorf("Error running the program: %v", err) } return nil }, Long: `The 'decode quotes' command gives the user drills to decode sentences. The flags should be self-explanatory. # How it works You will be given a long sound clip, which is an encoded morse code sentence. Ctrl+l will either stop or play the clip. Ctrl+c will either clear your input or go back. Ctrl+s will confirm your input. =========================================================================================== Decode quote training ┃ 1 ????? ┃ ┃ ┃ ┃ ┃ (ctrl+l to stop/restart playing, ctrl+s to confirm answer, ctrl+c/esc to clear or go back) =========================================================================================== At the end of the training session, you will be presented with the correct quote played. Use that as learning and/or feedback for the next training session. ========================================= Decode quote training results Do all things with love. - Og Mandino ? ? >> do nll things_with love og mandino (1/28 mistakes) (ctrl+c/esc to go back) ========================================= NOTE: - For the convenience and challenge, --speed can be used to slow down or speed up the sound being played.`, }
View Source
var WordCmd = &cobra.Command{ Use: "word", Short: "Train for decoding words.", Aliases: []string{"words"}, RunE: func(cmd *cobra.Command, args []string) error { iterations, _ := cmd.Flags().GetUint16("iterations") if iterations == 0 { return fmt.Errorf("--iterations is set to zero.") } levelArg, _ := cmd.Flags().GetUint16("level") wordLength, _ := cmd.Flags().GetUint16("w-length") charGap, gapGetErr := cmd.Flags().GetUint16("gap") if wordLength == 0 { if levelArg == 0 { return fmt.Errorf("--level and --w-length are both set to zero.\n") } if int(levelArg) > len(WordOptPerLevel) { cmd.PrintErrf("Warning: Max level for decoding words is %v.\n", len(WordOptPerLevel)) levelArg = uint16(len(WordOptPerLevel)) } wordLength = WordOptPerLevel[levelArg-1].MaxLen if gapGetErr != nil { charGap = WordOptPerLevel[levelArg-1].CharGap } } speed, _ := cmd.Flags().GetFloat64("speed") charGapInSeconds := float64(time.Duration(charGap)*commons.DefaultDitDuration) * speed if charGapInSeconds > float64(time.Second*10) || charGap < commons.CharGapMinimum { return fmt.Errorf("--gap is invalid (either too long or is zero)\n") } wordFile, _ := cmd.Flags().GetString("words") fileReader := io.Reader(strings.NewReader(assets.Words)) if len(wordFile) != 0 { file, err := os.Open(wordFile) if err != nil { return fmt.Errorf("Error opening %v: %v\n", wordFile, file) } defer file.Close() fileReader = io.Reader(file) } else { wordFile = "(the default word file)" } wordPool := []string(nil) scanner := bufio.NewScanner(fileReader) scanner.Split(bufio.ScanWords) for scanner.Scan() { word := scanner.Text() word = strings.Map(func(r rune) rune { if r >= 'a' && r <= 'z' { return r } if r >= 'A' && r <= 'Z' { return r } if r == '-' { return r } return -1 }, word) if len(word) <= int(wordLength) || int(wordLength) >= len(WordOptPerLevel) { wordPool = append(wordPool, word) } } if err := scanner.Err(); err != nil { return fmt.Errorf("Error reading through %v: %v", wordFile, err) } words := []string(nil) for range min(len(wordPool), int(iterations)) { wordIdx := rand.Intn(len(wordPool)) words = append(words, wordPool[wordIdx]) wordPool[wordIdx] = wordPool[len(wordPool)-1] wordPool = wordPool[:len(wordPool)-1] } p := tea.NewProgram(NewWordModel(words, wordLength, charGap, speed, nil)) if _, err := p.Run(); err != nil { return fmt.Errorf("Error running the model: %v\n", err) } return nil }, Long: `The 'decode words' command gives the user drills to decode morse code words. The flags in this command should be self-explanatory. # How it works For each item, you will be given a sound clip to listen. Input the word corresponding to the sound. Pressing space or hitting enter when empty will repeat the sound. Enter to confirm the answer. ==================================================================== Decode training (5 letter limit) (1 of 5) > egg (escape/ctrl+c to go back, space to repeat sound, enter to confirm) ==================================================================== At the end of the training session, you will be presented with the correct words together with your input. Use that as learning and/or feedback for the next training session. ================================================================ Decoding words training results (5 letter limit, 5 iterations): # Word Correct? Input 1 egg yes egg 2 type no tove ?? 3 smart yes smart 4 loose no loost ? 5 part yes part (2/5 mistakes) (escape / ctrl+c / enter to go back) ================================================================ # Extras This is the default word lengths and character gaps if you specify --level/-l: ============================================= | Level | Word Length Limit | Character Gap | | ----- | ----------------- | ------------- | | 1 | 5 | 16 | | 2 | 5 | 12 | | 3 | 5 | 9 | | 4 | 5 | 6 | | 5 | 5 | 3 | | 6 | 7 | 3 | | 7 | 10 | 3 | | 8+ | 16 | 3 | ============================================= NOTE: - For the convenience and the challenge, --speed can be used to slow down or speed up the sound being played.`, }
View Source
var WordOptPerLevel = [...]wordOpt{
{16, 5},
{12, 5},
{9, 5},
{6, 5},
{3, 5},
{3, 7},
{3, 10},
{3, 16},
}
Functions ¶
func DedupCleanLetters ¶
func NewLetterModel ¶
func NewQuoteModel ¶
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.