Here is a simple TikZ solution. The RoB
(rows of boxes) environment has two arguments: the *
determines whether the rows are drawn from top to bottom, or bottom-to-top; the optional argument [...]
is the size of the box -- the default is 10pt. The \boxrow
macro takes an argument of comma-separated values, <width of box>/<fill color>
. There is nothing complicated here: the two counters, xbpos
and ybpos
, keep track of the implicit coordinates.
\documentclass{article}
%\usepackage{xcolor}
\usepackage{xparse}
\usepackage{tikz}
\newcounter{ybpos}
\newcounter{xbpos}
\newlength{\boxsize}
%% |=====8><-----| %%
% * draws rows top-to-bottom; optional argument for size, default=10pt
\NewDocumentEnvironment{RoB}{sO{10pt}}{%
\IfBooleanTF{#1}{\def\ttob{-1}}{\def\ttob{1}}%
\setcounter{ybpos}{0}
\setlength{\boxsize}{#2}
\begin{tikzpicture}[outer sep=0pt]
}{%
\end{tikzpicture}
}
\NewDocumentCommand{\boxrow}{m}{% csv: width in units of \boxsize/color
\setcounter{xbpos}{0}
\foreach \xbwd/\boxcolor in {#1}{%
\node[draw,
thick,
fill=\boxcolor,
minimum height=\boxsize,
minimum width=\xbwd*\boxsize,
anchor=south west] at (\thexbpos*\boxsize,\ttob*\theybpos*\boxsize) {};
\addtocounter{xbpos}{\xbwd}
}
\stepcounter{ybpos}%
}
%% |=====8><-----| %%
\begin{document}
\begin{RoB}
\boxrow{2/red,1/white,3/green,1/purple}
\boxrow{2/blue,1/red,2/green,2/yellow}
\boxrow{1/white,2/red,1/brown,3/orange}
\end{RoB}
\bigskip
\begin{RoB}*[18pt]
\boxrow{2/red,1/white,3/green,1/purple}
\boxrow{3/blue,1/red,1/green,2/yellow}
\boxrow{1/white,2/red,1/brown,3/orange}
\end{RoB}
\end{document}

Update
My bad! I completely missed the dependence of color on size. You can change the colors to suit (noted in the code). All else works the same as in the first answer.
\documentclass{article}
%\usepackage{xcolor}
\usepackage{xparse}
\usepackage{tikz}
\newcounter{ybpos}
\newcounter{xbpos}
\newlength{\boxsize}
%% |=====8><-----| %%
% * draws rows top-to-bottom; option argument for size, default=10pt
\NewDocumentEnvironment{RoB}{sO{10pt}}{%
\IfBooleanTF{#1}{\def\ttob{-1}}{\def\ttob{1}}%
\setcounter{ybpos}{0}
\setlength{\boxsize}{#2}
\begin{tikzpicture}[outer sep=0pt]
}{%
\end{tikzpicture}
}
\NewDocumentCommand{\boxrow}{m}{% csv: width in units of \boxsize/color
\setcounter{xbpos}{0}
\foreach \xbwd in {#1}{%
%% Change the order of colors to suit...
\def\boxcolor{\ifcase\xbwd \or white\or red\or green\or purple\fi}
\node[draw,
thick,
fill=\boxcolor,
minimum height=\boxsize,
minimum width=\xbwd*\boxsize,
anchor=south west] at (\thexbpos*\boxsize,\ttob*\theybpos*\boxsize) {};
\addtocounter{xbpos}{\xbwd}
}
\stepcounter{ybpos}%
}
%% |=====8><-----| %%
\begin{document}
\begin{RoB}
\boxrow{1,2,1,3,1,2,1}
\boxrow{2,1,3,1,4}
\boxrow{4,1,3,1,2}
\end{RoB}
\medskip
\begin{RoB}*[1cm]
\boxrow{1,2,1,3,1,2,1}
\boxrow{2,1,3,1,4}
\boxrow{4,1,3,1,2}
\end{RoB}
\end{document}

Another update...
I refer Gentle Reader to https://en.wikipedia.org/wiki/Cuisenaire_rods. This code differs from my previous two answers in that keyval.sty
is used to communicate options to the environment. Note the following changes:
There is a new option, boxsize
that is used to specify the size (height) of the boxes. See the code below for examples.
There are three color schemes. In the code, they are \cuisenairei
, \cuisenaireii
and \cuisenaireiii
. They are available as options to the environment -- see examples below. The option i
(therefore \cuisenairei
) is the default; using the third scheme would require setting colorset=iii
for example.
You can use the number 0
to specify a placeholder (not drawn) box, making possible arbitrary spacing. See the last example below.
The colors are quick and relatively accurate approximations, though you are free to alter them to suit your own purposes.
The color black is used for any non-specified colors. It is also used for one of the rod colors in some of the schemes (7 in \cuisenairei
, for example).
Another option to the RoB
environment: You can specify that the numbers can be shown in the colored rectangles. Simply writing shownums
or shownums=true
will work.
Apologies for the somewhat more prolix code.
\documentclass{article}
\usepackage[margin=0.5in]{geometry}
\usepackage{xparse}
\usepackage{tikz}
\usepackage{keyval}
\newcounter{ybpos}
\newcounter{xbpos}
\newlength{\boxsize}
\newif\ifshownums
\def\colorset{i}
\setlength{\boxsize}{10pt}
\makeatletter
\define@key{cuisen}{colorset}{\def\colorset{#1}}
\define@key{cuisen}{boxsize}{\setlength{\boxsize}{#1}}
\define@key{cuisen}{shownums}[true]{\csname shownums#1\endcsname}
\makeatother
%% |=====8><-----| %%
%% Default is \cuisinairei
%% https://en.wikipedia.org/wiki/Cuisenaire_rods
%% Standard
%% 1-10
\def\cuisenairei{\ifcase\xbwd x\or white\or red\or green!50\or purple\or yellow\or green!50!black\or black\or brown\or blue\or orange\else black\fi}
%% to 10,12,16 all others black
\def\cuisenaireii{\ifcase\xbwd x\or white\or pink\or blue!50\or red\or yellow\or purple\or black\or brown\or blue\or orange\or black\or green\or black\or black\or black\or brown!50\else black\fi}
%%
%% to 12
%% 1 is white.
%% The first three primes (2,3,5) are basic colors: red, blue and yellow.
%% Primes >5 are a shade of gray
%% The remaining non-primes result from mixing the colors of their factors.
\definecolor{mauve}{rgb}{0.89,0.685,1}
\def\cuisenaireiii{\ifcase\xbwd x\or white\or red!50\or blue!50\or red\or yellow\or violet\or gray!80\or red!85!black\or blue!80!red\or yellow!60!orange\or black!60\or mauve\else black\fi}
% * draws rows top-to-bottom; optional argument for size, default=10pt
\NewDocumentEnvironment{RoB}{sO{}}{%
\IfBooleanTF{#1}{\def\ttob{-1}}{\def\ttob{1}}%
\setcounter{ybpos}{0}
\setkeys{cuisen}{#2}
\begin{tikzpicture}[outer sep=0pt]
}{%
\end{tikzpicture}%
}
\NewDocumentCommand{\boxrow}{m}{%
\setcounter{xbpos}{0}
\foreach \xbwd in {#1}{%
%% Change the order of colors to suit...
\expandafter\def\expandafter\boxcolor\expandafter{\csname cuisenaire\colorset\endcsname}
\if x\boxcolor
\node[minimum width=\boxsize,
minimum height=\boxsize,
anchor=south west] at (\thexbpos*\boxsize,\ttob*\theybpos*\boxsize) {};
\stepcounter{xbpos}
\else
\node[draw,
inner sep=0pt,
thick,
fill=\boxcolor,
minimum height=\boxsize,
minimum width=\xbwd*\boxsize,
anchor=south west] at (\thexbpos*\boxsize,\ttob*\theybpos*\boxsize)
{\ifshownums\tiny\xbwd\fi};
\addtocounter{xbpos}{\xbwd}
\fi
}%
\stepcounter{ybpos}%
}
%% |=====8><-----| %%
\parindent0pt
\begin{document}
\begin{RoB}*[colorset=i]
\boxrow{1}
\boxrow{2}
\boxrow{3}
\boxrow{4}
\boxrow{5}
\boxrow{6}
\boxrow{7}
\boxrow{8}
\boxrow{9}
\boxrow{10}
\end{RoB}
\begin{RoB}*[colorset=i,boxsize=9pt]
\boxrow{10}
\boxrow{1,9}
\boxrow{2,8}
\boxrow{3,7}
\boxrow{4,6}
\boxrow{5,5}
\boxrow{6,4}
\boxrow{7,3}
\boxrow{8,2}
\boxrow{9,1}
\boxrow{10}
\end{RoB}
\medskip
\begin{RoB}[colorset=ii,shownums]
\boxrow{1}
\boxrow{2}
\boxrow{3}
\boxrow{4}
\boxrow{5}
\boxrow{6}
\boxrow{7}
\boxrow{8}
\boxrow{9}
\boxrow{10}
\boxrow{12}
\boxrow{16}
\end{RoB}
\begin{RoB}[colorset=ii,boxsize=9pt,shownums]
\boxrow{16}
\boxrow{1,3,12}
\boxrow{2,4,10}
\boxrow{3,5,8}
\boxrow{4,12}
\boxrow{5,1,10}
\boxrow{6,4,6}
\boxrow{7,9}
\boxrow{8,5,3}
\boxrow{9,7}
\boxrow{10,1,5}
\boxrow{12,1,3}
\boxrow{16}
\end{RoB}
\medskip
\begin{RoB}*[colorset=iii]
\boxrow{1}
\boxrow{2}
\boxrow{3}
\boxrow{4}
\boxrow{5}
\boxrow{6}
\boxrow{7}
\boxrow{8}
\boxrow{9}
\boxrow{10}
\boxrow{11}
\boxrow{12}
\end{RoB}
\begin{RoB}*[colorset=iii,boxsize=9pt]
\boxrow{12}
\boxrow{1,11}
\boxrow{2,10}
\boxrow{3,9}
\boxrow{4,8}
\boxrow{5,7}
\boxrow{6,6}
\boxrow{7,5}
\boxrow{8,4}
\boxrow{9,3}
\boxrow{10,2}
\boxrow{11,1}
\boxrow{12}
\end{RoB}
\medskip
\noindent
\hspace{1.25in}
\begin{RoB}*[boxsize=1cm]
\boxrow{1,0,0,0,1}
\boxrow{0}
\boxrow{0,0,1}
\boxrow{0,0,1}
\boxrow{0}
\boxrow{0,3}
\end{RoB}
\end{document}

Yet another update...
There are two differences here: 1) the use of the TikZ \draw
command in place of \node
; and 2) rounded corners for the rectangles (the same option could be applied to \node
commands) -- gives a feeling for `rods'.
\documentclass{article}
\usepackage[margin=0.5in]{geometry}
\usepackage{xparse}
\usepackage{tikz}
\usepackage{keyval}
\newcounter{ybpos}
\newcounter{xbpos}
\newlength{\boxsize}
\newif\ifshownums
\def\colorset{i}
\setlength{\boxsize}{10pt}
\makeatletter
\define@key{cuisen}{colorset}{\def\colorset{#1}}
\define@key{cuisen}{boxsize}{\setlength{\boxsize}{#1}}
\define@key{cuisen}{shownums}[true]{\csname shownums#1\endcsname}
\makeatother
%% |=====8><-----| %%
%% Default is \cuisinairei
%% https://en.wikipedia.org/wiki/Cuisenaire_rods
%% Standard
%% 1-10
\def\cuisenairei{\ifcase\xbwd x\or white\or red\or green!50\or purple\or yellow\or green!50!black\or black\or brown\or blue\or orange\else black\fi}
%% to 10,12,16 all others black
\def\cuisenaireii{\ifcase\xbwd x\or white\or pink\or blue!50\or red\or yellow\or purple\or black\or brown\or blue\or orange\or black\or green\or black\or black\or black\or brown!50\else black\fi}
%%
%% to 12
%% 1 is white.
%% The first three primes (2,3,5) are basic colors: red, blue and yellow.
%% Primes >5 are shades of gray
%% The remaining non-primes result from mixing the colors of their factors.
\definecolor{mauve}{rgb}{0.89,0.685,1}
\def\cuisenaireiii{\ifcase\xbwd x\or white\or red!50\or blue!50\or red\or yellow\or violet\or gray!80\or red!85!black\or blue!80!red\or yellow!60!orange\or black!60\or mauve\else black\fi}
% * draws rows top-to-bottom; optional argument for keyval
\NewDocumentEnvironment{RoB}{sO{}}{%
\IfBooleanTF{#1}{\def\ttob{-1}}{\def\ttob{1}}%
\setcounter{ybpos}{0}%
\setkeys{cuisen}{#2}%
\begin{tikzpicture}[outer sep=0pt]
}{%
\end{tikzpicture}%
}
\NewDocumentCommand{\boxrow}{m}{%
\setcounter{xbpos}{0}%
\foreach \xbwd in {#1}{%
\expandafter
\def
\expandafter
\boxcolor
\expandafter{\csname cuisenaire\colorset\endcsname}
\if x\boxcolor
\path (\thexbpos*\boxsize,\ttob*\theybpos*\boxsize)
rectangle
++(\boxsize,\boxsize);
\stepcounter{xbpos}
\else
\draw[thick,fill=\boxcolor,
rounded corners=2pt](\thexbpos*\boxsize,\ttob*\theybpos*\boxsize)
rectangle node[inner sep=0pt,font=\tiny] {\ifshownums\xbwd\fi}
++(\xbwd*\boxsize,\boxsize);
\addtocounter{xbpos}{\xbwd}
\fi
}%
\stepcounter{ybpos}%
}
%% |=====8><-----| %%
\parindent0pt
\begin{document}
\begin{RoB}*[colorset=i]
\boxrow{1}
\boxrow{2}
\boxrow{3}
\boxrow{4}
\boxrow{5}
\boxrow{6}
\boxrow{7}
\boxrow{8}
\boxrow{9}
\boxrow{10}
\end{RoB}
\begin{RoB}*[colorset=i,boxsize=9pt]
\boxrow{10}
\boxrow{1,9}
\boxrow{2,8}
\boxrow{3,7}
\boxrow{4,6}
\boxrow{5,5}
\boxrow{6,4}
\boxrow{7,3}
\boxrow{8,2}
\boxrow{9,1}
\boxrow{10}
\end{RoB}
\medskip
\begin{RoB}[colorset=ii,shownums]
\boxrow{1}
\boxrow{2}
\boxrow{3}
\boxrow{4}
\boxrow{5}
\boxrow{6}
\boxrow{7}
\boxrow{8}
\boxrow{9}
\boxrow{10}
\boxrow{12}
\boxrow{16}
\end{RoB}
\begin{RoB}[colorset=ii,boxsize=9pt,shownums]
\boxrow{16}
\boxrow{1,3,12}
\boxrow{2,4,10}
\boxrow{3,5,8}
\boxrow{4,12}
\boxrow{5,1,10}
\boxrow{6,4,6}
\boxrow{7,9}
\boxrow{8,5,3}
\boxrow{9,7}
\boxrow{10,1,5}
\boxrow{12,1,3}
\boxrow{16}
\end{RoB}
\medskip
\begin{RoB}*[colorset=iii]
\boxrow{1}
\boxrow{2}
\boxrow{3}
\boxrow{4}
\boxrow{5}
\boxrow{6}
\boxrow{7}
\boxrow{8}
\boxrow{9}
\boxrow{10}
\boxrow{11}
\boxrow{12}
\end{RoB}
\begin{RoB}*[colorset=iii,boxsize=9pt]
\boxrow{12}
\boxrow{1,11}
\boxrow{2,10}
\boxrow{3,9}
\boxrow{4,8}
\boxrow{5,7}
\boxrow{6,6}
\boxrow{7,5}
\boxrow{8,4}
\boxrow{9,3}
\boxrow{10,2}
\boxrow{11,1}
\boxrow{12}
\end{RoB}
\medskip
\noindent
\hspace{1.25in}
\begin{RoB}*[boxsize=1cm]
\boxrow{1,0,0,0,1}
\boxrow{0}
\boxrow{0,0,1}
\boxrow{0,0,1}
\boxrow{0}
\boxrow{0,3}
\end{RoB}
\end{document}
