%% %% This is file `mahjong.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% mahjong.dtx (with options: `pkg') %% Copyright (c) 2021 Daniel Schmitz %% %% Permission is hereby granted, free of charge, to any person obtaining a copy of this software and %% associated documentation files (the "Software"), to deal in the Software without restriction, %% including without limitation the rights to use, copy, modify, merge, publish, distribute, %% sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is %% furnished to do so, subject to the following conditions: %% %% The above copyright notice and this permission notice shall be included in all copies or substantial %% portions of the Software. %% %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT %% NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND %% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT %% OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \NeedsTeXFormat{LaTeX2e}[2019/10/01] \RequirePackage{expl3} \ProvidesExplPackage{mahjong}{2021/04/16}{1.0.1}{Typeset Mahjong Hands} \RequirePackage{xparse} \RequirePackage{l3keys2e} \RequirePackage{graphicx} \RequirePackage{stackengine} \msg_new:nnnn {mahjong} {invalid_token} {Token ~ #1 ~ is ~ not ~ valid ~ in ~ MPSZ ~ notation} {Valid ~ tokens ~ are ~ digits ~ 0-9, ~ m, ~ p, ~ s, ~ z, ~ x, ~ -, ~ ?, ~ ', ~ and ~ " } \msg_new:nnnn {mahjong} {unknown_tile} {I~don't~know~tile~#1.} {Please~check~the~documentation~for~recognized~tiles.} \msg_new:nnnn {mahjong} {unknown_orientation} {Orientation ~ #1 ~ is ~ unknown} {This ~ should ~ not ~ happen.~ Please ~ create ~ a ~ bug ~ report.} \keys_define:nn {mahjong} { height .dim_gset:N = \g_mahjong_default_height } \cs_new:Npn \c__mahjong_suits_tl {mpsz} \cs_new:Npn \c__mahjong_allowed_tokens_tl {0123456789mpsz-?x'"} \tl_new:N \l__mahjong_suit_tl \tl_new:N \l__mahjong_tiles_tl \tl_new:N \l__mahjong_reversed_tl \tl_new:N \l__mahjong_hand_tl \tl_new:N \l__mahjong_current_suit_tl \tl_new:N \l__mahjong_current_group_tl \tl_new:N \l__mahjong_current_char \dim_set:Nn \g_mahjong_default_height {\baselineskip} \dim_new:N \l_mahjong_tile_height \int_new:N \l__mahjong_tile_orientation_int \seq_new:N \l__mahjong_tile_maps_seq \str_new:N \l__mahjong_file_path_str \ProcessKeysPackageOptions{mahjong} \cs_set:Npn \__mahjong_make_tile:nn #1#2 { \file_if_exist:nTF {#1} { \int_case:nnF {#2} { {0} { \stackinset{c}{0pt}{c}{0pt}{ \includegraphics[ angle=0, height=.85\l_mahjong_tile_height] {#1} }{ \includegraphics[ angle=0, height=\l_mahjong_tile_height] {tiles/mahjong-Front.pdf} } } {1} { \stackinset{c}{0pt}{c}{0pt}{ \includegraphics[ angle=90, width=.85\l_mahjong_tile_height] {#1} }{ \includegraphics[ angle=90, width=\l_mahjong_tile_height] {tiles/mahjong-Front.pdf} } } {2} { % Stack 2 rotated tiles on top of each other. \stackon [0pt] { \__mahjong_make_tile:nn {#1} {1} } { \__mahjong_make_tile:nn {#1} {1} } } } { \msg_fatal:nnx {mahjong} {unknown_orientation} {#2} } } { \msg_error:nnx {mahjong} {unknown_tile} {#1} } } \cs_generate_variant:Nn \__mahjong_make_tile:nn {VV, xV, nV} \cs_set:Npn \mahjong_typeset_hand:n #1 { \tl_set:Nx \l__mahjong_hand_tl {\text_lowercase:n {#1}} % MPSZ notation is easier to parse right-to-left, so reverse string % There is no string reversal function but we can reverse token lists % Token lists and strings are freely convertible between each other \tl_set:Nx \l__mahjong_reversed_tl {\tl_reverse:V \l__mahjong_hand_tl} \tl_map_variable:NNn \l__mahjong_reversed_tl \l__mahjong_current_char { % Check if we recognize the current token \exp_args:NVV \tl_if_in:nnF \c__mahjong_allowed_tokens_tl \l__mahjong_current_char { \msg_error:nnx {mahjong} {invalid_token} {\l__mahjong_current_char} } \exp_args:NVV \tl_if_in:nnTF \c__mahjong_suits_tl \l__mahjong_current_char { % If we've found a suit identifier, change the current suit \tl_set:NV \l__mahjong_current_suit_tl \l__mahjong_current_char } { \str_case:VnF \l__mahjong_current_char { {'} { % An apostrophe indicates that the next tile is rotated \int_set:Nn \l__mahjong_tile_orientation_int {1} } {"} { % Quotes mean the next tile is actually 2 rotated tiles stacked on top of each other \int_set:Nn \l__mahjong_tile_orientation_int {2} } } { % Default case: We've got a complete tile identifier % Turn it into a property list \prop_clear:N \l_tmpa_prop \prop_put:NnV \l_tmpa_prop {suit} \l__mahjong_current_suit_tl \prop_put:NnV \l_tmpa_prop {face} \l__mahjong_current_char \prop_put:NnV \l_tmpa_prop {orientation} \l__mahjong_tile_orientation_int % Add it to the beginning of the sequence (we are parsing in reverse) \seq_put_left:NV \l__mahjong_tile_maps_seq \l_tmpa_prop \int_set:Nn \l__mahjong_tile_orientation_int {0} } } } % Typesetting begins here. Sequence is in correct order \seq_map_variable:NNn \l__mahjong_tile_maps_seq \l_tmpa_prop { \prop_get:NnN \l_tmpa_prop {face} \l_tmpa_tl \prop_get:NnN \l_tmpa_prop {orientation} \l_tmpa_int \str_case:VnF \l_tmpa_tl { {-} { % If the current face is a dash, insert a space \includegraphics[height=\l_mahjong_tile_height]{tiles/mahjong-Space.pdf} } {x} { % Insert a flipped tile \int_case:nn {\l_tmpa_int} { {0} { % Upright \includegraphics[ angle=0, height=\l_mahjong_tile_height] {tiles/mahjong-Back.pdf} } {1} { % Rotated \includegraphics[ angle=90, width=\l_mahjong_tile_height] {tiles/mahjong-Back.pdf} } {2} { % Rotated and stacked \stackon [0pt] { \includegraphics[ angle=90, width=\l_mahjong_tile_height] {tiles/mahjong-Back.pdf} } { \includegraphics[angle=90, width=\l_mahjong_tile_height] {tiles/mahjong-Back.pdf} } } } } {?} { % Blank tile \__mahjong_make_tile:nV {tiles/mahjong-Blank.pdf} \l_tmpa_int } } { % Any other tile identified by a code. \__mahjong_make_tile:xV {tiles/mahjong-\l_tmpa_tl\prop_item:Nn \l_tmpa_prop {suit}.pdf} \l_tmpa_int } } % Clear the list for the next invocation \seq_clear:N \l__mahjong_tile_maps_seq } \cs_generate_variant:Nn \__mahjong_typeset_hand:n {x} \NewDocumentCommand{\mahjong}{O{\g_mahjong_default_height} m}{ \dim_set:Nn \l_mahjong_tile_height {#1} \mahjong_typeset_hand:n {#2} } \endinput %% %% End of file `mahjong.sty'.