Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to typeset some easy polyomino puzzles and therefore need a suitable LaTeX package. I could not find an easy to use package (other than using TikZ of course). Is there any approach other than using TikZ/PSTricks?

For anybody not aware of what polyominos are: http://en.wikipedia.org/wiki/Polyomino

Edit: With a polyomino puzzle, I mean something like this: http://www.virtualimage.co.uk/html/polyomino.html

So my intention is to put a set of polyominos into a given shape.

share|improve this question
    
Any such package would in turn use TikZ/PSTricks, and probably have a very TikZ/MP-like interface. If you can make a polyomino with TikZ, then I suggest you simply write such a package, as one does not appear to exist. –  Sean Allred Apr 23 '13 at 13:21
1  
@SeanAllred I believe that this is more a question of a good user interface than of the programming layer. Many LaTeX packages could witness that. –  tohecz Apr 23 '13 at 13:25
    
@tohecz than perhaps, in the complete absence of any extant package, a ideal user interface should be defined. I find it difficult to envision a consistent interface that would cover all the different configurations of every polyomino. –  Sean Allred Apr 23 '13 at 13:26
    
@SeanAllred; I think you are probably right. Since there are already 35 free forms for a polyomino of 6 blocks, it will be difficult to provide some intuitive way of specifying them with single commands. Would be an interesting idea for a package though. –  Mythio Apr 23 '13 at 13:57
1  
Have a look at Donald Knuth's metapost program for drawing polyominos. –  Marc van Dongen Apr 25 '13 at 10:50

5 Answers 5

up vote 15 down vote accepted

Code 1

\documentclass[tikz,border=2pt]{standalone}
\usetikzlibrary{matrix}
\makeatletter
\newcounter{qrr@tikz@omino}
\newcounter{qrr@tikz@omino@up}
\newcounter{qrr@tikz@omino@right}
\tikzset{
    omino/.style={/tikz/omino/.cd,#1},
    omino/distance/.initial=1,
    omino/radius/.initial=.5,
    omino/at/.style={/tikz/shift={(#1)}},
    omino/rotate/.style={/tikz/rotate=#1},
    omino/s/.code=
        \setcounter{qrr@tikz@omino}{0}%
        \setcounter{qrr@tikz@omino@up}{0}%
        \setcounter{qrr@tikz@omino@right}{0}%
        \pgfkeysalso{/tikz/insert path={(0,0) node[/tikz/omino/nodes/.try,/tikz/omino/node normal/.try,/tikz/omino/node start/.try] {\qrr@tikz@omino@text@start}}},
    omino/u/.code=%
        \stepcounter{qrr@tikz@omino}%
        \stepcounter{qrr@tikz@omino@up}%
        \pgfkeysalso{/tikz/insert path={
            to[/tikz/omino/how] ++(up:#1)
            node[/tikz/omino/nodes/.try,/tikz/omino/node normal/.try,/tikz/omino/node up/.try]{\qrr@tikz@omino@text@up}}},
    omino/d/.code=%
        \stepcounter{qrr@tikz@omino}%
        \addtocounter{qrr@tikz@omino@up}{-1}%
        \pgfkeysalso{/tikz/insert path={
            to[/tikz/omino/how] ++(down:#1)
            node[/tikz/omino/nodes/.try,/tikz/omino/node normal/.try,/tikz/omino/node down/.try]{\qrr@tikz@omino@text@down}}},
    omino/l/.code=%
        \stepcounter{qrr@tikz@omino}%
        \addtocounter{qrr@tikz@omino@right}{-1}%
        \pgfkeysalso{/tikz/insert path={
            to[/tikz/omino/how] ++(left:#1)
            node[/tikz/omino/nodes/.try,/tikz/omino/node normal/.try,/tikz/omino/node left/.try]{\qrr@tikz@omino@text@left}}},
    omino/r/.code=%
        \stepcounter{qrr@tikz@omino}%
        \stepcounter{qrr@tikz@omino@right}%
        \pgfkeysalso{/tikz/insert path={
            to[/tikz/omino/how] ++(right:#1)
            node[/tikz/omino/nodes/.try,/tikz/omino/node normal/.try,/tikz/omino/node right/.try] {\qrr@tikz@omino@text@right}}},
    omino/u/.default=\pgfkeysvalueof{/tikz/omino/distance},
    omino/d/.default=\pgfkeysvalueof{/tikz/omino/distance},
    omino/l/.default=\pgfkeysvalueof{/tikz/omino/distance},
    omino/r/.default=\pgfkeysvalueof{/tikz/omino/distance},
    omino/how/.style=,
    omino/reset/.code=
        \pgfutil@in@_{#1}%
        \ifpgfutil@in@
            \qrr@tikz@omino@split#1\relax
        \else
            \edef\pgf@tempa{\csname qrr@tikz@omino@coords@#1\endcsname}%
            \expandafter\qrr@tikz@omino@split\pgf@tempa\relax
        \fi
        \pgfkeysalso{/tikz/insert path={(omino-n-#1.center) node[/tikz/omino/nodes/.try, /tikz/omino/node reset/.try] {\qrr@tikz@omino@text@reset}}},
    omino/do/.code={\@tfor\@next:=#1\do{\pgfkeysalso{/tikz/omino/\@next}}},
    omino/node reset/.style={draw=none,fill=none},
    omino/node normal/.style={
        name=omino-n-\number\c@qrr@tikz@omino,
        alias=omino-n-\number\c@qrr@tikz@omino@right_\number\c@qrr@tikz@omino@up,
        omino/@store coords
    },
    omino/@store coords/.code=
        \expandafter\xdef\csname qrr@tikz@omino@coords@\arabic{qrr@tikz@omino}\endcsname
        {\number\c@qrr@tikz@omino@right_\number\c@qrr@tikz@omino@up},
    omino/Text/.code 2 args=\expandafter\edef\csname qrr@tikz@omino@text@#1\endcsname{#2},
    omino/Text={up}{},omino/Text={down}{},omino/Text={left}{},omino/Text={right}{},omino/Text={start}{},omino/Text={reset}{}
}
\def\qrr@tikz@omino@split#1_#2\relax{\setcounter{qrr@tikz@omino@right}{#1}\setcounter{qrr@tikz@omino@up}{#2}}

\tikzset{
    omino/x mirror/.style={/tikz/cm={-1,0,0,1,(0,0)}},
    omino/y mirror/.style={/tikz/cm={1,0,0,-1,(0,0)}}
}

\tikzset{fun/.code={\pgfmathtruncatemacro\@fun{\number\c@qrr@tikz@omino/4*100}\pgfkeysalso{fill=blue!\@fun!red}}}
\makeatother
\tikzset{
    tetris/.style={/tikz/tetris/.cd,#1},
    tetris/1/.style={/tikz/omino={do=suuu}},
    tetris/2/.style={/tikz/omino={do=suur}},
    tetris/2'/.style={/tikz/omino/x mirror, 2},
    tetris/3/.style={/tikz/omino={do=suru}},
    tetris/3'/.style={/tikz/omino/x mirror, 3},
    tetris/4/.style={/tikz/omino={do=surd}},
    tetris/5/.style={/tikz/omino={s,u,u,reset=1,r}}
}
\makeatletter

\makeatother
\newcommand*{\thesamepictureeverywhere}{\matrix[column sep=.5cm, row sep=.5cm, ampersand replacement=\&] {
\path [tetris=1];  \&
\path [tetris=2']; \& \path [tetris=2]; \\
\path [tetris=3];  \& \path [tetris=3']; \&
\path [tetris=4];  \&
\path [tetris=5];\\};}
\begin{document}
\begin{tikzpicture}[
    every path/.style=draw,
    omino/how/.style={bend left},
    omino/nodes/.style={circle, inner sep=+0pt, minimum size=+4pt, fill=black, outer sep=+0pt}]
\thesamepictureeverywhere
\end{tikzpicture}
\begin{tikzpicture}[omino/nodes/.style={rectangle, inner sep=+0pt, minimum size=+1cm, draw}]
\thesamepictureeverywhere
\end{tikzpicture}

\begin{tikzpicture}[omino={
        nodes/.style={circle, inner sep=+0pt, minimum size=+1cm, draw},
        Text={left}l,Text={right}r,Text={up}u,Text={down}d,Text={start}s
        }]
\thesamepictureeverywhere
\end{tikzpicture}

\begin{tikzpicture}[omino/nodes/.style={shape=circle, inner sep=+0pt, minimum size=+1cm, fun}]
\thesamepictureeverywhere
\end{tikzpicture}

\tikzset{
    tetris/1/.prefix style={/tikz/omino/nodes/.append style={fill=black,text=white}},
    tetris/2/.prefix style={/tikz/omino/nodes/.append style={fill=blue}},
    tetris/3/.prefix style={/tikz/omino/nodes/.append style={fill=green!70!blue}},
    tetris/4/.prefix style={/tikz/omino/nodes/.append style={fill=yellow!80!black}},
    tetris/5/.prefix style={/tikz/omino/nodes/.append style={fill=red!70!black}},
    omino/Text={start}{.}
}
\begin{tikzpicture}[omino/nodes/.style={shape=rectangle, rounded corners, inner sep=+0pt, minimum size=1cm-2\pgflinewidth}]
    \path [tetris=1];
    \path [omino/at=0:1] [tetris=2];
    \path [omino/at=0:2] [tetris=3];
    \path [omino={at=0:3, rotate=-90, x mirror}][tetris=5];
    \path [omino={at={5,1}, rotate=-90}][tetris=3];
    \path [omino={at={5,2}, rotate=-90}][tetris=2];
    \path [omino={at={4,2}, x mirror}][tetris=5];
    \path [omino={at={1,3}}][tetris=4];
\end{tikzpicture}
\end{document}

Output 1

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

Code 2

\documentclass[tikz,border=2pt,convert=false]{standalone}
\usetikzlibrary{matrix}
\makeatletter
\tikzset{
    omino/.style={/tikz/omino.cd,#1},
    omino/row sep/.initial=1cm,
    omino/column sep/.initial=1cm}
\newcounter{qrr@tikz@omino@y}
\newcounter{qrr@tikz@omino@x}
\def\qrr@tikz@omino@empty{\stepcounter{qrr@tikz@omino@x}}
\def\qrr@tikz@omino@full{%
    \stepcounter{qrr@tikz@omino@x}
    \node[
        every omino node/.try,
        every omino row \number\c@qrr@tikz@omino@y/.try,
        every omino column \number\c@qrr@tikz@omino@x/.try,
        every omino cell \number\c@qrr@tikz@omino@x-\number\c@qrr@tikz@omino@y/.try,
        at={(\c@qrr@tikz@omino@x*\pgfkeysvalueof{/tikz/omino/column sep},\c@qrr@tikz@omino@y*\pgfkeysvalueof{/tikz/omino/row sep})}
        ]{};}
\def\qrr@tikz@omino@nextrow{\setcounter{qrr@tikz@omino@x}{0}\stepcounter{qrr@tikz@omino@y}}
\def\qrr@tikz@omino@final{\endgroup\@gobble}
\def\qrr@omino{%
    \afterassignment\qrr@@omino\let\qrr@next@token=}
\def\qrr@@omino{%
    \let\qrr@next\relax
    \ifx\qrr@next@token.%
        \let\qrr@next\qrr@tikz@omino@empty
    \else
        \ifx\qrr@next@token*%
            \let\qrr@next\qrr@tikz@omino@full
        \else
            \ifx\qrr@next@token:
                \let\qrr@next\qrr@tikz@omino@nextrow
            \else
                \ifx\qrr@next@token;
                    \let\qrr@next\qrr@tikz@omino@final
                \fi
            \fi
        \fi
    \fi
    \qrr@next\qrr@omino
}
\newcommand*{\omino}[1][]{\begingroup\tikzset{#1}\setcounter{qrr@tikz@omino@x}{0}\setcounter{qrr@tikz@omino@y}{0}\qrr@omino}
\makeatother

\tikzset{every omino node/.style={circle, inner sep=+0pt, minimum size=+1cm}}
\begin{document}
\begin{tikzpicture}[every omino node/.append style={rectangle, fill,draw}]
\matrix[column sep=.5cm]{
\omino *:*:*:*; & \omino **:*:*; & \omino *:**:*; & \omino .*:**:*; \\};
\end{tikzpicture}
\begin{tikzpicture}[
    every omino row 0/.style={fill=blue},
    every omino row 1/.style={fill=blue!33!red},
    every omino row 2/.style={fill=blue!67!red},
    every omino row 3/.style={fill=red}]
\matrix[column sep=.5cm]{
\omino *:*:*:*; & \omino **:*:*; & \omino *:**:*; & \omino .*:**:*; \\};
\end{tikzpicture}
\end{document}

Output 2

enter image description here

enter image description here

share|improve this answer
    
can you insert onimo/A/.style={/tikz/insert path={coordinate[/tikz/onimo/how](#1)}}, into the tikzset? That way, one can easily define an anchor via A=anchorname, and jump back to it via reset? –  Toscho Apr 23 '13 at 17:17
    
@Toscho In my updated answer, nodes are named consecutively omino-n-<counter> and omino-n-<right>-<up> where <counter> increments from 0, and <right> and <up> are the position in relation to the first node. These names can be used for reset (either 1 or 0_1 in the last case). –  Qrrbrbirlbel Apr 23 '13 at 17:47
    
This definitely exceeds my Tikz skills :-) The only thing left is a grid to actually place the polyominos (so it is a puzzle or a tetris game). –  user26372 Apr 23 '13 at 19:50
    
@user26372 I have extended my first code and added an alternative. In both solutions, you can place these polyominos with at (first solution, uses shift internally) or shift (both solutions). In the first solution you can re-define the path, so that the start coordinate lies more in the middle tiles … It ultimately comes down to how you want to input these figures and where you want to use them … –  Qrrbrbirlbel Apr 23 '13 at 21:23
    
I edited my question to address that a little better. Hope you get what I mean. But your solution (especially the last example of your first piece of code) is already very close to what I was hoping for. –  user26372 Apr 23 '13 at 22:08

enter image description here

\documentclass{article}

\makeatletter
\def\omino#1{{%
\unitlength10\p@
\@tempcnta\z@
\@tempcntb\@ne
\count@\z@
\xomino#1\relax
\fbox{\begin{picture}(\@tempcnta,\@tempcntb)(0,-\@tempcntb)%
\@tempcnta\z@
\@tempcntb\@ne
\count@\z@
\xxomino#1\relax
\end{picture}}%
}%
}

\def\xomino#1{%
\ifx\relax#1%
\else
\ifx\\#1%
\ifnum\count@>\@tempcnta \@tempcnta\count@\fi
\advance\@tempcntb\@ne
\count@\z@
\else
\advance\count@\@ne
\fi
\expandafter\xomino
\fi}

\def\xxomino#1{%
\ifx\relax#1%
\else
  \ifx\\#1%
    \advance\@tempcntb\@ne
    \count@\z@
  \else
    \advance\count@\@ne
    \ifx*#1%
      \put(\count@,-\@tempcntb){\kern-10pt\rule{10pt}{10pt}}%
    \fi
  \fi
\expandafter\xxomino
\fi}


\makeatother

\begin{document}

\omino{
*\\
*\\
*\\
*\\
*}

\omino{
**\\
.*\\
.*\\
.*}

\omino{
**\\
*\\
*\\
**}
\end{document}
share|improve this answer
    
Wow. You're very quick. :-) But this doesn't allow you to interlock multiple polyominos into a puzzle (with visually distinct pieces). I put my thoughts on a possible interface for that in a comment above. I don't have the time to actually implement it, though. –  mhelvens Apr 23 '13 at 16:22
2  
Addendum: click here and enjoy. :) –  Paulo Cereda Apr 23 '13 at 16:23
    
@mhelvens it's just picture mode so the pieces can be placed in interlocking position (the \fbox around the outside is just for debugging really) , if you want thin gaps to show the original squares then you can reduce the size of the rule from 10pt so it is smaller than the coordinate spacing. –  David Carlisle Apr 23 '13 at 16:31
    
I very much like the way how you create the polyominos. Is it possible to put them into a puzzle (grid), too? –  user26372 Apr 23 '13 at 19:46
1  
A solution without loading any packages; very nice! –  Svend Tveskæg Apr 23 '13 at 22:07

David's solution converts ascii art into graphics. Here is a derived version that does a similar trick.

\documentclass{article}
\usepackage{color}

\newdimen\omsq  \omsq=20pt
\newdimen\omrule    \omrule=2pt
\newdimen\omint

\newif\ifvth    \newif\ifhth    \newif\ifomblank
\def\OMINO#1{%
    \vthtrue \hthtrue
    \vbox{ \offinterlineskip\parindent=0pt \OM#1\relax\vskip1pt}}


\def\OM#1{%
    \omint=\omsq    \advance\omint-\omrule
    \ifx\relax#1%
    \else
      \ifx\\#1 \newline\null \hthtrue \ifvth\vthfalse\else\vskip-\omrule\vthtrue\fi
      \else%
        \ifx .#1\hskip\ifhth \omrule\else \omint\fi
        \else%
          \ifx +#1\def\colour{black}\fi%
          \ifx -#1\def\colour{black}\fi%
          \ifx |#1\def\colour{black}\fi%
          \ifx @#1\def\colour{black}\fi%
          \ifx r#1\def\colour{red}\fi%
          \ifx g#1\def\colour{green}\fi%
          \ifx b#1\def\colour{blue}\fi%
          \ifx y#1\def\colour{yellow}\fi%
          \ifx m#1\def\colour{magenta}\fi%
          \ifx c#1\def\colour{cyan}\fi%
          \textcolor{\colour}{\rule{\ifhth\omrule\else\omsq\fi}{\ifvth\omrule\else\omsq\fi}}%
          \ifhth\else\hskip -\omrule\fi%
        \fi%
        \ifhth\hthfalse\else\hthtrue\fi%
      \fi%
    \expandafter\OM%
    \fi}

\makeatother

\begin{document}

\OMINO{
+-+-----+\\
|g|@|r.r|\\
|.+-+.+-+\\
|g.g|r|.|\\
+-+.|.|.|\\
|c|g|r|.|\\
|.+-+-+.|\\
|c.c.c|.|\\
+-----+-+
}

\OMINO{
+-+.......+-----+\\
|.|.......|r.r.r|\\
|.+-+-----+---+.|\\
|...|y.y.y.y.y|r|\\
+-+.+-+-----+-+.|\\
..|...|.....|r.r|\\
..+---+.....+---+
}

\end{document}

enter image description here

share|improve this answer
    
Love it. So many great answers! –  user26372 Apr 25 '13 at 15:10

May be something like this in crude form

enter image description here

    \documentclass{article}
    \begin{document}
    \begin{picture}(200,200)(120,120)
    \setlength{\unitlength}{1mm}
    \rule[0\unitlength]{10\unitlength}{20\unitlength}\rule[0\unitlength]{20\unitlength}{10\unitlength}
    \rule[0\unitlength]{10\unitlength}{20\unitlength}\rule[10\unitlength]{10\unitlength}{20\unitlength}
    \rule[0\unitlength]{20\unitlength}{10\unitlength}\rule[10\unitlength]{20\unitlength}{10\unitlength}
    \rule[0\unitlength]{20\unitlength}{10\unitlength}\rule[0\unitlength]{10\unitlength}{30\unitlength}
    \rule[0\unitlength]{10\unitlength}{30\unitlength}\rule[10\unitlength]{10\unitlength}{10\unitlength}
    \rule[0\unitlength]{10\unitlength}{20\unitlength}\rule[-20\unitlength]{10\unitlength}{20\unitlength}
    \rule[0\unitlength]{10\unitlength}{20\unitlength}\rule[10\unitlength]{10\unitlength}{10\unitlength}\rule[0\unitlength]{10\unitlength}{20\unitlength}
    \end{picture}
    \end{document}
share|improve this answer

Proposal for an interface:

d is a digit from 1 to 9 coordinate=d_nd_{n-1}d_{n-2}…d_2d_1 is a number out of digits (without 0) pattern=number is a number, in which each digit may appear at most once and 0 not at all

A polyomino is given by a dictionary with coordinates as keys and patterns as value. What does it mean?

Imagine a keyboard number pad or a telephone number pad. The digits 1-9 are arranged in a 3x3 grid. The digits above all identify one such cell of a 3x3 grid. The pattern is a number. Each digit occuring in the number means, that the identified cell is part of the polyomino.

Now polyominos can be larger than a 3x3-pattern. So we can arrange 3x3 of these 3x3-patterns into a 3x3 meta-pattern. The position of the pattern in this meta-pattern is specified by the digit d_1 of the coordinate. To get even larger, we can put 3x3 meta-patterns into a meta-meta-pattern. The position inside this meta-meta-pattern is specified by d_2. And so on.

Shorthands: coordinate=0 means, the last digit in coordinate is not d_1 but d_0 specifying the cell inside the pattern located at the coordinate created from the previous digits of coordinate.

0=pattern means, that the whole polyomino fits into one 3x3-pattern and is described by pattern.

So some examples: (with the base pattern being 789 456 123)

  • f-pentomino is 0=24589
  • N-pentomino is (1=1478,4=2)
  • I-dekomino is (11=123,12=123,13=123,21=1)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.