summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/wordle/wordle.sty
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/latex/wordle/wordle.sty')
-rw-r--r--Master/texmf-dist/tex/latex/wordle/wordle.sty864
1 files changed, 618 insertions, 246 deletions
diff --git a/Master/texmf-dist/tex/latex/wordle/wordle.sty b/Master/texmf-dist/tex/latex/wordle/wordle.sty
index 4df1801ba02..a463f22837e 100644
--- a/Master/texmf-dist/tex/latex/wordle/wordle.sty
+++ b/Master/texmf-dist/tex/latex/wordle/wordle.sty
@@ -1,298 +1,670 @@
-% Author.........: C. Pierquet
-% licence........: Released under the LaTeX Project Public License v1.3c or later, see http://www.latex-project.org/lppl.txtf
-% Inspiration....: https://tex.stackexchange.com/questions/659860/wordle-like-colored-letter-boxes-in-latex
+% ---------------------------------------------------------------
+% wordle --- A latex package for typesetting wordle puzzles
+%
+% E-mail: andrew.mathas@gmail.com and cpierquet@outlook.fr
+% Released under the LaTeX Project Public License v1.3c or later
+% See http://www.latex-project.org/lppl.txt
+% ----------------------------------------------------------------
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{wordle}[2023/09/03 v0.1.1 Wordle grid]
-% 0.1.1 Coorection d'un bug sur la version anglaise
-% 0.1.0 Version initiale + quelques modèles
-%------Packages utiles
+% Package version
+\def\wordle@version{0.3.0}
+\def\wordle@release{2024-08-18}
+
+\providecommand\DeclareRelease[3]{}
+\providecommand\DeclareCurrentRelease[2]{}
+\DeclareRelease{\wordle@version}{\wordle@release}{wordle.sty}
+\DeclareCurrentRelease{}{\wordle@release}
+
+\ProvidesExplPackage{wordle} {\wordle@release} {\wordle@version}
+ {A latex package for typesetting wordle puzzles}
+
+% ----------------------------------------------------------------
+% Required packages
+%\RequirePackage{xcolor}
\RequirePackage{tikz}
-\RequirePackage{simplekv}
-\RequirePackage{xstring}
-%commandes utiles
-\usepackage{expl3}
-\ExplSyntaxOn
+% ----------------------------------------------------------------
+% predefined tile colours
+
+% from https://www.nytimes.com/games/wordle
+\definecolor{WordleAbsent} {HTML} {797D7F}
+\definecolor{WordlePresent} {HTML} {F7DA21}
+\definecolor{WordleCorrect} {HTML} {6AAB64}
+\definecolor{WordleEmpty} {HTML} {F5F5DC}
+
+\definecolor{WordleHardPresent} {HTML} {95BEFA}
+\definecolor{WordleHardCorrect} {HTML} {FB9B00}
+
+% from https://sutom.nocle.fr/#
+\definecolor{WordleSutomAbsent} {HTML} {0077B7}
+\definecolor{WordleSutomPresent} {HTML} {FFBB00}
+\definecolor{WordleSutomCorrect} {HTML} {EB2152}
+
+% ----------------------------------------------------------------
+% package variables
+
+\bool_new:N \l__wordle_case_sensitive_bool % case sensitive mode (false by default)
+\bool_new:N \l__wordle_strict_bool % strict mode (false by default)
+
+\dim_new:N \l__wordle_grid_dim
+\dim_new:N \l__wordle_rounded_dim
+\dim_new:N \l__wordle_sep_dim
+\dim_new:N \l__wordle_size_dim
+\dim_new:N \l__wordle_thickness_dim
+
+\int_new:N \l__wordle_rows_int
-%boite en [fr]
-\cs_new:Npn \l__sutom_boite_lettre:nn #1#2#3
+\fp_new:N \l__wordle_scale_fp
+
+\tl_new:N \l__wordle_align_tl
+\tl_new:N \l__wordle_depth_tl
+\tl_new:N \l__wordle_font_tl
+\tl_new:N \l__wordle_name_tl
+\tl_new:N \l__wordle_style_tl
+\tl_new:N \l__wordle_tikz_tl
+\tl_new:N \l__wordle_tile_style_tl
+
+\tl_new:N \l__wordle_present_border_tl
+\tl_new:N \l__wordle_present_colour_tl
+\tl_new:N \l__wordle_present_frame_tl
+\tl_new:N \l__wordle_present_shape_tl
+\tl_new:N \l__wordle_present_text_tl
+
+\tl_new:N \l__wordle_correct_border_tl
+\tl_new:N \l__wordle_correct_colour_tl
+\tl_new:N \l__wordle_correct_frame_tl
+\tl_new:N \l__wordle_correct_shape_tl
+\tl_new:N \l__wordle_correct_text_tl
+
+\tl_new:N \l__wordle_empty_border_tl
+\tl_new:N \l__wordle_empty_colour_tl
+\tl_new:N \l__wordle_empty_frame_tl
+\tl_new:N \l__wordle_empty_shape_tl
+\tl_new:N \l__wordle_empty_text_tl
+
+\tl_new:N \l__wordle_absent_border_tl
+\tl_new:N \l__wordle_absent_colour_tl
+\tl_new:N \l__wordle_absent_frame_tl
+\tl_new:N \l__wordle_absent_shape_tl
+\tl_new:N \l__wordle_absent_text_tl
+
+
+% ----------------------------------------------------------------
+% Assign up to four style attributes from comma separated list to absent,
+% present, correct, empty, respectively. If there is only one entry in
+% the list then everything is set equal to that entry
+\cs_new_nopar:Npn \__wordle_set_style:nn #1#2
{
- \ifboolKV[SUTOM]{Lettres}%
- {%
- \tikz \draw[rounded~corners=\fpeval{#3*\SutomUnit}cm,draw=\SutomBorder,line~width=\SutomWidth~mm,fill=#1] (0,0) rectangle++ (\SutomUnit,\SutomUnit) node[midway,font=\SutomFonte,text=\SutomFonteColor,scale=\SutomUnit] {#2} ;
- }%
- {%
- \tikz \draw[rounded~corners=\fpeval{#3*\SutomUnit}cm,draw=\SutomBorder,line~width=\SutomWidth~mm,fill=#1] (0,0) rectangle++ (\SutomUnit,\SutomUnit) ;
- }%
+ \seq_set_split:Nnn \l_tmpa_seq {,} {#2}
+ \int_compare:nNnTF {\seq_count:N \l_tmpa_seq} = {1}
+ {
+ \tl_set:co {l__wordle_absent_#1_tl} {#2}
+ \tl_set:co {l__wordle_present_#1_tl} {#2}
+ \tl_set:co {l__wordle_correct_#1_tl} {#2}
+ \tl_set:co {l__wordle_empty_#1_tl} {#2}
+ }
+ {
+ \seq_pop_left:NNT \l_tmpa_seq \l_tmpa_tl { \tl_set:co {l__wordle_absent_#1_tl} {\l_tmpa_tl} }
+ \seq_pop_left:NNT \l_tmpa_seq \l_tmpa_tl { \tl_set:co {l__wordle_present_#1_tl} {\l_tmpa_tl} }
+ \seq_pop_left:NNT \l_tmpa_seq \l_tmpa_tl { \tl_set:co {l__wordle_correct_#1_tl} {\l_tmpa_tl} }
+ \seq_pop_left:NNT \l_tmpa_seq \l_tmpa_tl { \tl_set:co {l__wordle_empty_#1_tl} {\l_tmpa_tl} }
+ }
}
-\cs_new:Npn \l__sutom_boite_lettre_rond:nn #1#2#3#4
+% apply the wordle styles
+\cs_new_nopar:Npn \__wordle_apply_style:n #1 {
+ \str_case:enF { #1 }
+ {
+ {hard}
+ {
+ \__wordle_set_style:nn {border} {white}
+ \__wordle_set_style:nn {colour} {WordleAbsent,WordleHardPresent,WordleHardCorrect,WordleEmpty}
+ \__wordle_set_style:nn {frame} {false}
+ \__wordle_set_style:nn {shape} {rectangle}
+ \__wordle_set_style:nn {text} {white,white,white,black}
+ }
+
+ {alt}
+ { % alt appears in the English version of Cedric's manual for sutom
+ \__wordle_set_style:nn {border} {white}
+ \__wordle_set_style:nn {colour} {WordleSutomAbsent,WordleSutomPresent,WordleSutomCorrect,WordleEmpty}
+ \__wordle_set_style:nn {frame} {false,true,false,false}
+ \__wordle_set_style:nn {shape} {rectangle,circle,rectangle,circle}
+ \__wordle_set_style:nn {text} {white,white,white,black}
+ \tl_set:Nn \l_wordle_font_tl {\LARGE\bfseries\sffamily}
+
+ }
+
+ {sutom}
+ {
+ \__wordle_set_style:nn {border} {white}
+ \__wordle_set_style:nn {colour} {WordleSutomAbsent,WordleSutomPresent,WordleSutomCorrect,WordleEmpty}
+ \__wordle_set_style:nn {frame} {false,true,false,false}
+ \__wordle_set_style:nn {shape} {rectangle,circle,rectangle,circle}
+ \__wordle_set_style:nn {text} {white,white,white,black}
+ \tl_set:Nn \l_wordle_font_tl {\LARGE\bfseries\sffamily}
+ }
+ }
+ {
+ % default style
+ \__wordle_set_style:nn {border} {white}
+ \__wordle_set_style:nn {colour} {WordleAbsent,WordlePresent,WordleCorrect,WordleEmpty}
+ \__wordle_set_style:nn {frame} {false}
+ \__wordle_set_style:nn {shape} {rectangle}
+ \__wordle_set_style:nn {text} {white,white,white,black}
+ }
+}
+
+% rescale dimensions
+\cs_new_nopar:Npn \__wordle_rescale:n #1
{
- \IfStrEq{\SutomStyle}{rond}
- {%
- \tikz {\draw[rounded~corners=\fpeval{#4*\SutomUnit}cm,draw=\SutomBorder,line~width=\SutomWidth~mm,fill=#1] (0,0) rectangle++ (\SutomUnit,\SutomUnit) ;
- \ifboolKV[SUTOM]{Lettres}%
- {%
- \draw[line~width=\SutomWidth~mm,draw=#2,fill=#2] ({0.5*\SutomUnit},{0.5*\SutomUnit}) circle[radius=\fpeval{0.5*\SutomUnit-0.1*\SutomWidth}] node[font=\SutomFonte,text=\SutomFonteColor,scale=\SutomUnit] {#3} ;
- }%
- {%
- \draw[line~width=\SutomWidth~mm,draw=#2,fill=#2] ({0.5*\SutomUnit},{0.5*\SutomUnit}) circle[radius=\fpeval{0.5*\SutomUnit-0.1*\SutomWidth}];
- }%
- }%
- }%
- {%
- \ifboolKV[SUTOM]{Lettres}%
- {%
- \tikz \draw[rounded~corners=\fpeval{#4*\SutomUnit}cm,line~width=0\SutomWidth~mm,draw=\SutomBorder,fill=#2] (0,0) rectangle++ (\SutomUnit,\SutomUnit) node[midway,font=\SutomFonte,text=\SutomFonteColor,scale=\SutomUnit] {#3} ;
- }%
- {%
- \tikz \draw[rounded~corners=\fpeval{#4*\SutomUnit}cm,line~width=\SutomWidth~mm,draw=\SutomBorder,fill=#2] (0,0) rectangle++ (\SutomUnit,\SutomUnit) ;
- }%
- }%
+ \fp_set:Nn \l__wordle_scale_fp {#1}
+ \dim_set:Nn \l__wordle_rounded_dim { \fp_eval:n {#1*\dim_to_decimal_in_mm:n {\l__wordle_rounded_dim }}mm }
+ \dim_set:Nn \l__wordle_sep_dim { \fp_eval:n {#1*\dim_to_decimal_in_mm:n {\l__wordle_sep_dim }}mm }
+ \dim_set:Nn \l__wordle_size_dim { \fp_eval:n {#1*\dim_to_decimal_in_mm:n {\l__wordle_size_dim }}mm }
+ \dim_set:Nn \l__wordle_thickness_dim { \fp_eval:n {#1*\dim_to_decimal_in_mm:n {\l__wordle_thickness_dim}}mm }
}
-%boite en [en]
-\cs_new:Npn \l__wordle_boite_lettre:nn #1#2#3
+
+% ----------------------------------------------------------------
+% just in case we're running an old version of latex
+\providecommand \IfFormatAtLeastTF { \@ifl@t@r \fmtversion }
+
+\IfFormatAtLeastTF { 2022-06-01 }
+ { \ProcessKeyOptions [ wordle ] }
+ {
+ \RequirePackage { l3keys2e }
+ \ProcessKeysOptions { wordle }
+ }
+
+% ----------------------------------------------------------------
+% Define keys for the package options and their defaults
+
+\keys_define:nn { wordle }
{
- \ifboolKV[WORDLE]{Letters}%
- {%
- \tikz \draw[rounded~corners=\fpeval{#3*\SutomUnit}cm,draw=\SutomBorder,line~width=\SutomWidth~mm,fill=#1] (0,0) rectangle++ (\SutomUnit,\SutomUnit) node[midway,font=\SutomFonte,text=\SutomFonteColor,scale=\SutomUnit] {#2} ;
- }%
- {%
- \tikz \draw[rounded~corners=\fpeval{#3*\SutomUnit}cm,draw=\SutomBorder,line~width=\SutomWidth~mm,fill=#1] (0,0) rectangle++ (\SutomUnit,\SutomUnit) ;
- }%
+ % apply puzzle styles: sets colours of absent, present, correct and empty tiles
+ style .code:n = {
+ \seq_set_from_clist:Nn \l_tmpa_seq {#1}
+ \seq_map_inline:Nn \l_tmpa_seq { \__wordle_apply_style:n { \str_lowercase:n{##1}} }
+ },
+ Style .meta:n = { style = #1 },
+ style .initial:n = standard,
+
+ % specifying tile colours and shapes
+ borders .code:n = { \__wordle_set_style:nn {border} {#1} },
+ BorderColor .code:n = { \__wordle_set_style:nn {border} {#1} },
+ CouleurBordures.code:n = { \__wordle_set_style:nn {border} {#1} },
+
+ Couleurs .code:n = { \__wordle_set_style:nn {colour} {#1} },
+ colours .code:n = { \__wordle_set_style:nn {colour} {#1} },
+
+ frames .code:n = { \__wordle_set_style:nn {frame} {#1} },
+ Cadres .code:n = { \__wordle_set_style:nn {frame} {#1} },
+ frames .default:n = true,
+ shapes .code:n = { \__wordle_set_style:nn {shape} {#1} },
+ Formes .code:n = { \__wordle_set_style:nn {shape} {#1} },
+
+ % text colour
+ text .code:n = { \__wordle_set_style:nn {text} {#1} },
+ CouleurLettres .code:n = { \__wordle_set_style:nn {text} {#1} },
+
+ % align letters in puzzle
+ align .code:n = {
+ \tl_set:Nn \l__wordle_align_tl {\vphantom{azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN}}
+ \tl_set:Nn \l__wordle_depth_tl {text~depth=0pt}
+ },
+ noalign .code:n = {
+ \tl_set:Nn \l__wordle_align_tl {}
+ \tl_set:Nn \l__wordle_depth_tl {}
+ },
+ nonalign .meta:n = { noalign },
+ align .initial:n = {true},
+
+ absent .tl_set:N = \l__wordle_absent_colour_tl,
+ absent~color .tl_set:N = \l__wordle_absent_colour_tl,
+ couleur~absent .tl_set:N = \l__wordle_absent_colour_tl,
+ absent~colour .tl_set:N = \l__wordle_absent_colour_tl,
+ bordure~absent .tl_set:N = \l__wordle_absent_border_tl,
+ absent~border .tl_set:N = \l__wordle_absent_border_tl,
+ absent~frame .tl_set:N = \l__wordle_absent_frame_tl,
+ cadre~absent .tl_set:N = \l__wordle_absent_frame_tl,
+ absent~frame .default:n = true,
+ absent~shape .tl_set:N = \l__wordle_absent_shape_tl,
+ forme~absent .tl_set:N = \l__wordle_absent_shape_tl,
+ absent~text .tl_set:N = \l__wordle_absent_text_tl,
+ coultxt~absent .tl_set:N = \l__wordle_absent_text_tl,
+
+ correct .tl_set:N = \l__wordle_correct_colour_tl,
+ correct~color .tl_set:N = \l__wordle_correct_colour_tl,
+ correct~colour .tl_set:N = \l__wordle_correct_colour_tl,
+ couleur~correct.tl_set:N = \l__wordle_correct_colour_tl,
+ correct~border .tl_set:N = \l__wordle_correct_border_tl,
+ bordure~correct.tl_set:N = \l__wordle_correct_border_tl,
+ correct~frame .tl_set:N = \l__wordle_correct_frame_tl,
+ cadre~correct .tl_set:N = \l__wordle_correct_frame_tl,
+ correct~frame .default:n = true,
+ correct~shape .tl_set:N = \l__wordle_correct_shape_tl,
+ forme~correct .tl_set:N = \l__wordle_correct_shape_tl,
+ correct~text .tl_set:N = \l__wordle_correct_text_tl,
+ coultxt~correct.tl_set:N = \l__wordle_correct_text_tl,
+
+ empty .tl_set:N = \l__wordle_empty_colour_tl,
+ couleur~vide .tl_set:N = \l__wordle_empty_colour_tl,
+ empty~color .tl_set:N = \l__wordle_empty_colour_tl,
+ empty~colour .tl_set:N = \l__wordle_empty_colour_tl,
+ empty~border .tl_set:N = \l__wordle_empty_border_tl,
+ bordure~vide .tl_set:N = \l__wordle_empty_border_tl,
+ empty~frame .tl_set:N = \l__wordle_empty_frame_tl,
+ cadre~vide .tl_set:N = \l__wordle_empty_frame_tl,
+ empty~frame .default:n = true,
+ empty~shape .tl_set:N = \l__wordle_empty_shape_tl,
+ forme~vide .tl_set:N = \l__wordle_empty_shape_tl,
+ empty~text .tl_set:N = \l__wordle_empty_text_tl,
+ coultxt~vide. tl_set:N = \l__wordle_empty_text_tl,
+
+ present .tl_set:N = \l__wordle_present_colour_tl,
+ couleur~present.tl_set:N = \l__wordle_present_colour_tl,
+ present~color .tl_set:N = \l__wordle_present_colour_tl,
+ present~colour .tl_set:N = \l__wordle_present_colour_tl,
+ present~border .tl_set:N = \l__wordle_present_border_tl,
+ bordure~present.tl_set:N = \l__wordle_present_border_tl,
+ present~frame .tl_set:N = \l__wordle_present_frame_tl,
+ cadre~present .tl_set:N = \l__wordle_present_frame_tl,
+ present~frame .default:n = true,
+ present~shape .tl_set:N = \l__wordle_present_shape_tl,
+ forme~present .tl_set:N = \l__wordle_present_shape_tl,
+ present~text .tl_set:N = \l__wordle_present_text_tl,
+ coultxt~present.tl_set:N = \l__wordle_present_text_tl,
+
+ % text font
+ font .tl_set:N = \l__wordle_font_tl,
+ Fonte .tl_set:N = \l__wordle_font_tl,
+ Police .tl_set:N = \l__wordle_font_tl,
+ font .initial:n = \Large\bfseries\sffamily,
+
+ % tile size
+ size .dim_set:N = \l__wordle_size_dim,
+ Taille .dim_set:N = \l__wordle_size_dim,
+ size .initial:n = 8mm,
+
+ % thickness of tile border
+ thickness .dim_set:N = \l__wordle_thickness_dim,
+ Epaisseur .dim_set:N = \l__wordle_thickness_dim,
+ Thick .code:n = {\dim_set:Nn \l__wordle_thickness_dim {#1mm}},
+ thickness .initial:n = 0.25mm,
+
+ % rounded-corner = #
+ rounded .dim_set:N = \l__wordle_rounded_dim,
+ Arrondi .dim_set:N = \l__wordle_rounded_dim,
+ rounded .default:n = 4pt,
+ Rounded .code:n = {\dim_set:Nn \l__wordle_rounded_dim {#1mm}},
+ rounded .initial:n = 1mm,
+
+ % separation between tiles
+ separation .dim_set:N = \l__wordle_sep_dim,
+ Separation .dim_set:N = \l__wordle_sep_dim,
+ separation .initial:n = 0.5mm,
+
+ % rescale tiles
+ scale .code:n = { \__wordle_rescale:n {#1} },
+ Echelle .code:n = { \__wordle_rescale:n {#1} },
+ scale .initial:n = 1,
+ Unit .code:n = { \__wordle_rescale:n {#1} },
+ Unite .code:n = { \__wordle_rescale:n {#1} },
+
+ % letter case
+ case~sensitive .bool_set:N = \l__wordle_case_sensitive_bool,
+ case~sensitive .default:n = true,
+ case~sensitive .initial:n = false,
+
+ % letter visibility
+ letters .code:n = {\cs_set_eq:NN \__wordle_letter:n \__wordle_letter_natural:n},
+ Lettres .code:n = {\cs_set_eq:NN \__wordle_letter:n \__wordle_letter_natural:n},
+ noletters .code:n = {\cs_set_eq:NN \__wordle_letter:n \__wordle_letter_none:n},
+ NonLettres .code:n = {\cs_set_eq:NN \__wordle_letter:n \__wordle_letter_none:n},
+ letters .initial:n = true,
+
+ % forced letter case
+ natural~case .code:n = {
+ \cs_set_eq:NN \__wordle_letter:n \__wordle_letter_natural:n
+ },
+ lower~case .code:n = {
+ \cs_set_eq:NN \__wordle_letter:n \__wordle_letter_lower:n
+ \bool_set_false:N \l__wordle_case_sensitive_bool
+ },
+ upper~case .code:n = {
+ \cs_set_eq:NN \__wordle_letter:n \__wordle_letter_upper:n
+ \bool_set_false:N \l__wordle_case_sensitive_bool
+ },
+
+ % puzzle specs: rows and columns
+ rows .int_set:N = \l__wordle_rows_int,
+ Lignes .int_set:N = \l__wordle_rows_int,
+ rows .initial:n = 0,
+
+ strict .bool_set:N = \l__wordle_strict_bool,
+ Strict .bool_set:N = \l__wordle_strict_bool,
+ strict .default:n = true,
+ strict .initial:n = false,
+
+ % tikz settings
+ tile~style .tl_set:N = \l__wordle_tile_style_tl,
+ Style~case .tl_set:N = \l__wordle_tile_style_tl,
+ tile~style .initial:n = ,
+
+ name .tl_set:N = \l__wordle_name_tl,
+ Nom .tl_set:N = \l__wordle_name_tl,
+ name .initial:n = W,
+ tikz .tl_set:N = \l__wordle_tikz_tl,
+ tikz .initial:n = ,
+}
+
+% user settings
+\NewDocumentCommand\WordleSetup{ m }{ \keys_set:nn { wordle } {#1} }
+\NewDocumentCommand\ParamsSutom{ m }{ \keys_set:nn { wordle } {#1} }
+
+% ----------------------------------------------------------------
+% Define TikZ Wordle styles for the letters. Using tikz styles both
+% ensures consistency and has the added advantage of taking care of
+% expansion issues with the tile settings
+\tikzset{/Wordle/.is~family, /Wordle,
+ tile/.style = {
+ /tikz, % change back to using tikz keys
+ inner~sep = \l__wordle_sep_dim,
+ minimum~height = \l__wordle_size_dim,
+ minimum~size = \l__wordle_size_dim,
+ rounded~corners= \l__wordle_rounded_dim,
+ line~width = \l__wordle_thickness_dim,
+ font = \l__wordle_font_tl,
+ % scale = \fp_to_decimal:N \l__wordle_scale_fp,
+ text = \tl_use:c {l__wordle_#1_text_tl},
+ fill = \tl_use:c {l__wordle_#1_colour_tl},
+ shape = \tl_use:c {l__wordle_#1_shape_tl},
+ },
+ frame/.style = {
+ /Wordle/tile=#1,
+ /tikz, % change back to using tikz keys
+ draw = \tl_use:c{l__wordle_#1_border_tl},
+ minimum~size = {\l__wordle_size_dim+\l__wordle_thickness_dim},
+ fill = \tl_use:c {l__wordle_#1_colour_tl},
+ shape = rectangle,
+ },
}
-\cs_new:Npn \l__wordle_boite_lettre_rond:nn #1#2#3#4
+% apply a TikZ setting
+\cs_new_nopar:Npn \__wordle_tikzset:n #1 { \exp_args:Nx \tikzset{#1} }
+
+% ----------------------------------------------------------------
+% preprocessing of the wordle letters
+\cs_new_nopar:Npn \__wordle_letter_none:n #1 {}
+\cs_new_nopar:Npn \__wordle_letter_natural:n #1 {#1}
+\cs_new_nopar:Npn \__wordle_letter_lower:n #1 { \str_lowercase:n {#1} }
+\cs_new_nopar:Npn \__wordle_letter_upper:n #1 { \str_uppercase:n {#1} }
+
+% by default wordle letters are not processed
+\cs_set_eq:NN \__wordle_letter:n \__wordle_letter_natural:n
+
+% Print a letter in a box as a node. There is slightly different behaviour
+% depending on whether the tile is frames or we are in strict mode. The way
+% that the entry is printed depends is controlled by \__wordle_letter:n.
+\cs_new_nopar:Npn \wordle__boxed_letter:nn #1#2
{
- \IfStrEq{\SutomStyle}{default}
- {%
- \ifboolKV[WORDLE]{Letters}%
- {%
- \tikz \draw[rounded~corners=\fpeval{#4*\SutomUnit}cm,line~width=\SutomWidth~mm,draw=\SutomBorder,fill=#2] (0,0) rectangle++ (\SutomUnit,\SutomUnit) node[midway,font=\SutomFonte,text=\SutomFonteColor,scale=\SutomUnit] {#3} ;
- }%
- {%
- \tikz \draw[rounded~corners=\fpeval{#4*\SutomUnit}cm,line~width=\SutomWidth~mm,draw=\SutomBorder,fill=#2] (0,0) rectangle++ (\SutomUnit,\SutomUnit) ;
- }%
- }%
- {%
- \tikz {\draw[rounded~corners=\fpeval{#4*\SutomUnit}cm,draw=\SutomBorder,line~width=\SutomWidth~mm,fill=#1] (0,0) rectangle++ (\SutomUnit,\SutomUnit) ;
- \ifboolKV[WORDLE]{Letters}%
- {%
- \draw[line~width=\SutomWidth~mm,draw=#2,fill=#2] ({0.5*\SutomUnit},{0.5*\SutomUnit}) circle[radius=\fpeval{0.5*\SutomUnit-0.1*\SutomWidth}] node[font=\SutomFonte,text=\SutomFonteColor,scale=\SutomUnit] {#3} ;
- }%
- {%
- \draw[line~width=\SutomWidth~mm,draw=#2,fill=#2] ({0.5*\SutomUnit},{0.5*\SutomUnit}) circle[radius=\fpeval{0.5*\SutomUnit-0.1*\SutomWidth}];
- }%
- }%
- }%
+ % determine the node name, which takes the form <W>-<row>-<col>
+ \tl_set:No \l_tmpa_tl
+ {
+ \l__wordle_name_tl-\int_eval:n{1+\l__wordle_row_index_int}-\int_use:N\l__wordle_letter_index_int
+ }
+
+ % the construction of the node depends on whether the tile is framed
+ \tl_if_eq:cnTF {l__wordle_#1_frame_tl} {true}
+ {
+ % draw the frame
+ \node[/Wordle/frame=absent] % frame use the absent fill colour
+ at ({\l__wordle_letter_index_int*\l__wordle_grid_dim},{-\l__wordle_row_index_int*\l__wordle_grid_dim}){};
+ % draw the tile
+ \node[/Wordle/tile=#1]
+ (\l_tmpa_tl) at ({\l__wordle_letter_index_int*\l__wordle_grid_dim},
+ {-\l__wordle_row_index_int*\l__wordle_grid_dim})
+ { \l__wordle_align_tl\__wordle_letter:n {#2} };
+ }
+ {
+ % draw the tile, with a border
+ \node[/Wordle/frame=#1, /Wordle/tile=#1]
+ (\l_tmpa_tl) at ({\l__wordle_letter_index_int*\l__wordle_grid_dim},
+ {-\l__wordle_row_index_int*\l__wordle_grid_dim})
+ { \l__wordle_align_tl\__wordle_letter:n {#2} };
+ }
+
+ % if strict then put a slash through any extra letters
+ \bool_if:NT \l__wordle_strict_bool
+ {
+ \int_compare:nNnT {\l__wordle_letter_index_int} > {\seq_count:N \l__wordle_answer_seq }
+ {
+ \draw[red,ultra~thick] (\tl_use:N\l_tmpa_tl.south~west)--(\tl_use:N\l_tmpa_tl.north~east);
+ }
+ }
}
-\seq_new:N \l_wordle_seq % the answer
-\prop_new:N \l_wordle_prop % count letters in wordle
-\seq_new:N \l_words_seq % list of all words
-\prop_new:N \l_word_prop % count letters in word
-\int_new:N \l_letter_int % index of current letter in word
+\seq_new:N \l__wordle_answer_seq % the answer
+\prop_new:N \l__wordle_answer_counts_prop % count letters in wordle
+\seq_new:N \l__wordle_solution_seq % list of all words
+\prop_new:N \l__wordle_word_counts_prop % count letters in word
+\int_new:N \l__wordle_letter_index_int % index of current letter in word
+\int_new:N \l__wordle_row_index_int % TikZ row index in solution
-% a conditional for nonnegative prop counter in \l_word_prop
-\prg_new_protected_conditional:Npnn \if_wordle_letter_nonnegative:n #1 {TF}
+% a conditional for non-negative prop counter in \l__wordle_word_counts_prop
+\prg_new_protected_conditional:Npnn \if__wordle_letter_nonnegative:n #1 {TF}
{
- \prop_if_in:NnTF \l_word_prop {#1}
- { % letter in in prop
- \prop_get:NnN \l_word_prop {#1} \l_tmpa_tl
- \int_compare:nNnTF {\l_tmpa_tl} < {0}
- {\prg_return_false:} {\prg_return_true:}
- }
- {\prg_return_false:}
+ \prop_if_in:NnTF \l__wordle_word_counts_prop {#1}
+ { % letter in in prop
+ \prop_get:NnN \l__wordle_word_counts_prop {#1} \l_tmpa_tl
+ \int_compare:nNnTF {\l_tmpa_tl} < {0}
+ {\prg_return_false:} {\prg_return_true:}
+ }
+ {\prg_return_false:}
}
+\cs_generate_variant:Nn \str_if_eq:nVTF {xVTF}
+
% a conditional for comparing letters
-\prg_new_protected_conditional:Npnn \if_wordle_letters_agree:n #1 {T, TF}
+\prg_new_protected_conditional:Npnn \if__wordle_letters_agree:n #1 {T, TF}
{
- \str_set:Nx \l_tmpa_str {\seq_item:Nn \l_wordle_seq {\l_letter_int}}
- \str_if_eq:nVTF {#1} \l_tmpa_str {\prg_return_true:} {\prg_return_false:}
+ \str_set:Nx \l_tmpa_str
+ {\seq_item:Nn \l__wordle_answer_seq {\l__wordle_letter_index_int}}
+
+
+ \bool_if:NTF \l__wordle_case_sensitive_bool
+ {\str_if_eq:nVTF {#1} \l_tmpa_str {\prg_return_true:} {\prg_return_false:}}
+ {\str_if_eq:xVTF {\str_uppercase:n{#1}} \l_tmpa_str {\prg_return_true:} {\prg_return_false:}}
}
% add #3 to <prop=#1>.#2
-\cs_new_protected:Npn \wordle__add_to_prop_counter:Nnn #1#2#3
+\cs_new_nopar:Npn \wordle__add_to_prop_counter:Nnn #1#2#3
{
- \prop_put_if_new:Nnn #1 {#2} {0}
- \prop_pop:NnN #1 {#2} \l_tmp_a
- \prop_put:Nnx #1 {#2} {\int_eval:n {#3+\l_tmp_a}}
+ \prop_put_if_new:Nnn #1 {#2} {0}
+ \prop_pop:NnN #1 {#2} \l_tmp_a
+ \prop_put:Nnx #1 {#2} {\int_eval:n {#3+\l_tmp_a}}
}
-% make \l_wordle_prop<x> = #x's in wordle_seq
-\cs_new_protected:Npn \count_letters_in_wordle:n #1
+% make \l__wordle_answer_counts_prop<x> = #x's in wordle_seq
+\cs_new_nopar:Npn \wordle__count_letters_in_answer:n #1
{
- \wordle__add_to_prop_counter:Nnn \l_wordle_prop {#1} {1}%
+ \wordle__add_to_prop_counter:Nnn \l__wordle_answer_counts_prop {#1} {1}
}
% first run: subtract correct matches from letter counts
-\cs_new:Npn \count_letters_in_word:n #1
+\cs_new_nopar:Npn \wordle__count_letters_in_word:n #1
{
- \int_incr:N \l_letter_int
- \if_wordle_letters_agree:nT {#1}
- { \wordle__add_to_prop_counter:Nnn \l_word_prop {#1} {-1} }%
+ \int_incr:N \l__wordle_letter_index_int
+ \if__wordle_letters_agree:nT {#1}
+ { \wordle__add_to_prop_counter:Nnn \l__wordle_word_counts_prop {#1} {-1} }
}
-%commande [fr]
% on the second run we print a coloured wordle word
-\cs_new:Npn \write_letters_in_word:n #1
+\cs_new_nopar:Npn \wordle__write_letters_in_word:n #1
{
- \int_incr:N \l_letter_int
- \if_wordle_letters_agree:nTF {#1}
- { \l__sutom_boite_lettre:nn {\SutomBienPlacee}{#1}{\SutomRounded} }
- {
- % subtract 1 from the prop counter
- \wordle__add_to_prop_counter:Nnn \l_word_prop {#1} {-1}
- % if the counter is non-negative this is a pseudo match
- \if_wordle_letter_nonnegative:nTF {#1}
- { \l__sutom_boite_lettre_rond:nn {\SutomCoulFond}{\SutomCoulMalPlacee}{#1}{\SutomRounded} }
- { \l__sutom_boite_lettre:nn {\SutomCoulFond}{#1}{\SutomRounded} }
- }%
+ \int_incr:N \l__wordle_letter_index_int
+ \if__wordle_letters_agree:nTF {#1}
+ { \wordle__boxed_letter:nn {correct} {#1} }
+ {
+ % subtract 1 from the prop counter
+ \wordle__add_to_prop_counter:Nnn \l__wordle_word_counts_prop {#1} {-1}
+ % if the counter is non-negative this is a pseudo match
+ \if__wordle_letter_nonnegative:nTF {#1}
+ { \wordle__boxed_letter:nn {present} {#1} }
+ { \wordle__boxed_letter:nn {absent} {#1} }
+ }
}
-%commande [en]
-% on the second run we print a coloured wordle word
-\cs_new:Npn \write_letters_in_wordle:n #1
+\cs_generate_variant:Nn \seq_set_split:Nnn {Nnx}
+\cs_generate_variant:Nn \cs_set_nopar:Nn {NV}
+
+% typeset the word "#1", colouring letters using the wordle convention
+\cs_new_nopar:Npn \wordle__mark_word:n #1
{
- \int_incr:N \l_letter_int
- \if_wordle_letters_agree:nTF {#1}
- { \l__wordle_boite_lettre:nn {\SutomBienPlacee}{#1}{\SutomRounded} }
- {
- % subtract 1 from the prop counter
- \wordle__add_to_prop_counter:Nnn \l_word_prop {#1} {-1}
- % if the counter is non-negative this is a pseudo match
- \if_wordle_letter_nonnegative:nTF {#1}
- { \l__wordle_boite_lettre_rond:nn {\SutomCoulFond}{\SutomCoulMalPlacee}{#1}{\SutomRounded} }
- { \l__wordle_boite_lettre:nn {\SutomCoulFond}{#1}{\SutomRounded} }
- }%
-}
+ \str_if_eq:nnTF {#1} {*}
+ {
+ \cs_set_eq:NN \wordle__process_word:n \wordle__empty_word:n
+ }
+ {
+ \prop_set_eq:NN \l__wordle_word_counts_prop \l__wordle_answer_counts_prop
+ \tl_map_function:nN {#1} \wordle__count_letters_in_word:n
+ \int_zero:N \l__wordle_letter_index_int
+ \tl_map_function:nN {#1} \wordle__write_letters_in_word:n
-%clés [fr]
-\defKV[SUTOM]{%
- Couleurs=\def\SutomCouleurs{#1},%
- Arrondi=\def\SutomRounded{#1},%
- Unite=\def\SutomUnit{#1},%
- Police=\def\SutomFonte{#1},%
- CouleurLettres=\def\SutomFonteColor{#1},%
- Style=\def\SutomStyle{#1},%
- Epaisseur=\def\SutomWidth{#1},%
- CouleurBordure=\def\SutomBorder{#1}
-}
+ % if strict then check lengths
+ \bool_if:NT \l__wordle_strict_bool
+ {
+ \int_while_do:nNnn {\l__wordle_letter_index_int} < {\seq_count:N\l__wordle_answer_seq}
+ {
+ \int_incr:N \l__wordle_letter_index_int
+ \wordle__boxed_letter:nn {absent} {\c_space_tl}
+ }
+ }
-\setKVdefault[SUTOM]{%
- Couleurs={cyan!75!black,yellow,red},%
- Arrondi=0.1,%
- Unite=1,%
- Police=\LARGE\bfseries\sffamily,%
- CouleurLettres=white,%
- Lettres=true,%
- Style=rond,%
- Epaisseur=0.25,%
- CouleurBordure=white
+ % increment the row index
+ \int_incr:N \l__wordle_row_index_int
+ }
}
-%environnement [fr]
-\NewDocumentEnvironment{GrilleSutom}{ O{} m b }%
-{%
- \restoreKV[SUTOM]%
- \setKV[SUTOM]{#1}%
- \StrBefore{\SutomCouleurs}{,}[\SutomCoulFond]%
- \StrBetween[1,2]{\SutomCouleurs}{,}{,}[\SutomCoulMalPlacee]%
- \StrBehind[2]{\SutomCouleurs}{,}[\SutomBienPlacee]%
- \StrLen{#2}[\SutomNbLettres]%
- \def\SutomLarg{\fpeval{1.01*\SutomUnit*\SutomNbLettres}}%
- \begin{minipage}{\SutomLarg~cm}
- \lineskip=0pt%
- \parindent=0pt%
- % split the answer into letters
- \seq_set_split:Nnn \l_wordle_seq {} {#2}
- % we need to count the number of times each letter appears in \l_wordle_seq
- \prop_clear:N \l_wordle_prop
- \tl_map_function:nN {#2} \count_letters_in_wordle:n
- % split the solution into words
- \regex_split:nnN {\s} {#3} \l_words_seq
- % process the words
- \seq_map_inline:Nn \l_words_seq
- {
- \int_zero:N \l_letter_int
- \prop_set_eq:NN \l_word_prop \l_wordle_prop
- \tl_map_function:nN {##1} \count_letters_in_word:n
- \int_zero:N \l_letter_int
- \tl_map_function:nN {##1} \write_letters_in_word:n
- \par
- }
-}%
-{%
- \end{minipage}%
+% typeset the word "#1" by putting boxes around each letter
+\cs_new_nopar:Npn \wordle__empty_word:n #1
+{
+ \tl_map_inline:nn {#1}
+ {
+ \int_incr:N \l__wordle_letter_index_int
+ \wordle__boxed_letter:nn {empty} {##1}
+ }
+ % if strict then check lengths
+ \bool_if:NT \l__wordle_strict_bool
+ {
+ \int_while_do:nNnn {\l__wordle_ltter_index_int} < {\seq_count:N\l__wordle_answer_seq}
+ {
+ \int_incr:N \l__wordle_letter_index_int
+ \wordle__boxed_letter:nn {empty} {\c_space_tl}
+ }
+ }
+ \int_incr:N \l__wordle_row_index_int
}
-%clés [en]
-\definecolor{WordleBack}{HTML}{797D7F}
-\definecolor{WordleBad}{HTML}{CAB557}
-\definecolor{WordleGood}{HTML}{6AAB64}
-
-\defKV[WORDLE]{%
- Colors=\def\SutomCouleurs{#1},%
- Rounded=\def\SutomRounded{#1},%
- Unit=\def\SutomUnit{#1},%
- Fonte=\def\SutomFonte{#1},%
- ColorLetters=\def\SutomFonteColor{#1},%
- Style=\def\SutomStyle{#1},%
- Thickness=\def\SutomWidth{#1},%
- BorderColor=\def\SutomBorder{#1}
-}
+\cs_set_eq:NN \wordle__process_word:n \wordle__mark_word:n
-\setKVdefault[WORDLE]{%
- Colors={WordleBack,WordleBad,WordleGood},%
- Rounded=0.1,%
- Unit=1,%
- Fonte=\LARGE\bfseries\sffamily,%
- CouleurLettres=white,%
- Letters=true,%
- Style=default,%
- Thick=0.25,%
- BorderColor=white
-}
+\NewDocumentEnvironment{wordle}{ O{} m O{} b }
+{
+ % apply wordle environment options
+ \WordleSetup{#1}
+ \begin{tikzpicture}
-%environnement [en]
-\NewDocumentEnvironment{WordleGrid}{ O{} m b }
-{%
- \restoreKV[WORDLE]%
- \setKV[WORDLE]{#1}%
- \StrBefore{\SutomCouleurs}{,}[\SutomCoulFond]%
- \StrBetween[1,2]{\SutomCouleurs}{,}{,}[\SutomCoulMalPlacee]%
- \StrBehind[2]{\SutomCouleurs}{,}[\SutomBienPlacee]%
- \StrLen{#2}[\SutomNbLettres]%
- \def\SutomLarg{\fpeval{1.01*\SutomUnit*\SutomNbLettres}}%
- \begin{minipage}{\SutomLarg~cm}
- \parindent=0pt
- \lineskip=0pt
- % split the answer into letters
- \seq_set_split:Nnn \l_wordle_seq {} {#2}
- % we need to count the number of times each letter appears in \l_wordle_seq
- \prop_clear:N \l_wordle_prop
- \tl_map_function:nN {#2} \count_letters_in_wordle:n
- % split the solution into words
- \regex_split:nnN {\s} {#3} \l_words_seq
- % process the words
- \seq_map_inline:Nn \l_words_seq
- {
- \int_zero:N \l_letter_int
- \prop_set_eq:NN \l_word_prop \l_wordle_prop
- \tl_map_function:nN {##1} \count_letters_in_word:n
- \int_zero:N \l_letter_int
- \tl_map_function:nN {##1} \write_letters_in_wordle:n
- \par
- }
-}%
-{%
- \end{minipage}%
-}
+ % apply any tikz settings -- we need to some expansion trickery to do this
+ \__wordle_tikzset:n {\l__wordle_tikz_tl}
+ \__wordle_tikzset:n {/Wordle/tile/.append~style={\l__wordle_depth_tl,\l__wordle_tile_style_tl}}
+
+ % set grid dimension = box size + separation
+ \dim_set:Nn \l__wordle_grid_dim {\l__wordle_size_dim+\l__wordle_sep_dim}
+
+ % split the answer into letters
+ \bool_if:NTF \l__wordle_case_sensitive_bool
+ { \seq_set_split:Nnn \l__wordle_answer_seq {} {#2} }
+ { \seq_set_split:Nnx \l__wordle_answer_seq {} {\str_uppercase:n {#2}} }
+
+ % count the number of times letters appear in \l__wordle_answer_seq
+ \prop_clear:N \l__wordle_answer_counts_prop
+ \tl_map_function:nN {#2} \wordle__count_letters_in_answer:n
+
+ % split the solution into words
+ \regex_split:nnN {\s} {#4} \l__wordle_solution_seq
+
+ % process the words
+ \int_zero:N \l__wordle_row_index_int
+ \seq_map_inline:Nn \l__wordle_solution_seq
+ {
+ \int_zero:N \l__wordle_letter_index_int
+ \wordle__process_word:n {##1}
+ }
+
+ % if required, add extra required blank rows
+ \int_while_do:nNnn {\l__wordle_row_index_int} < {\l__wordle_rows_int}
+ {
+ \int_zero:N \l__wordle_letter_index_int
+ \int_while_do:nNnn {\l__wordle_letter_index_int} < {\seq_count:N\l__wordle_answer_seq}
+ {
+ \int_incr:N \l__wordle_letter_index_int
+ \wordle__boxed_letter:nn {empty} {\c_space_tl}
+ }
+ \int_incr:N \l__wordle_row_index_int
+ }
+
+ % finally, execute the optional TikZ commands
+ #3
+
+ \end{tikzpicture}
+}{}
+
+% wrapper environment for Gridwordle
+\NewDocumentEnvironment{GridWordle}{ O{} m O{} b }
+ {
+ \begin{wordle}[#1]{#2}[#3]#4]\end{wordle}
+ }
+ {}
+
+% wrapper environment for GrilleSutom
+\NewDocumentEnvironment{GrilleSutom}{ O{} m O{} b }
+ {
+ \begin{wordle}[style=sutom,#1]{#2}[#3]#4\end{wordle}
+ }
+ {}
-\ExplSyntaxOff
+\endinput
-\endinput \ No newline at end of file
+% ----------------------------------------------------------------
+% CHANGE LOG
+%
+% Version 0.3 - \wordle@release
+% - merged AM & CP packages, adding styles and streamlining options, french keys
+%
+% Version 0.2 - \wordle@release
+% - added documentation and cleaned some of the options
+%
+% Version 0.1 - 2022-10-01
+% - initial version
+%
+% ----------------------------------------------------------------
+%
+% Copyright (C) 2022-3 by Andrew Mathas <andrew.mathas@gmail.com>
+% and Cédric Pierquet cpierquet@outlook.fr
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License (LPPL), either
+% version 1.3c of this license or (at your option) any later
+% version. The latest version of this license is in the file:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This work is "maintained" (as per LPPL maintenance status) by
+% Andrew Mathas.
+%
+% This work consists of the files:
+% wordle.sty
+% wordle.tex