48

How can I create a Caesar's encryption disk with LaTeX?

Caesar's encryption disk

I guess, the ultimate solution would take a arbitrary list of letters and calculate the spaces and angles for each letter automatically. So if I pass 4 letters to it, each space should have 90 degrees.

8
  • 2
    This looks like fun. Can we add that to the tag?
    – hpesoj626
    Mar 20, 2013 at 5:51
  • Done, added 'fun' :-) Mar 20, 2013 at 6:04
  • 1
    What have you tried so far? MWE? Do you want to give a list of letters? The number of letters? What should happen when the number is greater than 26? Mar 20, 2013 at 6:10
  • I have no idea how to tackle this problem, so there is no MWE yet. I could imagine it as the following: \ceasar[circleouterwidth=5cm]{a,b,c,d,e,f,g}{a,b,c,d,e,f,g} with character for the inner and the outer circle. Giving two separate lists could allow to use math symbols as well or Greek characters. There should not be a problem if there are more than 26 chars. Mar 20, 2013 at 6:27
  • 3
    Next challenge - build an Enigma machine in TeX? en.wikipedia.org/wiki/Enigma_machine Mar 20, 2013 at 12:52

4 Answers 4

57

Commands

  • \drawCaesarsDisk that works with a number of letters (only A to Z)
  • \drawCaesarsList that works with one list for both rings or two different lists

Keys

  • inner radius/middle radius/outer radius
    • Improvements: Specify inner radius and add inner height and outer height respectively to calculate the actual radii.
    • Improvements: With these heights, scale the letters so that they fit right into one ring segment.
  • number of letters (only \drawCaesarsDisk)
  • inner letters and outer letters (only \drawCaesarsList): If only inner letters is specified the letters in the outer ring will be the same as in the inner ring.
  • shift

Parameters (both commands)

  • First (optional): Key=Values for the disk.
  • Second (mandatory): where the Disk is placed.

Improvement:

  • Radii/font-size calculation (see above)
  • Starting with the first letter at the north position or right of it (possible style)
  • Adding styles for circles, separators, letters, etc.
  • Bug: The List command breaks with

    ! Dimension too large. <recently read> \pgfmath@x
    

    when 46 or more letters are specified.

  • I forgot something …

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{backgrounds}
\makeatletter
\tikzset{
    /caesar/.cd,
    inner radius/.store in=\qrr@caesar@innerR,
    middle radius/.store in=\qrr@caesar@middleR,
    outer radius/.store in=\qrr@caesar@outerR,
    inner letters/.store in=\qrr@caesar@innerL,
    outer letters/.store in=\qrr@caesar@outerL,
    number of letters/.code=\pgfmathtruncatemacro\qrr@caesar@number{#1},
    shift/.store in=\qrr@caesar@shift,
    % defaults:
    outer letters=,
    shift=0
}
\newcommand*{\drawCaesarsDisk}[2][]{%
    \begingroup
    \pgfqkeys{/caesar}{#1}%
    \foreach \radius in {\qrr@caesar@innerR,\qrr@caesar@middleR,\qrr@caesar@outerR}
        \draw (#2) circle [radius=\radius];
    \foreach \step in {0,...,\numexpr\qrr@caesar@number-1}{
        \draw[shift={(#2)}] (\step*360/\qrr@caesar@number:\qrr@caesar@innerR) -- (\step*360/\qrr@caesar@number:\qrr@caesar@outerR);
        \node[shift={(#2)},rotate=(\step+.5)*360/\qrr@caesar@number-90] at ({(\step+.5)*360/\qrr@caesar@number}:{.5*(\qrr@caesar@innerR)+.5*(\qrr@caesar@middleR)} ) {\@Alph{\numexpr26-\step}};
        \pgfmathtruncatemacro\pgf@temp{mod(\step+\qrr@caesar@shift,\qrr@caesar@number)}%
        \node[shift={(#2)},rotate=(\step+.5)*360/\qrr@caesar@number-90] at ({(\step+.5)*360/\qrr@caesar@number}:{.5*(\qrr@caesar@outerR)+.5*(\qrr@caesar@middleR)} ) {\@Alph{\numexpr26-\pgf@temp}};
    }
    \endgroup
}
\newcount\qrr@caesar@c
\newcommand*{\drawCaesarsList}[2][]{%
    \begingroup
    \pgfqkeys{/caesar}{#1}%
    \foreach \radius in {\qrr@caesar@innerR,\qrr@caesar@middleR,\qrr@caesar@outerR}
        \draw (#2) circle [radius=\radius];
    \qrr@caesar@c=0\relax
    \foreach \element in \qrr@caesar@innerL {\global\advance\qrr@caesar@c1}
    \ifx\pgfutil@empty\qrr@caesar@outerL
        \let\qrr@caesar@outerL\qrr@caesar@innerL
    \fi
    \edef\qrr@caesar@number{\number\qrr@caesar@c}%
    \foreach \innerLetter[count=\step from 0] in \qrr@caesar@innerL {
        \draw[shift={(#2)}] (\step*360/\qrr@caesar@number:\qrr@caesar@innerR) -- (\step*360/\qrr@caesar@number:\qrr@caesar@outerR);
        \node[shift={(#2)},rotate=-(\step+.5)*360/\qrr@caesar@number-90] at ({-(\step+.5)*360/\qrr@caesar@number}:{.5*(\qrr@caesar@innerR)+.5*(\qrr@caesar@middleR)} ) {\innerLetter};
    }
    \foreach \outerLetter[count=\step@ from 0] in \qrr@caesar@outerL {
        \ifnum\step@=\qrr@caesar@number\breakforeach\fi
        \pgfmathtruncatemacro\step{mod(\step@+\qrr@caesar@shift,\qrr@caesar@number)}%
        \node[shift={(#2)},rotate=-(\step+.5)*360/\qrr@caesar@number-90] at ({-(\step+.5)*360/\qrr@caesar@number}:{.5*(\qrr@caesar@outerR)+.5*(\qrr@caesar@middleR)} ) {\outerLetter};
    }
    \endgroup
}
\makeatother
\begin{document}
\begin{tikzpicture}
\drawCaesarsDisk[
    inner radius=2cm,
    middle radius=2cm+1.3em,
    outer radius=2cm+3em,
    number of letters=26,
    shift=13,
    ]{0,0}
\end{tikzpicture}

\begin{tikzpicture}
\drawCaesarsList[
    inner radius=.5cm,
    middle radius=.5cm+1.3em,
    outer radius=.5cm+3em,
    inner letters={a,b,c,d,e,f,g},
    outer letters={A,B,C,D,E,F,G}
    ]{2,0}
\end{tikzpicture}

\begin{tikzpicture}
\drawCaesarsList[
    inner radius=2cm,
    middle radius=2cm+1.3em,
    outer radius=2cm+3em,
    inner letters={a,...,z,A,B,...,T},%,U,V,W,X,Y,Z},
    shift=26,
    ]{0,0}
\end{tikzpicture}
\end{document}

Output

enter image description here

enter image description here

enter image description here

4
  • Wow! However I get an error: "! Package tikz Error: A node must have a (possibly empty) label text. ... l.58 ]{0,0} Mar 20, 2013 at 7:17
  • @UweZiegenhagen I have added some explanation since you made your comment. I also updated the solution to work with the 2.10 version of TikZ. The problem was a parsing error that was already discussed in other questions. And to clarify: Yes, you can give two (possibly different) lists and you can specify a shift. Mar 20, 2013 at 7:35
  • You are awesome! :-) Mar 20, 2013 at 7:47
  • An alternative way of getting the length of a \foreach list is: \foreach \x [count=\c from 1, remember=\c] in {A,...,Z}{}. Then \c holds the length of the list. Mar 20, 2013 at 11:50
22

Here is what I've done so far:

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
  \begin{tikzpicture}
    \pgfmathsetmacro{\alphsize}{26}

    \pgfmathsetmacro{\ang}{360/\alphsize}
    \pgfmathsetmacro{\d}{10}
    \pgfmathsetmacro{\op}{98 + \ang/2 - 1.2}
    \pgfmathsetmacro{\e}{\ang + \ang*\d}
    \pgfmathsetmacro{\ep}{\op + \ang*\d}

    \foreach \x in {0,\ang,...,360} {
      \draw[gray] (\x:8em) -- (\x:12em);
    }

    \foreach \x [count=\xi] in {A,...,Z} {
      \node[rotate=\ang - \ang*\xi] at (\op - \ang*\xi:11em) {\Large\x};
      \node[rotate=\e - \ang*\xi] at (\ep - \ang*\xi:9em) {\Large\x};
    }

    \draw[thick] (0cm,0cm) circle(12em);
    \draw[gray] (0cm,0cm) circle(10em);
    \draw[thick] (0cm,0cm) circle(8em);
  \end{tikzpicture}
\end{document}

Caesar latin circle

18

Here:

\documentclass{article}
\usepackage{tikz}
\usepackage{ifthen}

\newcounter{encrypted}
\newcounter{original}

\newcommand{\increase}[1]{%command to increase a counter by 1 modulo 26
\ifthenelse{\arabic{#1}<26}{\addtocounter{#1}{1}}{\setcounter{#1}{1}}
}

\begin{document}

\setcounter{encrypted}{7}
\setcounter{original}{1}
\begin{tikzpicture}[scale=0.5]
\draw(0,0)circle(5)circle(7)circle(9);
\foreach \x in {1,2,...,26}
{
\draw(\x*360/26:5)--(\x*360/26:9);
\node at (\x*360/26+360/26+180/26:6){\Alph{encrypted}};
\node at (\x*360/26+360/26+180/26:8){\Alph{original}};
\increase{encrypted}
\increase{original}
}
\end{tikzpicture}

\end{document}

enter image description here

2
  • This looks really promising. Is there an easy way to take just a list of characters instead of hard-coding the 26 letters? Mar 20, 2013 at 6:33
  • 1
    @Toscho I have added the picture for you. I hope you don't mind. :-)
    – hpesoj626
    Mar 20, 2013 at 9:10
15

Just 4 fun with PSTricks.

enter image description here

\documentclass[pstricks,border=12pt]{standalone}
\SpecialCoor
\makeatletter
\def\N{26}

\begin{document}
% speficy the angular distance between the 2 sets of alphabets
\def\offset{13}
\begin{pspicture}(-5,-5)(5,5)
    \psforeach{\r} {2,3,4}{\pscircle{\r}}
    \degrees[\N]
    \psforeach{\t}{65,66,..,90}{%
        \psline(2;\the\psLoopIndex)(4;\the\psLoopIndex)
        \pstVerb{/angle {\the\psLoopIndex\space 0.5 add} bind def}%
        \rput{!angle 6.5 sub}(!3.5 angle \pst@angleunit PtoC){\char\t\relax}
        \rput{!angle \offset\space add 6.5 sub}(!2.5 angle \offset\space add \pst@angleunit PtoC){\char\t\relax}
    }
\end{pspicture}
\end{document}

Animated version

To be funner!

enter image description here

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{multido}
\SpecialCoor
\makeatletter
\def\N{26}

\begin{document}
\multido{\i=0+1}{\N}{%
% speficy the angular distance between the 2 sets of alphabets
\def\offset{\i}
\begin{pspicture}(-5,-5)(5,5)
    \psforeach{\r} {2,3,4}{\pscircle{\r}}
    \degrees[\N]
    \psforeach{\t}{65,66,..,90}{%
        \psline(2;\the\psLoopIndex)(4;\the\psLoopIndex)
        \pstVerb{/angle {\the\psLoopIndex\space 0.5 add} bind def}%
        \rput{!angle 6.5 sub}(!3.5 angle \pst@angleunit PtoC){\char\t\relax}
        \rput{!angle \offset\space add 6.5 sub}(!2.5 angle \offset\space add \pst@angleunit PtoC){\char\t\relax}
    }
\end{pspicture}}
\end{document}

Warning

If we invoke \degrees[<value other than 360>] previously, conversion with \pst@angleunit is needed for representing points in RPN notation but it is NOT need for representing rotation angle. See the following code snippet.

\rput{!angle 6.5 sub}(!3.5 angle \pst@angleunit PtoC){\t}

It is funny? Don't ask me! I just knew this feature several minutes ago!

One more feature, unlike \foreach \t in {A,...,Z}{} that produces a correct result, \psforeach{\t}{A,..,Z}{} produces a weird output!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .