asterism-games 0.17.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 73a018990c0459db79342e9b10b9272e6ab214b9cf50d09e326130921828d128
4
+ data.tar.gz: 2b4fffccb723ce03389c5a1fd96175556a1571fd32929095c70542b3a8bfcadc
5
+ SHA512:
6
+ metadata.gz: 1856261b67b3b6e45090cbe8d9e2b385a274ee03798ac03d2ad8f5bfa0cb18b1a9a26f5c8926f748380a74ed39bf1e89dec433302f2f3ae3892dc2dbff569b89
7
+ data.tar.gz: b34655b8d465dffc37e388b0dbd9f0203a26a39488b049541953e326e51d0d6a33c99ca5e1554b5a86364da2ed721373bf99cafc5fdf72195c7e6f282e2b8a71
data/CHANGELOG.md ADDED
@@ -0,0 +1,282 @@
1
+ # Changelog
2
+
3
+ Versions before 0.11.1 are noted in the README where each feature is
4
+ described ("games 0.10.0" and the like).
5
+
6
+ ## 0.17.0
7
+
8
+ - **`asterism-games play <game>`** (README "Playing in a terminal"): the
9
+ tables from a terminal, CRuby and the asterism gem only. `play othello`
10
+ is what `bin/othello-tty` was (the script stays and runs it, with the
11
+ same options). `play mahjong` is new: the table list, the lobby (sit,
12
+ stand, CPUs, tonpuu or hanchan, start), the rounds with the tiles in
13
+ kanji as the table app draws them (the hand in two rows, 一..九 or
14
+ full-width 1..9 over 萬 筒 索; 一萬 4筒 3索 東 in the rivers), or
15
+ `--tiles emoji` (🀇🀈🀉; the fonts decide how they look, 🀄 is often a
16
+ colour emoji) or `--tiles mpsz` (1m 4p 3s and 東 ... 中), the result
17
+ with its yaku and points and the OKs it waits for, the end of the game,
18
+ and watching. Discard by the letter under a tile or by the tile (`6s`,
19
+ `0p`); `riichi`, `tsumo`, `ron`, `pon`, `chi`, `kan`, `pass`, `ok`, with
20
+ a choice when there are several ways; the last line says what can be
21
+ done now, and on a terminal the time left counts down in place once a
22
+ second (only that line is rewritten, the cursor saved and put back, so
23
+ a line being typed is untouched). `--commands "sit,cpu,start"` waits
24
+ for the moment the table can take each command (the lobby, the owner's
25
+ role, the four seats). Tiles and letters keep their columns however wide a terminal
26
+ or a font makes an emoji (each put at its column with the cursor). Both
27
+ take `--router`, `--credentials`, `--namespace`, `--table`, `--name`,
28
+ and with neither of the first two `ASTERISM_ROUTER` /
29
+ `ASTERISM_CREDENTIALS`, as the asterism command line; both wait for a
30
+ host that left the network and go on when it is back.
31
+ - **Keys on a terminal** (README "Keys"): when the input is a terminal,
32
+ both clients read one key at a time, the table apps' keys. Mahjong:
33
+ Left / Right choose a tile (`^^` under it), Enter or Space discards it,
34
+ `R` riichi, `T` tsumo or ron, `P` pon, `C` `V` `B` the chi offered,
35
+ `K` `L` `J` the kans, `N` nine kinds, Esc pass, Enter the result's OK;
36
+ the lobby `1`-`4` sit, `S` stand, `C` CPUs, Enter start. Othello: the
37
+ arrows move a cursor on the board (it stops at the edges), Enter plays
38
+ there, Esc resigns after asking (`resign? [Y] yes [N] no`: `Y` resigns,
39
+ `N` or Esc cancels); `S` sit or stand, `C` the CPU, Enter start. `Q`, Ctrl+Q or Ctrl+C
40
+ quits, and `:` (or `/`) opens a line for any command as typed before.
41
+ The last line names the keys that work now (`[R]リーチ [T]ツモ`). The
42
+ terminal is in raw mode only while keys are read and is put back however
43
+ the client ends. A pipe, a file and `--commands` work as before.
44
+ - The gem holds the mahjong client (`lib/asterism_games/play/`), not the
45
+ table: it needs neither riichi_engine nor the framework.
46
+ - **Jev at the othello table** (README "AI players", "The othello
47
+ table"): the owner may seat Jev as at mahjong, `cpu(token, seat,
48
+ "jev")`; the view has `ak` (`["jev"]` when the host has Jev's key) and
49
+ `ai`, `@status` `ais`. Othello offers Jev only (`AI::GAME_KINDS`, the
50
+ one place that says which game seats which kinds; mahjong keeps Claude
51
+ and Jev). A move Jev does not answer in `ai_turn_seconds` (30 s,
52
+ `OTHELLO_AI_TURN_SECONDS`), answers out of range or fails is the CPU's;
53
+ the day's money and the game's decisions are counted with mahjong's,
54
+ and when they run out Jev's seat becomes the CPU. `play othello`: `A`
55
+ (or `ai`) puts Jev in the other seat and turns it back into the CPU;
56
+ the board's first line says when Jev is thinking. The same key
57
+ (`TYPESAFE_API_KEY`) as mahjong's Jev: nothing new to set.
58
+ - `asterism-games --help` (and `help`, `-h`) prints the usage; it used to
59
+ start the host.
60
+ - Updating: `./update.sh 0.17.0` (docs/install.md); nothing in `.env`. The
61
+ mahjong table does not change; the othello table offers Jev where
62
+ `TYPESAFE_API_KEY` is already set, and old table apps keep playing it
63
+ with the CPU.
64
+
65
+ ## 0.16.3
66
+
67
+ - **asterism 0.8.0** (the Gemfile's pin, from 0.7.1): the host now takes
68
+ from the gem what it did by hand before: the tables' counts on
69
+ `@status` (`net.status`; README "Status"), the players' table apps
70
+ coming and going (`net.on_app_join` / `on_app_leave`; README "Who is
71
+ there"), and the methods' argument names and texts in the meta
72
+ (`asterism objects`, `asterism mcp`). Nothing the players or the
73
+ tables see changes; the wire protocol is 1 as before. The gem's
74
+ dependency stays `~> 0.7, >= 0.7.1`: with an asterism 0.7.1 the host
75
+ still does these by hand.
76
+ - Updating: `./update.sh 0.16.3` (docs/install.md); nothing in `.env`.
77
+
78
+ ## 0.16.2
79
+
80
+ - **The owner away hands the role on** (README "Players that drop out"):
81
+ when a mahjong table's owner has been away for `owner_handover_seconds`
82
+ (`MAHJONG_OWNER_HANDOVER_SECONDS`, 60; 0: never), in the lobby or in a
83
+ game, the role goes to a member who is there: the seated one who sat
84
+ first, else the one who joined first. The old owner coming back does
85
+ not take it back. One log line.
86
+ - **A table left alone ends its game** (README "Players that drop out"):
87
+ during a game, when no seated human is there any more (a member who
88
+ left counts no more at once, an away one for `abandon_seconds`,
89
+ `MAHJONG_ABANDON_SECONDS`, 180; 0: never), the game is abandoned: back
90
+ to the lobby, the CPUs kept, the away humans off their seats, nothing
91
+ recorded (no record, nothing in the stats). One log line. Tables of CPUs
92
+ only (`humans: 0`) are not touched.
93
+ - `seat_reuse_seconds` stays 1800 (README "Who joins"): with the console
94
+ 0.3.9 a page opened again in the same browser comes back as the same
95
+ seat, and the time still has to match the door's `WS_DOOR_SEAT_IDLE`,
96
+ after which a seat may go to another page.
97
+ - Updating: `./update.sh 0.16.2` (docs/install.md); nothing in `.env`
98
+ (the two settings have their defaults). Works with any console; with
99
+ 0.3.9 a closed tab opened again is the same person.
100
+
101
+ ## 0.16.1
102
+
103
+ - The mahjong table's view carries the game host's version, `hv`
104
+ (README, the view's keys), so the table apps can show which host they
105
+ are playing on (the list of tables and the lobby). Nothing else
106
+ changes; `.env` and the records stay as they are.
107
+
108
+ ## 0.16.0
109
+
110
+ - **The rooms of one invite link see each other's game records** (README
111
+ "Game records"; with a console 0.3.8): the host reads a room's
112
+ `"group"` from `rooms.json` (the console's invite link it was made
113
+ from; not secret) and gives it to the room's host, which keeps it with
114
+ each game the room plays. A room's `records` and `record` give out its
115
+ own games and those of the rooms of the same group (the same table
116
+ name). Rooms without a group (made by an admin, or a console before
117
+ 0.3.8), the permanent tables and the LAN tables are as before. The
118
+ stats and `@status`'s `last` stay the room's own; the newest kept are
119
+ counted as before.
120
+ - The records' database gains the column `grp` (added in place on the
121
+ first start; the format stays 1, so 0.15.0 put back reads it as
122
+ before). The games of before keep none and stay their own room's.
123
+ - Updating: `./update.sh 0.16.0` (docs/install.md, "From 0.15 to
124
+ 0.16.0"); nothing in `.env`. Either the console or the host may be
125
+ updated first.
126
+
127
+ ## 0.15.0
128
+
129
+ - **A daily limit per AI kind** (README "AI players"):
130
+ `ASTERISM_GAMES_AI_DAILY_USD_CLAUDE` and `ASTERISM_GAMES_AI_DAILY_USD_JEV`
131
+ give a kind a limit of its own. A kind with one stops when its own money
132
+ of the day reaches it: no table offers it any more and its seats are
133
+ played by the CPU, while the other kinds go on. A kind without one
134
+ follows `ASTERISM_GAMES_AI_DAILY_USD` as before (the day's total of
135
+ every kind). Without any of them the host behaves as 0.14.0. A value
136
+ that is not a number of dollars (0 or more) is ignored with a line in
137
+ the log; the start's log line says each kind's limit, and the stop is
138
+ said once per kind (`today's limit for claude ($10.0) is reached`). A
139
+ new day lets the kind play again.
140
+ - `@status`'s `ai_today` keeps `calls`, `usd` and `limit_usd` and, when a
141
+ kind has a limit of its own, adds `kinds` (each kind's `usd`,
142
+ `limit_usd`, `own`, `over`; README "Status"). The rooms' status
143
+ (`bin/asterism-games status`) adds `kind_limit_usd` and prints a kind's
144
+ money against its own limit. `ai_usage.json` keeps its form.
145
+ - **Mahjong: the start of a round and the result** (README "Result"),
146
+ at a table with humans:
147
+ - After the deal the host waits `deal_pause_seconds` (2,
148
+ `MAHJONG_DEAL_PAUSE_SECONDS`) while the screens show the round's name
149
+ ("東1局 0本場"): no clock runs (the dealer's first move has its full
150
+ time after it), no CPU or AI player plays, `act` is `"not offered"`.
151
+ New view key `in` (the ms left).
152
+ - A round's result waits until every human seated and there (not away)
153
+ has pressed OK, the action next (12): a screen of before gives its
154
+ OK with its "next" as it did. Whoever does not press, the result
155
+ moves on `result_auto_seconds` (10, `MAHJONG_RESULT_AUTO_SECONDS`)
156
+ after the end of its count. The count is the screens' rule too: per
157
+ winner one second for each yaku line and one for the points, the
158
+ winners of a double or triple ron one after the other, one second for
159
+ a round without a win. New view key `ok`: `[the seats that gave their
160
+ OK, the seats still waited for, the ms until it moves on]` (bits,
161
+ bits, ms; not in a spectator's delayed view).
162
+ - **`result_seconds` (`MAHJONG_RESULT_SECONDS`) no longer holds a table
163
+ with humans**: the fixed 8 s are now only those of a table without
164
+ humans (CPUs and AI players), which stays as it was (no pause, no
165
+ OKs). The end of a game (`over`) is as before.
166
+ - A table saved with a result by 0.14.0 moves on by its saved time.
167
+ - Updating: `./update.sh 0.15.0` and the two lines in `.env`
168
+ (docs/install.md, "From 0.14 to 0.15.0"); the times of the round's start
169
+ and result have optional lines of their own.
170
+ - **`deploy/vps/update.sh` no longer stops at "local changes" because of
171
+ `credentials/`.** The directory belongs to the container's user (mode
172
+ 700, docs/install.md), so git run as the server's user could not stat
173
+ the `.gitignore` it tracks there and called it changed. The check of the
174
+ checkout now leaves `credentials/` out (its contents are the host's own).
175
+ Servers that marked the file with `git update-index --assume-unchanged`
176
+ to get past it need nothing more.
177
+
178
+ ## 0.14.0
179
+
180
+ - **The games' records in SQLite** (README "Game records"): every game a
181
+ mahjong table plays to its end goes into one database in the state
182
+ volume, `state_dir/records.sqlite3` (setting `records_db`), written once
183
+ at the game's end by whichever host process played it (the rooms', the
184
+ permanent tables', a LAN host; WAL, a 10 s wait for the lock). The 1000
185
+ newest games of each table are kept (`records_kept`,
186
+ `MAHJONG_RECORDS_KEPT`; the rooms' tables of one name together). A
187
+ game in progress is still in the table's saved state (JSON).
188
+ - A room's games stay when the room closes. Only the room's own host gives
189
+ them out (`records`, `record`, the table apps' recent games) while it is
190
+ open; the other rooms, the permanent and the LAN tables never list them.
191
+ - **Taken in once**: a table's `<table>.records.json` of 0.13.0 goes into
192
+ the database on the first start of 0.14.0 and is renamed
193
+ `<table>.records.json.imported` (docs/install.md, "From 0.13 to 0.14.0").
194
+ - A game's `id` is its row in the database (it grows across the tables).
195
+ - **Backups**: after every game the host writes a consistent copy,
196
+ `records-backup.sqlite3` (`VACUUM INTO`, renamed over the last one), for
197
+ the console's daily backup to take; a host that finds the copy without
198
+ the database starts from it, which is how a restore puts it back
199
+ (docs/install.md, "Backups and restoring"). The console needs no change.
200
+ - **New method `stats(days, game, scope, from)`** (README "Stats"): per
201
+ person (by the name at the table) and per kind (CPU, Claude, Jev):
202
+ games, ranks, average rank, 1st rate, wins, deal-ins and riichi with
203
+ their rates of the rounds, average score, the sum of the rank points; by
204
+ period and kind of game, over every table and room (`"all"`, the
205
+ default) or this table's games; names and numbers, never a record; in
206
+ pages, with its text in the meta (`asterism call`, `asterism mcp`).
207
+ - The records keep each AI seat's kind (`"ais"`: `"claude"`, `"jev"`) for
208
+ the stats; a record of 0.13.0 is read by its AI player's name.
209
+ - The sqlite3 gem is in the Gemfile (the image) and **not a dependency of
210
+ the gem**: without it (the gem alone, or `records_db: json`) the records
211
+ stay in the JSON files of 0.13.0 (the 20 newest, a room's go with it),
212
+ and `stats` counts those. `rake test:gem` runs that way.
213
+
214
+ ## 0.13.0
215
+
216
+ - **Mahjong game records** (README "Game records"): every game a table
217
+ plays to its end is kept, the 20 newest of each table, in the table's
218
+ place in the store (`<table>.records.json`; a room's go with the room).
219
+ A record holds the deals, the dora indicators, every draw and discard,
220
+ the calls, riichi, the wins and draws and the points, in `look`'s tile
221
+ names. A game in progress is part of the table's saved state, so a host
222
+ started again goes on with its record.
223
+ - New methods `records(from)` (the games, newest first, in pages) and
224
+ `record(id, round, part)` (a game's head, a round, a part of a long
225
+ round), with their names and texts in the meta: the table apps, the
226
+ command line (`asterism call`) and an AI assistant (`asterism mcp`) read
227
+ the same. Every answer fits one message of a board.
228
+ - `@status`: each mahjong table's most recent result (`last`: its id,
229
+ when, the four as `[name, rank, score]` in rank order). The rooms'
230
+ status file stays counts only.
231
+ - The views have `cl`, the last declaration (`[type, state version,
232
+ seat, ...]`: riichi, the calls, the wins, nine kinds), which the table
233
+ apps show at the seat that made it.
234
+ - Mahjong (the unreleased 0.12.1): `cpu(token, seat, on)` on one seat that holds a CPU or an AI
235
+ player of another kind turns it into the one asked for in the same call
236
+ (a CPU into `"claude"`, `"claude"` into `"jev"`, `true` an AI player
237
+ back into a CPU). A refused AI player (`"no ai"`: no key, or the day's
238
+ limit) leaves the seat as it was. Seat -1 still fills empty seats only.
239
+ The table apps' lobby has a button per seat that goes round empty, CPU,
240
+ Claude, Jev with it.
241
+
242
+ ## 0.12.0
243
+
244
+ - **The gem `asterism-games`** (`asterism-games.gemspec`, `require
245
+ "asterism_games"`): the framework, othello and the drawing board,
246
+ `bin/asterism-games` and `bin/othello-tty`. It depends on asterism
247
+ (`~> 0.7`, 0.7.1 or later) only. Not in it: mahjong, `bin/mahjong-bots`,
248
+ `deploy/`, `config/`, the tests (README "The gem and the image").
249
+ - Mahjong moved from `lib/asterism_games/mahjong` to
250
+ `app/asterism_games/mahjong`: an application on the gem, kept out of it
251
+ (it needs the riichi_engine fork from git). `require
252
+ "asterism_games/mahjong"` is unchanged with `app/` on the load path;
253
+ `bin/asterism-games` and `bin/mahjong-bots` put it there when it exists.
254
+ - `bin/asterism-games --require FILE` loads a game of your own after the
255
+ others.
256
+ - `rake test:gem`: the tests of what the gem holds, with `lib/` alone on
257
+ the load path (mahjong never loaded).
258
+ - **The image is published**: pushing a tag `v<version>` builds
259
+ `deploy/vps/Dockerfile` (amd64, arm64) and pushes
260
+ `ghcr.io/ruby-asterism/asterism-games:<version>` (also `:<major>.<minor>`
261
+ and `:latest`; `.github/workflows/image.yml`).
262
+ - `deploy/vps`: the compose file uses the published image by default
263
+ (`GAMES_IMAGE=ghcr.io/ruby-asterism/asterism-games`); building it on the
264
+ server is `docker-compose.build.yml`. `update.sh` takes a version
265
+ (`./update.sh 0.12.0`: the tag `v0.12.0` and its image, pulled; `--build`
266
+ builds it there) instead of a ref, and no longer writes `GAMES_REF`. Its
267
+ copy of the saved tables before a restart takes the permanent tables too.
268
+ Updating from 0.11: docs/install.md "From 0.11 to 0.12.0" (set
269
+ `GAMES_IMAGE`, and take the new `update.sh` from the tag once).
270
+
271
+ ## 0.11.1
272
+
273
+ - Jev (the `jev` AI player) is asked through TypeSafe's own API
274
+ (`POST https://api.typesafe.ai/v1/systemone`) instead of Cloudflare
275
+ Workers AI. Its key is `TYPESAFE_API_KEY` (console.typesafe.ai, Keys);
276
+ `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_API_TOKEN` are no longer read.
277
+ Move the key in `.env` when updating, or Jev is not offered.
278
+ - `ASTERISM_GAMES_JEV_MODEL` defaults to `jev-latest` (was `typesafe/jev`,
279
+ a Workers AI name). A versioned id such as `jev-1.13.0` keeps one model.
280
+ - The tokens counted are the answer's `usage` (`input_tokens`,
281
+ `output_tokens`); the default price stays $0.042 per million input
282
+ tokens, output free (TypeSafe's published price, checked 2026-10-18).
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Katsuhiko Kageyama
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.