2

I am trying to draw a punch card using tikz. The card is a 8 x 80 matrix. A card "stores" a sentence (e.g. a line from a program's source code) printed in the card header via an encoding scheme (e.g., ASCII). Each column represents a sentence char by its binary code: column 0 represents 1st char, column 1 the 2nd and so on. Obviously, a sentence cannot be longer than 80 characters. A hole in a row represents that the corresponding code bit is 1; a "non-hole" represents 0. For example, if the 11th position char is 'A' (65 or 01000001 in binary), in column 10 a hole in row 0 and row 6.

Using the binhex library \nbinary macro, I can get the 1's and 0's string corresponding to a decimal number; with the \StrChar macro from the xstring package, I can get these "bits", but from left to right, which makes the holes appear in the wrong positions of the card (for example, in the case of 'A', the hole appears on line 7 and 5).

My other problem is that I can't get position by position of the sentence (the printed character is the same for all columns).

Above, a partial view with the first 4 columns of what I want to get. Partial view of the punshed card

My code:

\documentclass[16pt,a4paper, openright,twoside, fleqn]{book}
\usepackage{tikz}
\usetikzlibrary{arrows, arrows.meta, backgrounds,calc, chains, calligraphy,  decorations.pathreplacing, decorations.markings, external, fit,positioning, scopes, ,shapes.arrows, shapes.multipart, shapes.symbols, shapes.geometric, shapes.callouts, shadows, shadows.blur, tikzmark}
\usepackage{xstring}
\usepackage{ifthen}
\usepackage{stix}

\begin{document}
\input binhex   
\def\word{\nbinary{8}{0}} % Fixed ASCII
       
   
\begin{tikzpicture}[scale=.4, transform shape]  
   \node[rectangle, draw, rounded corners=1ex, fit={(-1,1) (37, -11)}, line width = 0.4mm, ] (card) {};
   \node[text centered, below right = 3mm and 1cm of card.north west] {{\huge \texttt{IF WS-NUM1 IS GREATER THAN OR EQUAL TO WS-NUM2 THEN}}};
   \foreach \x  [count = \yi] in {0, ..., 79} {
       \node[text centered] at (\x*.45,-11) {\x};
   }
   
   \foreach \x  [count = \xi] in {0, 1, 2, ..., 79}{   
       \foreach \k  [count = \ki] in {1, ..., 8}{  
           \StrChar{\word}{\k}[\bit]
           \ifthenelse{\equal{\bit}{1}}{
               \node[text centered, minimum size=2mm, text width=2mm] at (\x*.45,\k *-1.2) {{\huge $\talloblong$}}; 
           }
           {
               \node[text centered, minimum size=2mm, text width=2mm] at (\x*.45,\k *-1.2) {\number\numexpr 1-\k \relax};
           }
       }
   }
\end{tikzpicture}       
\end{document}

Thanks in advance!

2
  • I think that for each column you use the same \word, which is 00000000. Why do you expect more a variation in the columns?
    – user227987
    Commented Nov 4, 2020 at 2:23
  • Exact. I would like to take the characters from the string. This is the main problem. I pre-fixed a value just to generate the layout. Commented Nov 4, 2020 at 12:38

2 Answers 2

4

The Hollerith cards I remember looked more like

hollerith

The text was printed above the holes, and the coding was probably EBCDIC (at least with IBM card punchers). I think the ninth row was a parity bit.

3
  • You're right. I made a version using ASCII (it could only have 7 lines) just to illustrate how it works. Commented Nov 4, 2020 at 12:35
  • It is a good idea to use the 8th row (in my punshed card "version") as parity bit. But I don't know how to make it automatically. Commented Nov 4, 2020 at 13:04
  • Since all zeros produces a zero parity bit, the total number of bits (including the parity bit) should always be an even number. Use XOR on the first 8 bits to compute the parity bit. Commented Nov 4, 2020 at 14:58
2

Here is some function that converts a binary in a list and prepends enough zeros so that the list has a fixed length. You can then loop over this list to draw the column entries. I just used random binaries for the test. I am not old enough to know how the punch cards really looked.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{fit,positioning}
\makeatletter
\pgfmathdeclarefunction{Split}{2}{%
  \begingroup%
    \pgfmath@count0%
    \expandafter\pgfmath@split@i#1\pgfmath@token@stop
    \pgfutil@loop
        \ifnum\pgfmath@count<#2\relax
          \advance\pgfmath@count by1\relax 
          \edef\pgfmathresult{0,\pgfmathresult}%   
    \pgfutil@repeat
    \pgfmathsmuggle\pgfmathresult%
  \endgroup}
\def\pgfmath@split@i#1{%
    \ifx\pgfmath@token@stop#1%
    \else
      \ifnum\pgfmath@count=0\relax
        \edef\pgfmathresult{#1}%
      \else
        \edef\pgfmathresult{\pgfmathresult,#1}%
      \fi
      \advance\pgfmath@count by1%
      \expandafter\pgfmath@split@i
    \fi}  
\makeatother
\begin{document}
\begin{tikzpicture}[scale=.4, transform shape]  
   \node[rectangle, draw, rounded corners=1ex, fit={(-1,1) (37, -11)}, line width = 0.4mm, ] (card) {};
   \node[text centered, below right = 3mm and 1cm of card.north west,
    font=\huge\ttfamily] 
    {IF WS-NUM1 IS GREATER THAN OR EQUAL TO WS-NUM2 THEN};
   \foreach \x  [count = \yi] in {0, ..., 79} {
       \node[text centered] at (\x*.45,-11) {\x};
   }
   
   \foreach \x  [count = \xi] in {0, 1, 2, ..., 79}{  
       % generate a random integer between 0 and 255
       \pgfmathtruncatemacro{\myrnd}{random(256)-1}
       % convert it to a binary
       \pgfmathtruncatemacro{\myword}{bin(\myrnd)}
       % convert the binary to a list and prepend zeros till it has 8 entries
       \pgfmathsetmacro{\mysplitword}{Split("\myword",8)}  
       \foreach \k  [count = \ki] in \mysplitword {  
           \ifnum\k=1
             \path (\x*.45,-1.2*\ki) 
             node[text height=1.1em,draw,inner sep=0pt,minimum width={width("0")}] {}; 
           \else
              \path (\x*.45,-1.2*\ki) 
              node (tmp)[text height=1.1em,inner sep=0pt] {\ki}
              (\tikzlastnode.north west) edge (\tikzlastnode.north east);
           \fi            
       }
   }
\end{tikzpicture}       
\end{document}

enter image description here

2
  • I appreciate your suggestion. What I need is to take character by character from the card header, which is easy with \ StrChar, and transform it into ASCII code, which I don't know how to do. Suppose latex has a toASCII macro, the code fragment would look like:\myrnd=\StrChar{IF WS-NUM1 IS GREATER THAN OR EQUAL TO WS-NUM2 THEN}{\xi}; ... \pgfmathtruncatemacro{\myword}{bin(toASCII(\myrnd))} Commented Nov 6, 2020 at 1:31
  • @CristianKoliver Are you looking for this? (I think one could make this a pgf function.)
    – user227987
    Commented Nov 6, 2020 at 1:43

You must log in to answer this question.

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