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!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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