borse 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of borse might be problematic. Click here for more details.
- borse-0.1.0/.github/workflows/ci.yml +35 -0
- borse-0.1.0/.github/workflows/conv-commit.yml +16 -0
- borse-0.1.0/.github/workflows/release.yml +35 -0
- borse-0.1.0/.gitignore +66 -0
- borse-0.1.0/.pre-commit-config.yml +85 -0
- borse-0.1.0/CLAUDE.md +46 -0
- borse-0.1.0/LICENSE +21 -0
- borse-0.1.0/PKG-INFO +141 -0
- borse-0.1.0/README.md +128 -0
- borse-0.1.0/morse-tree.jpg +0 -0
- borse-0.1.0/pyproject.toml +44 -0
- borse-0.1.0/src/borse/WORDS.txt +5454 -0
- borse-0.1.0/src/borse/__about__.py +3 -0
- borse-0.1.0/src/borse/__init__.py +3 -0
- borse-0.1.0/src/borse/a1z26.py +41 -0
- borse-0.1.0/src/borse/braille.py +106 -0
- borse-0.1.0/src/borse/config.py +130 -0
- borse-0.1.0/src/borse/game.py +472 -0
- borse-0.1.0/src/borse/main.py +27 -0
- borse-0.1.0/src/borse/morse.py +87 -0
- borse-0.1.0/src/borse/progress.py +167 -0
- borse-0.1.0/src/borse/semaphore.py +154 -0
- borse-0.1.0/src/borse/words.py +44 -0
- borse-0.1.0/tests/__init__.py +1 -0
- borse-0.1.0/tests/test_a1z26.py +64 -0
- borse-0.1.0/tests/test_braille.py +85 -0
- borse-0.1.0/tests/test_config.py +77 -0
- borse-0.1.0/tests/test_morse.py +77 -0
- borse-0.1.0/tests/test_progress.py +151 -0
- borse-0.1.0/tests/test_semaphore.py +82 -0
- borse-0.1.0/tests/test_words.py +82 -0
- borse-0.1.0/uv.lock +254 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
ci:
|
|
11
|
+
name: ✨ Full CI Audit Workflow
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- name: 🧾 Checkout code
|
|
16
|
+
uses: actions/checkout@v6
|
|
17
|
+
|
|
18
|
+
- name: 🐍 Set up Python
|
|
19
|
+
uses: actions/setup-python@v6
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.14"
|
|
22
|
+
|
|
23
|
+
- name: 📦 Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v7
|
|
25
|
+
with:
|
|
26
|
+
enable-cache: true
|
|
27
|
+
|
|
28
|
+
- name: 📥 Install dependencies
|
|
29
|
+
run: uv sync
|
|
30
|
+
|
|
31
|
+
- name: 🧼 Check formatting
|
|
32
|
+
run: uv run prek --all-files
|
|
33
|
+
|
|
34
|
+
- name: 🧪 Run tests
|
|
35
|
+
run: uv run prek --all-files --hook-stage pre-push
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: "Conventional commits"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request_target:
|
|
5
|
+
types:
|
|
6
|
+
- opened
|
|
7
|
+
- edited
|
|
8
|
+
- synchronize
|
|
9
|
+
- reopened
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
pull-requests: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
main:
|
|
16
|
+
uses: vEnhance/dotfiles/.github/workflows/conv-commit.yml@main
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: PyPI Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
pypi-publish:
|
|
10
|
+
name: Upload release to PyPI
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment:
|
|
13
|
+
name: pypi
|
|
14
|
+
url: https://pypi.org/p/borse
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
|
+
with:
|
|
20
|
+
submodules: recursive
|
|
21
|
+
- name: Setup Python
|
|
22
|
+
uses: actions/setup-python@v6
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.14"
|
|
25
|
+
- name: Install Hatch
|
|
26
|
+
run: pipx install hatch
|
|
27
|
+
- uses: actions/cache@v5
|
|
28
|
+
with:
|
|
29
|
+
path: ~/.cache/hatch
|
|
30
|
+
key: ${{ runner.os }}-hatch
|
|
31
|
+
restore-keys: ${{ runner.os }}-hatch
|
|
32
|
+
- name: Build package
|
|
33
|
+
run: hatch build
|
|
34
|
+
- name: Publish package distributions to PyPI
|
|
35
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
borse-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
*.egg-info/
|
|
24
|
+
.installed.cfg
|
|
25
|
+
*.egg
|
|
26
|
+
|
|
27
|
+
# PyInstaller
|
|
28
|
+
*.manifest
|
|
29
|
+
*.spec
|
|
30
|
+
|
|
31
|
+
# Installer logs
|
|
32
|
+
pip-log.txt
|
|
33
|
+
pip-delete-this-directory.txt
|
|
34
|
+
|
|
35
|
+
# Unit test / coverage reports
|
|
36
|
+
htmlcov/
|
|
37
|
+
.tox/
|
|
38
|
+
.nox/
|
|
39
|
+
.coverage
|
|
40
|
+
.coverage.*
|
|
41
|
+
.cache
|
|
42
|
+
nosetests.xml
|
|
43
|
+
coverage.xml
|
|
44
|
+
*.cover
|
|
45
|
+
*.py,cover
|
|
46
|
+
.hypothesis/
|
|
47
|
+
.pytest_cache/
|
|
48
|
+
|
|
49
|
+
# Translations
|
|
50
|
+
*.mo
|
|
51
|
+
*.pot
|
|
52
|
+
|
|
53
|
+
# Environments
|
|
54
|
+
.env
|
|
55
|
+
.venv
|
|
56
|
+
env/
|
|
57
|
+
venv/
|
|
58
|
+
ENV/
|
|
59
|
+
env.bak/
|
|
60
|
+
venv.bak/
|
|
61
|
+
|
|
62
|
+
# IDE
|
|
63
|
+
.idea/
|
|
64
|
+
.vscode/
|
|
65
|
+
*.swp
|
|
66
|
+
*.swo
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
default_install_hook_types:
|
|
2
|
+
- pre-commit
|
|
3
|
+
- commit-msg
|
|
4
|
+
- pre-push
|
|
5
|
+
|
|
6
|
+
default_stages: [pre-commit]
|
|
7
|
+
|
|
8
|
+
repos:
|
|
9
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
10
|
+
rev: v6.0.0
|
|
11
|
+
hooks:
|
|
12
|
+
- id: check-json
|
|
13
|
+
- id: check-merge-conflict
|
|
14
|
+
- id: check-toml
|
|
15
|
+
- id: check-yaml
|
|
16
|
+
- id: detect-private-key
|
|
17
|
+
- id: end-of-file-fixer
|
|
18
|
+
- id: fix-byte-order-marker
|
|
19
|
+
- id: mixed-line-ending
|
|
20
|
+
- id: trailing-whitespace
|
|
21
|
+
|
|
22
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
23
|
+
rev: v0.14.14
|
|
24
|
+
hooks:
|
|
25
|
+
- id: ruff-format
|
|
26
|
+
name: ruff format
|
|
27
|
+
types: [python]
|
|
28
|
+
- id: ruff
|
|
29
|
+
name: ruff check
|
|
30
|
+
args: [--fix]
|
|
31
|
+
types: [python]
|
|
32
|
+
|
|
33
|
+
- repo: https://github.com/JoC0de/pre-commit-prettier
|
|
34
|
+
rev: v3.8.1
|
|
35
|
+
hooks:
|
|
36
|
+
- id: prettier
|
|
37
|
+
types_or: [css, javascript, markdown, json, toml, yaml]
|
|
38
|
+
|
|
39
|
+
- repo: https://github.com/codespell-project/codespell
|
|
40
|
+
rev: v2.4.1
|
|
41
|
+
hooks:
|
|
42
|
+
- id: codespell
|
|
43
|
+
additional_dependencies:
|
|
44
|
+
- tomli
|
|
45
|
+
|
|
46
|
+
- repo: https://github.com/compilerla/conventional-pre-commit
|
|
47
|
+
rev: v4.3.0
|
|
48
|
+
hooks:
|
|
49
|
+
- id: conventional-pre-commit
|
|
50
|
+
stages: [commit-msg]
|
|
51
|
+
args:
|
|
52
|
+
[
|
|
53
|
+
feat,
|
|
54
|
+
fix,
|
|
55
|
+
build,
|
|
56
|
+
ci,
|
|
57
|
+
chore,
|
|
58
|
+
docs,
|
|
59
|
+
drop,
|
|
60
|
+
edit,
|
|
61
|
+
perf,
|
|
62
|
+
polish,
|
|
63
|
+
root,
|
|
64
|
+
refactor,
|
|
65
|
+
revert,
|
|
66
|
+
style,
|
|
67
|
+
temp,
|
|
68
|
+
tests,
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
- repo: local
|
|
72
|
+
hooks:
|
|
73
|
+
- id: pytest
|
|
74
|
+
name: pytest
|
|
75
|
+
entry: uv run pytest
|
|
76
|
+
language: system
|
|
77
|
+
pass_filenames: false
|
|
78
|
+
stages: [pre-push]
|
|
79
|
+
|
|
80
|
+
- id: ty
|
|
81
|
+
name: ty
|
|
82
|
+
entry: uv run ty check
|
|
83
|
+
language: system
|
|
84
|
+
pass_filenames: false
|
|
85
|
+
stages: [pre-push]
|
borse-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Borse Development Guide
|
|
2
|
+
|
|
3
|
+
A terminal curses game for practicing Morse code, Braille, and flag semaphore reading.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv sync # Install dependencies
|
|
9
|
+
uv run borse # Run the game
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Project Structure
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
src/borse/
|
|
16
|
+
├── main.py # Entry point, curses wrapper
|
|
17
|
+
├── game.py # Curses UI, menu, and game loop
|
|
18
|
+
├── morse.py # Morse code encoding (dots and dashes)
|
|
19
|
+
├── braille.py # Braille 3x2 ASCII art (filled/unfilled circles)
|
|
20
|
+
├── semaphore.py # Flag semaphore 5x5 ASCII art
|
|
21
|
+
├── words.py # Common English word list
|
|
22
|
+
├── config.py # User configuration (~/.config/borse/config.toml)
|
|
23
|
+
└── progress.py # Daily progress tracking
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Development Commands
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv run pytest # Run all tests (63 tests)
|
|
30
|
+
uv run ruff check src # Lint
|
|
31
|
+
uv run ruff format src # Format
|
|
32
|
+
uv run ty check src # Type check
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Configuration
|
|
36
|
+
|
|
37
|
+
User config stored in `~/.config/borse/config.toml`:
|
|
38
|
+
|
|
39
|
+
- `progress_file`: Path to progress JSON file
|
|
40
|
+
- `words_per_game`: Number of words per session (default: 10)
|
|
41
|
+
|
|
42
|
+
## Adding New Features
|
|
43
|
+
|
|
44
|
+
- **New encoding**: Add module in `src/borse/`, implement `get_display_lines(word) -> list[str]`
|
|
45
|
+
- **New words**: Edit `COMMON_WORDS` list in `words.py`
|
|
46
|
+
- **Game modes**: Add to `GameMode` enum and `MODE_DISPLAY_FUNCS` in `game.py`
|
borse-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Evan Chen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
borse-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: borse
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A terminal game for practicing Morse code, Braille, and semaphore.
|
|
5
|
+
Project-URL: repository, https://github.com/vEnhance/borse
|
|
6
|
+
Author-email: Evan Chen <evan@evanchen.cc>
|
|
7
|
+
License: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Python: <4.0,>=3.10
|
|
10
|
+
Requires-Dist: tomli-w>=1.0.0
|
|
11
|
+
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# borse
|
|
15
|
+
|
|
16
|
+
**borse** is a terminal program meant to practice
|
|
17
|
+
reading braille, Morse code, and semaphore,
|
|
18
|
+
which are common encodings for
|
|
19
|
+
[puzzle hunts](https://web.evanchen.cc/upload/EvanPuzzleCodings.pdf).
|
|
20
|
+
Also supports A1Z26 practice.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
uvx borse
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or you can install from PyPI by using `uv`, `pip`, etc.
|
|
29
|
+
|
|
30
|
+
## Configuration
|
|
31
|
+
|
|
32
|
+
Configuration is stored in `~/.config/borse/config.json` by default:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"progress_file": "~/.config/borse/progress.json",
|
|
37
|
+
"words_per_game": 10
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Your daily progress is also automatically saved and displayed on the main menu.
|
|
42
|
+
|
|
43
|
+
## Hints for memorizing the encodings
|
|
44
|
+
|
|
45
|
+
Actually this is a note-to-self.
|
|
46
|
+
|
|
47
|
+
### Remembering braille
|
|
48
|
+
|
|
49
|
+
For Grade 1 (just the letters `A-Z`),
|
|
50
|
+
the chart on [Wikipedia](https://en.wikipedia.org/wiki/English_Braille)
|
|
51
|
+
is helpful!
|
|
52
|
+
The trick is to memorize just the first 10 symbols for `A-J`,
|
|
53
|
+
which only use the upper four dots.
|
|
54
|
+
That's because `K-T` are the same as `A-J` with one extra dot,
|
|
55
|
+
while `UVXYZ` are `A-E` with one extra dot.
|
|
56
|
+
|
|
57
|
+
In real life, Grade 2 braille has some additional contractions.
|
|
58
|
+
It might be nice to add these into borse at some point.
|
|
59
|
+
|
|
60
|
+
### Remembering Morse code
|
|
61
|
+
|
|
62
|
+
In Morse code, the most frequent letters are shorter.
|
|
63
|
+
So I think it's a lot easier to remember Morse code as a binary tree,
|
|
64
|
+
since the common letters will all be towards the top.
|
|
65
|
+
I found [this picture on the Internet](https://slidetodoc.com/binary-trees-binary-tree-structure-root-node-stores/):
|
|
66
|
+
|
|
67
|
+

|
|
68
|
+
|
|
69
|
+
I think the dot looks like 0 and a dash looks like a (rotated) 1,
|
|
70
|
+
so it makes sense to me that dots are in the left of the tree.
|
|
71
|
+
|
|
72
|
+
Then you can just memorize the letters in each row in order.
|
|
73
|
+
Here are some terrible mnemonics I made up that worked for me
|
|
74
|
+
for the first three rows (you're on your own for the last one):
|
|
75
|
+
|
|
76
|
+
- `ET`: Eastern Time, or a [1982 movie][et]
|
|
77
|
+
- `IANM`: I Am Not Mad
|
|
78
|
+
- `SURWDKGO`: [SuperUser][su] [ReWrote][rw] [DynamicKernel][dk] in [GO][go]
|
|
79
|
+
|
|
80
|
+
(Also, `surdwkgo` is also the name of a
|
|
81
|
+
[Taiwanese CodeForces grandmaster](https://codeforces.com/profile/surwdkgo).)
|
|
82
|
+
|
|
83
|
+
[et]: https://en.wikipedia.org/wiki/E.T._the_Extra-Terrestrial
|
|
84
|
+
[su]: https://en.wikipedia.org/wiki/Su_(Unix)
|
|
85
|
+
[rw]: https://lean-lang.org/doc/reference/latest/Tactic-Proofs/Tactic-Reference/#rw
|
|
86
|
+
[dk]: https://en.wikipedia.org/wiki/Dynamic_Kernel_Module_Support
|
|
87
|
+
[go]: https://en.wikipedia.org/wiki/Go_(programming_language)
|
|
88
|
+
|
|
89
|
+
### Remembering semaphore
|
|
90
|
+
|
|
91
|
+
If you look at a semaphore chart,
|
|
92
|
+
what you'll find is that there are some groups of adjacent letters
|
|
93
|
+
that just differ in one hand rotating clockwise.
|
|
94
|
+
For example, the letters from `A-G` are obtained
|
|
95
|
+
by fixing one arm at 6 o'clock and rotating the other arm
|
|
96
|
+
all the way from 7:30 to 4:30.
|
|
97
|
+
|
|
98
|
+
So in my head, I organize the letters in "blocks",
|
|
99
|
+
where each block starts with two arms at a 45-degree angle,
|
|
100
|
+
and then having the other arm rotate clockwise.
|
|
101
|
+
The resulting blocks are then easier to remember:
|
|
102
|
+
|
|
103
|
+
- **A block**: `ABCDEFG`
|
|
104
|
+
- **H block**: `HIKLMN` (note `J` is missing)
|
|
105
|
+
- **O block**: `OPQRS`
|
|
106
|
+
- **T block**: `TUY` (note the additional `Y`)
|
|
107
|
+
- **# block**: `#JV` (this is the weird exceptions one)
|
|
108
|
+
- **W block**: `WX`
|
|
109
|
+
- **Z block**: `Z`
|
|
110
|
+
|
|
111
|
+
I don't know if `A HOT #WZ` means anything to you.
|
|
112
|
+
|
|
113
|
+
## Development
|
|
114
|
+
|
|
115
|
+
Set up by cloning the repository and running
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
uv sync
|
|
119
|
+
uv run prek install
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
To manually run the linter and tests
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
uv run prek --all-files # run linter
|
|
126
|
+
uv run prek --all-files --hook-stage pre-push
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## FAQ
|
|
130
|
+
|
|
131
|
+
- _Where does the name come from?_
|
|
132
|
+
|
|
133
|
+
From `Braille mORse SEmaphore`.
|
|
134
|
+
|
|
135
|
+
- _Should "braille" be capitalized?_
|
|
136
|
+
|
|
137
|
+
[No](https://www.brailleauthority.org/capitalization/capitalization.html).
|
|
138
|
+
|
|
139
|
+
- _Why would you spend time learning this?_
|
|
140
|
+
|
|
141
|
+
It could be a great conversation starter for a first date…
|
borse-0.1.0/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# borse
|
|
2
|
+
|
|
3
|
+
**borse** is a terminal program meant to practice
|
|
4
|
+
reading braille, Morse code, and semaphore,
|
|
5
|
+
which are common encodings for
|
|
6
|
+
[puzzle hunts](https://web.evanchen.cc/upload/EvanPuzzleCodings.pdf).
|
|
7
|
+
Also supports A1Z26 practice.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
uvx borse
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or you can install from PyPI by using `uv`, `pip`, etc.
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
Configuration is stored in `~/.config/borse/config.json` by default:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"progress_file": "~/.config/borse/progress.json",
|
|
24
|
+
"words_per_game": 10
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Your daily progress is also automatically saved and displayed on the main menu.
|
|
29
|
+
|
|
30
|
+
## Hints for memorizing the encodings
|
|
31
|
+
|
|
32
|
+
Actually this is a note-to-self.
|
|
33
|
+
|
|
34
|
+
### Remembering braille
|
|
35
|
+
|
|
36
|
+
For Grade 1 (just the letters `A-Z`),
|
|
37
|
+
the chart on [Wikipedia](https://en.wikipedia.org/wiki/English_Braille)
|
|
38
|
+
is helpful!
|
|
39
|
+
The trick is to memorize just the first 10 symbols for `A-J`,
|
|
40
|
+
which only use the upper four dots.
|
|
41
|
+
That's because `K-T` are the same as `A-J` with one extra dot,
|
|
42
|
+
while `UVXYZ` are `A-E` with one extra dot.
|
|
43
|
+
|
|
44
|
+
In real life, Grade 2 braille has some additional contractions.
|
|
45
|
+
It might be nice to add these into borse at some point.
|
|
46
|
+
|
|
47
|
+
### Remembering Morse code
|
|
48
|
+
|
|
49
|
+
In Morse code, the most frequent letters are shorter.
|
|
50
|
+
So I think it's a lot easier to remember Morse code as a binary tree,
|
|
51
|
+
since the common letters will all be towards the top.
|
|
52
|
+
I found [this picture on the Internet](https://slidetodoc.com/binary-trees-binary-tree-structure-root-node-stores/):
|
|
53
|
+
|
|
54
|
+

|
|
55
|
+
|
|
56
|
+
I think the dot looks like 0 and a dash looks like a (rotated) 1,
|
|
57
|
+
so it makes sense to me that dots are in the left of the tree.
|
|
58
|
+
|
|
59
|
+
Then you can just memorize the letters in each row in order.
|
|
60
|
+
Here are some terrible mnemonics I made up that worked for me
|
|
61
|
+
for the first three rows (you're on your own for the last one):
|
|
62
|
+
|
|
63
|
+
- `ET`: Eastern Time, or a [1982 movie][et]
|
|
64
|
+
- `IANM`: I Am Not Mad
|
|
65
|
+
- `SURWDKGO`: [SuperUser][su] [ReWrote][rw] [DynamicKernel][dk] in [GO][go]
|
|
66
|
+
|
|
67
|
+
(Also, `surdwkgo` is also the name of a
|
|
68
|
+
[Taiwanese CodeForces grandmaster](https://codeforces.com/profile/surwdkgo).)
|
|
69
|
+
|
|
70
|
+
[et]: https://en.wikipedia.org/wiki/E.T._the_Extra-Terrestrial
|
|
71
|
+
[su]: https://en.wikipedia.org/wiki/Su_(Unix)
|
|
72
|
+
[rw]: https://lean-lang.org/doc/reference/latest/Tactic-Proofs/Tactic-Reference/#rw
|
|
73
|
+
[dk]: https://en.wikipedia.org/wiki/Dynamic_Kernel_Module_Support
|
|
74
|
+
[go]: https://en.wikipedia.org/wiki/Go_(programming_language)
|
|
75
|
+
|
|
76
|
+
### Remembering semaphore
|
|
77
|
+
|
|
78
|
+
If you look at a semaphore chart,
|
|
79
|
+
what you'll find is that there are some groups of adjacent letters
|
|
80
|
+
that just differ in one hand rotating clockwise.
|
|
81
|
+
For example, the letters from `A-G` are obtained
|
|
82
|
+
by fixing one arm at 6 o'clock and rotating the other arm
|
|
83
|
+
all the way from 7:30 to 4:30.
|
|
84
|
+
|
|
85
|
+
So in my head, I organize the letters in "blocks",
|
|
86
|
+
where each block starts with two arms at a 45-degree angle,
|
|
87
|
+
and then having the other arm rotate clockwise.
|
|
88
|
+
The resulting blocks are then easier to remember:
|
|
89
|
+
|
|
90
|
+
- **A block**: `ABCDEFG`
|
|
91
|
+
- **H block**: `HIKLMN` (note `J` is missing)
|
|
92
|
+
- **O block**: `OPQRS`
|
|
93
|
+
- **T block**: `TUY` (note the additional `Y`)
|
|
94
|
+
- **# block**: `#JV` (this is the weird exceptions one)
|
|
95
|
+
- **W block**: `WX`
|
|
96
|
+
- **Z block**: `Z`
|
|
97
|
+
|
|
98
|
+
I don't know if `A HOT #WZ` means anything to you.
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
Set up by cloning the repository and running
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
uv sync
|
|
106
|
+
uv run prek install
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
To manually run the linter and tests
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
uv run prek --all-files # run linter
|
|
113
|
+
uv run prek --all-files --hook-stage pre-push
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## FAQ
|
|
117
|
+
|
|
118
|
+
- _Where does the name come from?_
|
|
119
|
+
|
|
120
|
+
From `Braille mORse SEmaphore`.
|
|
121
|
+
|
|
122
|
+
- _Should "braille" be capitalized?_
|
|
123
|
+
|
|
124
|
+
[No](https://www.brailleauthority.org/capitalization/capitalization.html).
|
|
125
|
+
|
|
126
|
+
- _Why would you spend time learning this?_
|
|
127
|
+
|
|
128
|
+
It could be a great conversation starter for a first date…
|
|
Binary file
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "borse"
|
|
3
|
+
description = "A terminal game for practicing Morse code, Braille, and semaphore."
|
|
4
|
+
readme = "README.md"
|
|
5
|
+
requires-python = ">=3.10,<4.0"
|
|
6
|
+
dependencies = [
|
|
7
|
+
"tomli>=2.0.0; python_version < '3.11'",
|
|
8
|
+
"tomli-w>=1.0.0",
|
|
9
|
+
]
|
|
10
|
+
authors = [{ name = "Evan Chen", email = "evan@evanchen.cc" }]
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
urls = { repository = "https://github.com/vEnhance/borse" }
|
|
13
|
+
dynamic = ["version"]
|
|
14
|
+
|
|
15
|
+
[project.scripts]
|
|
16
|
+
borse = "borse.main:main"
|
|
17
|
+
|
|
18
|
+
[build-system]
|
|
19
|
+
requires = ["hatchling"]
|
|
20
|
+
build-backend = "hatchling.build"
|
|
21
|
+
|
|
22
|
+
[tool.hatch.version]
|
|
23
|
+
path = "src/borse/__about__.py"
|
|
24
|
+
|
|
25
|
+
[tool.ruff]
|
|
26
|
+
target-version = "py314"
|
|
27
|
+
|
|
28
|
+
[tool.ruff.lint]
|
|
29
|
+
select = ["E4", "E7", "E9", "F", "I"]
|
|
30
|
+
|
|
31
|
+
[tool.pytest.ini_options]
|
|
32
|
+
testpaths = ["tests"]
|
|
33
|
+
pythonpath = ["src"]
|
|
34
|
+
|
|
35
|
+
[tool.ty.environment]
|
|
36
|
+
python-version = "3.14"
|
|
37
|
+
|
|
38
|
+
[dependency-groups]
|
|
39
|
+
dev = [
|
|
40
|
+
"prek>=0.3.1",
|
|
41
|
+
"pytest>=8.0.0",
|
|
42
|
+
"ruff>=0.4.0",
|
|
43
|
+
"ty>=0.0.1a6",
|
|
44
|
+
]
|