5

This is a sort-of follow-up to the question Create environment whose contents are passed to TikZ matrix, which did not reveal any solution to the specific question (but did make me aware of another package to try).

I need to create an environment to draw Sudoku grids, in which the syntax used is that of a tabular environment. That is, with cells delimited by & and new rows indicated by \\.

The following code is a solution using tabularray:

\documentclass[11pt]{article}
\usepackage{tabularray}
\usepackage{color}
\newenvironment{sudoku}[1][]{%
    \begin{tblr}{
        hline{1,4,7,10}={blue,2pt},
        hline{2,3,5,6,8,9}={blue,0.5pt},
        vline{1,4,7,10}={blue,2pt},
        vline{2,3,5,6,8,9}={blue,0.5pt},
        abovesep=3pt,
        #1
    }
}{%
    \end{tblr}
}
\begin{document}
\begin{sudoku}
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
\end{sudoku}
\end{document}

This would be perfect, except for the following:

  • It doesn't work at all on some devices (presumably something to do with the LaTeX 3 nature of the package)
  • On devices where it does work, the time taken to compile a tex file with 20 or 30 of these sudoku grids in is getting seriously problematic. (See here for a related post.)

So, I need something less computationally intensive: it's just a 9x9 grid, after all! Can anyone replace the code in the definition of the sudoku environment above to render a similar/the same result?

Besides tabularray Here are some things I've looked - this is not to say that one of these doesn't have a solution, but I haven't been able to work one out.

  1. Using tikz-matrix. This was the subject of my earlier post.

  2. Using nicematrix. I haven't found a way to specify (e.g.) that different \hlines can have different thicknesses.

  3. Using sudoku. Perhaps something can be done with catcodes to replace the normal syntax?

As a broader comment: we LaTeX users still seem to have to work with table-like structures in which the styling has to be embedded within the code for the table, rather than applied separately (if you're familiar with web-design, think of the distinction between the HTML and the CSS of a well-crafted page). That's why the tabularray is (almost) perfect.

Thanks in advance for any help!

rbrignall
  • 1,564
  • Is the use of an array mandatory? If not, why don't you just draw the grid then place numbers in it with a simple foreach loop, reading a data set? – SebGlav May 03 '22 at 15:12
  • The use of the tabular-style syntax is mandatory, yes. For accessibility reasons, the TeX source file has to be parsed by a computer system in which the sudoku environment must be regarded simply as a standard table. – rbrignall May 03 '22 at 15:18

5 Answers5

7

Plain TeX solution:

\newcount\suline
\def\thickline{1.4pt}
\def\sudokuA{\advance\suline by1 \ifnum\suline<10 \expandafter \sudokuB \fi}
\def\sudokuB#1&#2&#3&#4&#5&#6&#7&#8&#9{%
   \hbox{\vrule width\thickline
         \bx{#1}.\bx{#2}.\bx{#3}|%
         \bx{#4}.\bx{#5}.\bx{#6}|%
         \bx{#7}.\bx{#8}.\bx{#9}|}%
   \hrule \ifnum\numexpr \suline-(\suline/3)*3=0 height\thickline \fi
}
\def\bx#1#2{\hbox to1.5em{\lower.5em\vbox to1.5em{}\hss\ignorespaces#1\unskip\hss
                          \vrule \if|#2 width\thickline\fi}}

\def\sudoku#1{\vbox\bgroup \let\=\sudokuA \hrule height\thickline \#1\egroup }

\sudoku{ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ } \bye

And you can compare the speed...

wipet
  • 74,238
  • There might be a typo in \bx{#7}.\bx{#8}.\bx{#4}|}. Should be \bx{#7}.\bx{#8}.\bx{#9}|}. But very nice and fast solution. – SebGlav May 04 '22 at 07:49
5

Here is a programmation with nicematrix.

I don't know whether it is faster enough for you...

\documentclass[11pt]{article}
\usepackage{nicematrix,tikz}
\usepackage{color}

\NewDocumentEnvironment{sudoku} {} { \begin{NiceTabular}{*{9}{c}}[hvlines,rules={width=0.2pt,color=blue}] } { \CodeAfter \tikz \draw [line width=0.7pt,blue] (4-|1) -- (4-|10) (7-|1) -- (7-|10) (1-|4) -- (10-|4) (1-|7) -- (10-|7)
(1-|1) rectangle (10-|10) ; \end{NiceTabular} }

\begin{document} \begin{sudoku} 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ 1&2&3&4&5&6&7&8&9\ \end{sudoku}

\end{document}

Output of the above code

F. Pantigny
  • 40,250
  • 1
    Oooh, there is a way to do it in nicematrix! I'll have to benchmark the speed against the tabularray solution... – rbrignall May 03 '22 at 15:16
  • 2
    Ok, a quick test, to render 50 (identical) sudoku grids: nicematrix: 29 seconds. tabularray: 214 seconds. Nicematrix wins by an order of magnitude! – rbrignall May 03 '22 at 15:27
  • 2
    @rbrignall Plain TeX solution needs cca 0.35 seconds for creating 50 sudoku grids. – wipet May 04 '22 at 05:27
4

Ok, so not exactly what OP's asking for (since I didn't respect the tabular notation of the datas), but for further purpose, I think it could be nice to add a simple TikZ solution. I didn't take time to benchmark but it took less than 2 seconds to run for this single grid.

sudoku rendering with TikZ

\documentclass[12pt]{article}
\usepackage{tikz}

\tikzset{thck/.style={blue,line width=2pt},thn/.style={blue,line width=0.5pt}} \newcommand{\sudoku}[1]{% \begin{tikzpicture} \draw[thn] (0,0) grid (9,9); \draw[thck,line cap=rect] (0,0) grid[step=3] (9,9);

    \foreach \n [count=\i from 0] in {#1}
        {
        \pgfmathtruncatemacro{\x}{Mod(\i,9)}
        \pgfmathtruncatemacro{\y}{\i/9)}
        \node at (\x+0.5,9-\y-0.5) {\n};
        }
\end{tikzpicture}
}

\begin{document}
\sudoku{ 1,2,3,4,5,6,7,8,9, 9,8,7,6,5,4,3,2,1, 1,2,3,4,5,6,7,8,9, 1,2,3,4,5,6,7,8,9, 1,2,3,4,5,6,7,8,9, 1,2,3,4,5,6,7,8,9, 1,2,3,4,5,6,7,8,9, 1,2,3,4,5,6,7,8,9, 1,2,3,4,5,6,7,8,9 } \end{document}

SebGlav
  • 19,186
  • This is a nice solution - thanks for sharing (even though it doesn't fit with the rather exacting conditions I imposed!) – rbrignall May 03 '22 at 16:27
4

It doesn't work at all on some devices (presumably something to do with the LaTeX 3 nature of the package)

Although tabularray is a new package, it is included in TeX distributions for almost one year. You need to update your MikTeX or TeXLive to 2022 version. Then it will work.

TeX engines don't provide property list as a native data structure, but tabularray package needs to write and read lots of key-value pairs to/from property lists, to build powerful tables. Therefore it is nearly impossible to make tabularray run very fast.

As the author of this package, I can only give you a suggestion for making your code run faster: fixing the column widths.

\documentclass[11pt]{article}
\usepackage{tabularray}
\usepackage{color}
\usepackage{l3benchmark}
\ExplSyntaxOn
\let \bmtic = \benchmark_tic:
\let \bmtoc = \benchmark_toc:
\ExplSyntaxOff
\newenvironment{sudoku}[1][]{%
    \begin{tblr}{
        colspec = {*{9}{Q[wd=1em,c]}},
        hline{1,4,7,10}={blue,2pt},
        hline{2,3,5,6,8,9}={blue,0.5pt},
        vline{1,4,7,10}={blue,2pt},
        vline{2,3,5,6,8,9}={blue,0.5pt},
        abovesep=3pt,
        #1
    }
}{%
    \end{tblr}
}
\newcommand\mysudoku{\begin{sudoku}
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
    1&2&3&4&5&6&7&8&9\\
\end{sudoku}\par}
\begin{document}
\bmtic
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\mysudoku
\bmtoc
\end{document}

Before fixing the column widths, you need 21.1 seconds to make 20 sodukus, and now you only need 14.3 seconds.

L.J.R.
  • 10,932
  • It is not the LaTeX 3 nature of the package, it is if you LaTeX distribution is up-to-date or not – CarLaTeX May 04 '22 at 05:05
  • With TeX Live 2022 and TeX Live 2021 it works, with older versions it doesn't. – CarLaTeX May 04 '22 at 05:09
  • This is quicker than my version, but not massively so: 161 seconds for 50 sudokus on my laptop. It's a shame, because I love the interface and features that tabularray provides. – rbrignall May 04 '22 at 09:05
1

Have you looked at the sudokubundle?

It basically has three packages: printsudoku to print a puzzle; solvesudoku which does its best to solve a puzzle; and createsukodo which creates puzzles solvable via solvesudoku.

I realise that this is not an explicit answer to your question but I think it might be worth your while to look at these.

Peter Wilson
  • 28,066
  • Thanks, I'll take a look. My use case is for writing teaching material: Sudoku will appear, but there are other array-type combinatorial objects too... – rbrignall May 03 '22 at 20:29