# How to pimp my tube?

How can I pimp my tube?

\documentclass{scrartcl}
% needs logicpuzzle bundle v1.8
% http://mirrors.ctan.org/graphics/pgf/contrib/logicpuzzle/logicpuzzle.sty
% or replace logicpuzzle -> battleship
\usepackage{logicpuzzle}
\makeatletter
\definecolor{LPlgrey}{rgb}{.8,.8,.8}
\definecolor{LPtgrey}{rgb}{.7,.7,.7}
\definecolor{LPgrey}{rgb}{.5,.5,.5}
\def\myscale{.7}
\newcommand*\LPtunnel%
{%
\begin{tikzpicture}[scale=\myscale]
\fill[color=black] (0,0) -- (0,1) -- (.4,.5) -- (.4,0) -- cycle;
\fill[color=LPgrey] (0,1) -- (1,1) -- (1,.5) -- (.4,.5) -- cycle;
\fill[color=LPlgrey] (.40,0) rectangle (1,.5);
\end{tikzpicture}
}%
\newcommand*\tunnel[2]{\LP@setcellcontent{#1}{#2}{\LPtunnel}}
\newcommand*\tube[3]%
{%
\def\tubepath{%
(#1.5,#2.5)
\foreach \dir in {#3}%
{%
\ifnum\dir=2%
--++(0,-1)%
\fi%
\ifnum\dir=4%
--++(-1,0)%
\fi%
\ifnum\dir=6%
--++(1,0)%
\fi%
\ifnum\dir=8%
--++(0,1)%
\fi%
};}%
\begin{puzzlebackground}
\pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
\draw[color=LPtgrey, line width=.4cm*\myscale] \tubepath;%
\end{puzzlebackground}
}%
\makeatother
\begin{document}
\begin{logicpuzzle}[scale=\myscale]
\tunnel{1}{1}
\tunnel{5}{5}
\tube{1}{1}{6,6,6,6,8,8,8,4,2,4,4,4,8,8,6,6,6,6}
\end{logicpuzzle}
\end{document}


Can I add a decoration like in this picture?

I know I can add a shading (kind of 3D effect) to a rectangle. But it is also possible for such a complex path with a shading based on the angle?

Another important point: It must survive scaling.

• That looks like a line with double option. I don't see where the shadows come into play here. – percusse Apr 18 '13 at 14:25
• @percusse Not in the picture tube. The shading 3D-effect is just another idea. – Josef Apr 18 '13 at 14:32

Something like that ?

\documentclass{standalone}
% needs logicpuzzle bundle v1.8
% http://mirrors.ctan.org/graphics/pgf/contrib/logicpuzzle/logicpuzzle.sty
% or replace logicpuzzle -> battleship
\usepackage{logicpuzzle}
\makeatletter
\definecolor{LPlgrey}{rgb}{.8,.8,.8}
\definecolor{LPtgrey}{rgb}{.7,.7,.7}
\definecolor{LPgrey}{rgb}{.5,.5,.5}
\def\myscale{.7}
\newcommand*\LPtunnel%
{%
\begin{tikzpicture}[scale=\myscale]
\fill[color=black] (0,0) -- (0,1) -- (.4,.5) -- (.4,0) -- cycle;
\fill[color=LPgrey] (0,1) -- (1,1) -- (1,.5) -- (.4,.5) -- cycle;
\fill[color=LPlgrey] (.40,0) rectangle (1,.5);
\end{tikzpicture}
}%
\newcommand*\tunnel[2]{\LP@setcellcontent{#1}{#2}{\LPtunnel}}
\newcommand*\tube[3]%
{%
\def\tubepath{%
(#1.5,#2.5)
\foreach \dir in {#3}%
{%
\ifnum\dir=2%
--++(0,-1)%
\fi%
\ifnum\dir=4%
--++(-1,0)%
\fi%
\ifnum\dir=6%
--++(1,0)%
\fi%
\ifnum\dir=8%
--++(0,1)%
\fi%
};}%
\begin{puzzlebackground}
\pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
\draw[color=LPtgrey!80!black, line width=.4cm*\myscale] \tubepath;%
\draw[color=LPtgrey, line width=.38cm*\myscale] \tubepath;%
\draw[color=LPtgrey!85, line width=.35cm*\myscale] \tubepath;%
\draw[color=LPtgrey!70, line width=.32cm*\myscale] \tubepath;%
\draw[color=LPtgrey!55, line width=.29cm*\myscale] \tubepath;%
\draw[color=LPtgrey!45, line width=.25cm*\myscale] \tubepath;%
\draw[color=LPtgrey!35, line width=.2cm*\myscale] \tubepath;%
\end{puzzlebackground}
}%
\makeatother
\begin{document}
\begin{tikzpicture}[scale=\myscale]
\path[draw] (1,1) grid (6,6);
\tunnel{1}{1}
\tunnel{5}{5}
\tube{1}{1}{6,6,6,6,8,8,8,4,2,4,4,4,8,8,6,6,6,6}
\end{tikzpicture}
\end{document}


• looks fine, indeed! ;-) – Josef Apr 18 '13 at 14:37
• This solution shall be part of tunnel.sty in the next version of the logicpuzzle bundle. May i kindly ask you for a waiver (based on cc-wiki) to include your code and license it under LPPL? I will of course attribute you. Even with your real name, if you contact me. ;-) – Josef Apr 19 '13 at 10:47
• you can use this code as you want ! I'm happy that it's useful for you. – Xoff Apr 19 '13 at 13:47

Solution below uses the Asymptote module tubepuzzle.asy to set up the puzzle and to draw it. The puzzle is defined by dimensions and a pipe path, numbers are counted automatically. File tpuzzle.tex:

\begin{filecontents*}{tubepuzzle.asy}
struct TubePuzzle{
int m,n;
pair start;
pair fin;
guide pipe;
pen inPen,outPen;
pen txtPen,gridPen;
pen botPen,topPen;
pen leftPen;

int[] rowCount;
int[] colCount;
int[][] M;

picture picBoard;

void iniPens(){
inPen= rgb(236/255,234/255,238/255)+5;
outPen=rgb(132/255,174/255,204/255)+7;
txtPen=rgb(52/255,50/255,52/255);
gridPen=txtPen+0.8pt;
botPen=rgb(228/255,238/255,236/255);
topPen=rgb(132/255,134/255,132/255);
leftPen=rgb(28/255,30/255,36/255);
}
transform sh,pipesh;

void hole(picture pict,pair t, transform tr){
pair a=(0,0);
fill(pict,tr*shift(t)*((a.x,-0.5)--(0.5,-0.5)--(0.5,a.y)--a--cycle),botPen);
fill(pict,tr*shift(t)*(a--(-0.5,0.5)--(-0.5,-0.5)--(a.x,-0.5)--cycle),leftPen);
fill(pict,tr*shift(t)*(a--(0.5,a.y)--(0.5,0.5)--(-0.5,0.5)--cycle),topPen);
}

void countCells(){
rowCount=array(m,0);
colCount=array(n,0);
M=array(m,array(n,0));
pair a,b,c,d;
a=point(pipe,0);
for(int k=1;k<size(pipe);++k){
b=point(pipe,k);
c=(min(a.x,b.x),min(a.y,b.y));
d=(max(a.x,b.x),max(a.y,b.y));
for(int i=(int)c.y;i<=(int)d.y;++i)M[i-1][(int)d.x-1]=max(M[i-1][(int)d.x-1],1);
for(int j=(int)c.x;j<=(int)d.x;++j)M[(int)d.y-1][j-1]=max(M[(int)d.y-1][j-1],1);
a=b;
}
for(int i=0;i<M.length;++i){
for(int j=0;j<M[0].length;++j){
colCount[j]+=M[i][j];
rowCount[i]+=M[i][j];
}
}
}

picture draw(transform sc=identity(), bool showPipe=false){
picture temp;
erase(picBoard);
for(int i=1;i<m;++i){
draw(pict,tr*sh*((0,i)--(n,i)),gridPen);
}
for(int j=1;j<n;++j){
draw(pict,tr*sh*((j,0)--(j,m)),gridPen);
}
draw(pict,tr*sh*((0,0)--(n,0)--(n,m)--(0,m)--cycle),gridPen+2pt);

real  xxyy=max(tr.xx,tr.xy,tr.yx,tr.yy);
inPen= rgb(236/255,234/255,238/255)+xxyy*0.5;
outPen=rgb(132/255,174/255,204/255)+xxyy*0.8;

if(showPipe){// drawTube(pict,tr);

draw(pict,tr*pipesh*pipe,outPen);
draw(pict,tr*pipesh*pipe,inPen);
}
hole(pict,start,tr);
hole(pict,fin,tr);
for(int i=0;i<rowCount.length;++i){
label(pict,tr*shift(-1,i)*scale(2pt/10mm)*Label(string(rowCount[i])));
}
for(int j=0;j<colCount.length;++j){
label(pict,tr*shift(j,m)*scale(2pt/10mm)*Label(string(colCount[j])));
}
});
return picBoard;
}

void operator init(int m=9, int n=m
, guide pipe=(1,1)--(n,1)--(n,m)
){
this.sh=shift(-0.5,-0.5);
this.pipesh=shift(-1,-1);
this.m     = m    ;
this.n     = n    ;
this.pipe  = pipe ;
this.start = pipesh*point(this.pipe,0);
this.fin   = pipesh*point(this.pipe,length(this.pipe));
iniPens();
countCells();
}
}
\end{filecontents*}
%
%
\documentclass[10pt,a4paper]{article}
\usepackage{lmodern}
\usepackage{caption}
\usepackage{asymptote}
\begin{document}

\section*{Tube puzzles with the Asymptote}
\begin{minipage}{5cm}
\center
\begin{asy}
import tubepuzzle;
unitsize(5mm);
texpreamble("\usepackage{lmodern}");
TubePuzzle tp=TubePuzzle();
\end{asy}
\captionof{figure}{Default puzzle board}
\end{minipage}
%
\begin{minipage}{5cm}
\begin{asy}
import tubepuzzle;
unitsize(5mm);
//size(300,300,IgnoreAspect);
texpreamble("\usepackage{lmodern}");
TubePuzzle tp=TubePuzzle();
\end{asy}

\captionof{figure}{Default puzzle solution}
\end{minipage}

\center
\begin{asy}
import tubepuzzle;
unitsize(5mm);
//size(300,300,IgnoreAspect);
texpreamble("\usepackage{lmodern}");
guide g=(4,2)--(4,1)--(2,1)--(2,2)--(1,2)--(1,4)--(5,4)--(5,6)--(1,6)
--(1,8)--(2,8)--(2,9)--(5,9)--(5,8)--(9,8)--(9,4)--(8,4)--(8,3)--(7,3)--(7,2);

TubePuzzle tp=TubePuzzle(9,9,pipe=g);
\end{asy}

\captionof{figure}{Custom puzzle/solution}

\end{document}


To process it with latexmk, create file latexmkrc:

sub asy {return system("asy '\$_[0]'");}


and run latexmk -pdf tpuzzle.tex.

• Each and every one of your answers using Asymptote convinces me more and more that it's a really powerful tool. Fantastic job! – Gonzalo Medina Apr 18 '13 at 23:36
• Thanks a lot for your perspective, it inspires everyone. – texenthusiast Apr 19 '13 at 5:56
• @Gonzalo Medina: It is really powerful indeed. Just touching the tip of the iceberg, actually. – g.kov Apr 19 '13 at 9:36
• Interesting answer, but i'm focused on TikZ – Josef Apr 19 '13 at 10:41

Just for completeness:

Based on percusse's comment about double, here's a version for a tube like in the picture.

\newcommand*\tube[3]%
{%
\def\tubepath{%
(#1.5,#2.5)
\foreach \dir in {#3}%
{%
\ifnum\dir=2%
--++(0,-1)%
\fi%
\ifnum\dir=4%
--++(-1,0)%
\fi%
\ifnum\dir=6%
--++(1,0)%
\fi%
\ifnum\dir=8%
--++(0,1)%
\fi%
};}%
\begin{puzzlebackground}
\pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
\draw[color=blue!40, double=LPtgrey!40, line width=1pt*\myscale, double distance between line centers=.4cm*\myscale] \tubepath;%
\end{puzzlebackground}
}%


For a version with corners, just delete \pgfsetcornersarced{\pgfpoint{3mm}{3mm}}

Just for fun. The pipe is drawn with a double line, the tunnel is defined with a pic which allows to repeate it very easily. And pipe's path is defined using perpendicular segments or following turtle route.

\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{turtle}

\definecolor{LPlgrey}{rgb}{.8,.8,.8}
\definecolor{LPtgrey}{rgb}{.7,.7,.7}
\definecolor{LPgrey}{rgb}{.5,.5,.5}
\tikzset{
pipe/.style={double=gray!30, draw, double distance=3mm, rounded corners=3mm},
tunnel/.pic={%
\fill[color=black] (0,0) -- (0,1) -- (.4,.5) -- (.4,0) -- cycle;
\fill[color=LPgrey] (0,1) -- (1,1) -- (1,.5) -- (.4,.5) -- cycle;
\fill[color=LPlgrey] (.40,0) rectangle (1,.5);}
}

\begin{document}
\begin{tikzpicture}
\draw (0,0) grid (5,5);
\path (0,0) pic{tunnel};
\path (4,4) pic{tunnel};
\draw[pipe] (1,.5)-|(4.5,3.5)-|(3.5,2.5)-|(0.5,4.5)--(4,4.5);
\end{tikzpicture}

\begin{tikzpicture}
\draw (0,0) grid (5,5);
\path (0,0) pic{tunnel};
\path (4,4) pic{tunnel};
\draw[pipe] (1,.5)
[turtle={right, fd=3.5, lt, fd=3, lt, fd, lt, fd, rt, fd=3, rt, fd=2, rt, fd=3.5}];
\end{tikzpicture}
\end{document}