Skip to content

Commit

Permalink
docs: update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
paithiov909 committed Nov 16, 2024
1 parent 39c2e73 commit 5fa05c5
Show file tree
Hide file tree
Showing 2 changed files with 271 additions and 5 deletions.
93 changes: 93 additions & 0 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,99 @@ calc_defen("m345567p234s3378", baopai = "z1", rongpai = "s9=")
parse_hupai(score$hupai, "jp")
```

### 牌譜ファイルを扱う

```{r include = FALSE}
stopifnot(requireNamespace("convlog", quietly = TRUE))
```

[convlog](https://github.com/paithiov909/convlog)パッケージを使うと、天鳳のJSON形式(`tenhou.net/6`)のファイルから牌譜を読み込むことができます。

`convlog::read_tenhou6()`の戻り値は、次のようなかたちをしています。

```{r}
json_log <-
list.files(
system.file("testdata/", package = "convlog"),
pattern = "*.json$",
full.names = TRUE
) |>
convlog::read_tenhou6()
json_log
```

この関数は、天鳳のJSON形式を一度MJAIフォーマットのJSON文字列へと変換したうえでパースするため、牌の表現などがshikakusphereで用いているものとは異なっています。MJAIフォーマットにおける牌の表現をshikakusphereで用いている表現に変換するには、`trans_tile()`, `mjai_target()`, `mjai_conv()`を使って、次のようにします。

```{r}
paifu <-
json_log[["paifu"]] |>
dplyr::filter(
type %in% c("tsumo", "dahai", "chi", "pon", "daiminkan", "kakan", "ankan", "reach")
) |>
dplyr::mutate(
# ツモ切りかを判定する場合、あらかじめ`NA`を`FALSE`で埋めておく
tsumogiri = dplyr::if_else(is.na(tsumogiri), FALSE, tsumogiri),
# 牌の表現の変換
pai = trans_tile(pai)
) |>
dplyr::group_by(game_id, round_id, actor) |>
dplyr::mutate(
# 副露メンツの変換
pai = mjai_conv(type, pai, consumed, mjai_target(actor, target)),
# ツモ切りなら末尾に"_"を付ける
pai = dplyr::if_else(tsumogiri,
paste0(pai, "_"),
pai
),
# # リーチ宣言牌なら末尾に"*"を付ける
pai = dplyr::if_else(
dplyr::lag(type, default = "") == "reach",
paste0(pai, "*"),
pai
)
) |>
dplyr::ungroup()
paifu
```

`proceed()`を使うと、ゲームのある時点におけるプレイヤーの手牌の状態を再現することができます。この関数には、その時点までの各プレイヤーの配牌・ツモ・打牌をそれぞれlistとして与えます。チー・ポンと大明槓についてはツモの一部、暗槓と加槓については打牌の一部とします。

たとえば、ここで読み込んでいるデータについて、各本場の終わりの時点におけるプレイヤーの手牌を再現するには、次のようにします。

```{r}
qipai <-
json_log[["round_info"]] |>
dplyr::rowwise() |>
dplyr::reframe(
game_id = game_id,
round_id = round_id,
actor = 0:3,
tehais
) |>
dplyr::group_by(game_id, round_id, actor) |>
dplyr::mutate(qipai = list(trans_tile(as.character(tehais))), .keep = "unused") |>
dplyr::ungroup()
paifu |>
dplyr::left_join(qipai, by = dplyr::join_by(game_id, round_id, actor)) |>
dplyr::group_by(game_id, round_id, actor) |>
dplyr::summarise(
qipai = unique(qipai),
zimo = list(pai[which(type %in% c("tsumo", "chi", "pon", "daiminkan"))]),
dapai = list(pai[which(type %in% c("dahai", "kakan", "ankan"))]),
.groups = "keep"
) |>
dplyr::ungroup() |>
dplyr::reframe(
game_id = game_id,
round_id = round_id,
player = actor,
last_state = proceed(qipai, zimo, dapai)
)
```

# License

GPL (>= 3). This package contains the [tinyxml2](https://github.com/leethomason/tinyxml2) code released under the zlib license.
183 changes: 178 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,23 @@ tidy(hands) |>
lineup()
#> [[1]]
#> [1] m1 m1 p2 p3 p4 s5 s5 s5 z1 z1 z1 z2 z2
#> 37 Levels: m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 ... z7
#> 38 Levels: _ m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 ... z7
#>
#> [[2]]
#> [1] p1 p1 p2 p2 p3 p3 p4 p4 p5 p5 p6 p6 p7
#> 37 Levels: m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 ... z7
#> 38 Levels: _ m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 ... z7
#>
#> [[3]]
#> [1] m1 m9 p1 p9 s1 s9 z1 z2 z3 z4 z5 z6 z7
#> 37 Levels: m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 ... z7
#> 38 Levels: _ m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 ... z7
#>
#> [[4]]
#> [1] m0 m5 m5 m7 m8 m9 z5 z5 z5 z5 z6 z6 z6 z7 z7
#> 37 Levels: m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 ... z7
#> 38 Levels: _ m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 ... z7
#>
#> [[5]]
#> [1] m0 m5 m5 m7 m8 m9 z5 z5 z5 z5 z6 z6 z6 z7 z7
#> 37 Levels: m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 ... z7
#> 38 Levels: _ m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 ... z7
```

さらに、このかたちのlist of factors(またはlist of
Expand Down Expand Up @@ -220,6 +220,179 @@ parse_hupai(score$hupai, "jp")
#> 54 Levels: 場風 東 場風 南 場風 西 場風 北 自風 東 自風 南 自風 西 ... 地和
```

### 牌譜ファイルを扱う

[convlog](https://github.com/paithiov909/convlog)パッケージを使うと、天鳳のJSON形式(`tenhou.net/6`)のファイルから牌譜を読み込むことができます。

`convlog::read_tenhou6()`の戻り値は、次のようなかたちをしています。

``` r
json_log <-
list.files(
system.file("testdata/", package = "convlog"),
pattern = "*.json$",
full.names = TRUE
) |>
convlog::read_tenhou6()

json_log
#> $game_info
#> # A tibble: 21 × 4
#> game_id names qijia aka
#> <int> <named list> <int> <lgl>
#> 1 1 <chr [4]> 4 TRUE
#> 2 2 <chr [4]> 0 TRUE
#> 3 3 <chr [4]> 0 TRUE
#> 4 4 <chr [4]> 0 TRUE
#> 5 5 <chr [4]> 0 TRUE
#> 6 6 <chr [4]> 0 TRUE
#> 7 7 <chr [4]> 0 TRUE
#> 8 8 <chr [4]> 0 TRUE
#> 9 9 <chr [4]> 0 TRUE
#> 10 10 <chr [4]> 0 TRUE
#> # ℹ 11 more rows
#>
#> $round_info
#> # A tibble: 33 × 10
#> game_id round_id bakaze dora_marker kyoku honba kyotaku oya scores tehais
#> <int> <int> <chr> <chr> <int> <int> <int> <int> <list> <list>
#> 1 1 1 E 3s 1 0 0 0 <int> <chr[…]>
#> 2 2 1 E 4m 3 3 0 2 <int> <chr[…]>
#> 3 3 1 E 6m 1 0 0 0 <int> <chr[…]>
#> 4 4 1 E E 4 0 0 3 <int> <chr[…]>
#> 5 5 1 E 8p 2 2 0 1 <int> <chr[…]>
#> 6 6 1 E 7s 1 0 0 0 <int> <chr[…]>
#> 7 7 1 S 6s 4 0 0 3 <int> <chr[…]>
#> 8 8 1 S 2m 4 1 1 3 <int> <chr[…]>
#> 9 9 1 S 2m 1 0 0 0 <int> <chr[…]>
#> 10 10 1 S 7s 2 2 0 1 <int> <chr[…]>
#> # ℹ 23 more rows
#>
#> $paifu
#> # A tibble: 3,255 × 12
#> game_id round_id event_id type actor target pai tsumogiri consumed
#> <int> <int> <int> <chr> <int> <int> <chr> <lgl> <list>
#> 1 1 1 1 tsumo 0 NA S NA <NULL>
#> 2 1 1 2 dahai 0 NA N FALSE <NULL>
#> 3 1 1 3 tsumo 1 NA 2m NA <NULL>
#> 4 1 1 4 dahai 1 NA 8p FALSE <NULL>
#> 5 1 1 5 tsumo 2 NA 6p NA <NULL>
#> 6 1 1 6 dahai 2 NA 8s FALSE <NULL>
#> 7 1 1 7 tsumo 3 NA 1m NA <NULL>
#> 8 1 1 8 dahai 3 NA P FALSE <NULL>
#> 9 1 1 9 tsumo 0 NA 1m NA <NULL>
#> 10 1 1 10 dahai 0 NA 1p FALSE <NULL>
#> # ℹ 3,245 more rows
#> # ℹ 3 more variables: dora_marker <chr>, deltas <list>, ura_markers <list>
```

この関数は、天鳳のJSON形式を一度MJAIフォーマットのJSON文字列へと変換したうえでパースするため、牌の表現などがshikakusphereで用いているものとは異なっています。MJAIフォーマットにおける牌の表現をshikakusphereで用いている表現に変換するには、`trans_tile()`,
`mjai_target()`, `mjai_conv()`を使って、次のようにします。

``` r
paifu <-
json_log[["paifu"]] |>
dplyr::filter(
type %in% c("tsumo", "dahai", "chi", "pon", "daiminkan", "kakan", "ankan", "reach")
) |>
dplyr::mutate(
# ツモ切りかを判定する場合、あらかじめ`NA`を`FALSE`で埋めておく
tsumogiri = dplyr::if_else(is.na(tsumogiri), FALSE, tsumogiri),
# 牌の表現の変換
pai = trans_tile(pai)
) |>
dplyr::group_by(game_id, round_id, actor) |>
dplyr::mutate(
# 副露メンツの変換
pai = mjai_conv(type, pai, consumed, mjai_target(actor, target)),
# ツモ切りなら末尾に"_"を付ける
pai = dplyr::if_else(tsumogiri,
paste0(pai, "_"),
pai
),
# # リーチ宣言牌なら末尾に"*"を付ける
pai = dplyr::if_else(
dplyr::lag(type, default = "") == "reach",
paste0(pai, "*"),
pai
)
) |>
dplyr::ungroup()

paifu
#> # A tibble: 3,185 × 12
#> game_id round_id event_id type actor target pai tsumogiri consumed
#> <int> <int> <int> <chr> <int> <int> <chr> <lgl> <list>
#> 1 1 1 1 tsumo 0 NA z2 FALSE <NULL>
#> 2 1 1 2 dahai 0 NA z4 FALSE <NULL>
#> 3 1 1 3 tsumo 1 NA m2 FALSE <NULL>
#> 4 1 1 4 dahai 1 NA p8 FALSE <NULL>
#> 5 1 1 5 tsumo 2 NA p6 FALSE <NULL>
#> 6 1 1 6 dahai 2 NA s8 FALSE <NULL>
#> 7 1 1 7 tsumo 3 NA m1 FALSE <NULL>
#> 8 1 1 8 dahai 3 NA z5 FALSE <NULL>
#> 9 1 1 9 tsumo 0 NA m1 FALSE <NULL>
#> 10 1 1 10 dahai 0 NA p1 FALSE <NULL>
#> # ℹ 3,175 more rows
#> # ℹ 3 more variables: dora_marker <chr>, deltas <list>, ura_markers <list>
```

`proceed()`を使うと、ゲームのある時点におけるプレイヤーの手牌の状態を再現することができます。この関数には、その時点までの各プレイヤーの配牌・ツモ・打牌をそれぞれlistとして与えます。チー・ポンと大明槓についてはツモの一部、暗槓と加槓については打牌の一部とします。

たとえば、ここで読み込んでいるデータについて、各本場の終わりの時点におけるプレイヤーの手牌を再現するには、次のようにします。

``` r
qipai <-
json_log[["round_info"]] |>
dplyr::rowwise() |>
dplyr::reframe(
game_id = game_id,
round_id = round_id,
actor = 0:3,
tehais
) |>
dplyr::group_by(game_id, round_id, actor) |>
dplyr::mutate(qipai = list(trans_tile(as.character(tehais))), .keep = "unused") |>
dplyr::ungroup()

paifu |>
dplyr::left_join(qipai, by = dplyr::join_by(game_id, round_id, actor)) |>
dplyr::group_by(game_id, round_id, actor) |>
dplyr::summarise(
qipai = unique(qipai),
zimo = list(pai[which(type %in% c("tsumo", "chi", "pon", "daiminkan"))]),
dapai = list(pai[which(type %in% c("dahai", "kakan", "ankan"))]),
.groups = "keep"
) |>
dplyr::ungroup() |>
dplyr::reframe(
game_id = game_id,
round_id = round_id,
player = actor,
last_state = proceed(qipai, zimo, dapai)
)
#> Warning: There were 2 warnings in `dplyr::reframe()`.
#> The first warning was:
#> ℹ In argument: `last_state = proceed(qipai, zimo, dapai)`.
#> Caused by warning in `.Call()`:
#> ! possibly incorrect mianzi at: m04-6
#> ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
#> # A tibble: 130 × 4
#> game_id round_id player last_state
#> <int> <int> <int> <paistr>
#> 1 1 1 0 <13>'m34677p33405s123'
#> 2 1 1 1 <13>'m12227999z13336'
#> 3 1 1 2 <13>'m05567s40z111,m333='
#> 4 1 1 3 <14>'m56688p3377s4,s666+6'
#> 5 2 1 0 <13>'m2255p345567s567'
#> 6 2 1 1 <13>'m3p222,z777=,s222=,z111+'
#> 7 2 1 2 <13>'m24777789z55,m666+'
#> 8 2 1 3 <14>'m3445688s406m2,z222-'
#> 9 3 1 0 <13>'m34p8s23466z11,m67-8'
#> 10 3 1 1 <13>'m88p456s06789,z555+'
#> # ℹ 120 more rows
```

# License

GPL (\>= 3). This package contains the
Expand Down

0 comments on commit 5fa05c5

Please sign in to comment.