# How to randomly shuffle a sliced image?

I have no idea to shuffle the following grids of a sliced image. How to do this in (La)TeX or PostScript level?

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{multido}
\usepackage{graphicx}

\def\Columns{5}% columns
\def\Rows{5}% rows
\def\Filename{ParisHilton}
\def\Scale{1}

\newsavebox\IBox
\savebox\IBox{\includegraphics[scale=\Scale]{\Filename}}

\psset
{
xunit=\dimexpr\wd\IBox/\Columns,
yunit=\dimexpr\ht\IBox/\Rows,
}

\SpecialCoor
\begin{document}

\multido{\ny=\Rows+-1}{\Rows}
{
\multido{\nx=0+1}{\Columns}
{
\pspicture(\Columns,\Rows)
\psclip{\psframe[linestyle=none,linewidth=0pt](!\nx\space \ny\space 1 sub)(!\nx\space 1 add \ny)}
\rput[bl](0,0){\usebox\IBox}
\endpsclip
\endpspicture
}
}

\end{document}


Here is the picture that I used in this answer as a demo picture.

-
@PauloCereda made a blog post about selecting parts of an image which is here: tex.blogoverflow.com/2012/05/using-sprite-sheets-with-latex . So the remaining part is to randomize the parts and Bob's your uncle and Paris is family anyway. – percusse Sep 6 '12 at 17:27
I added now random-numbers. This lead me to the following related question which looks promising: tex.stackexchange.com/questions/63357/… – Martin Scharrer Sep 6 '12 at 17:39
I'm surprised that you accepted Herbert's answer instead of Aditya's or percusse's: I had understood that you wanted the position of the slides to be shuffled, not the order of appearance. Maybe it would be a good idea to edit your question to be more explicit about this point. – Jake Sep 7 '12 at 13:47
@Jake: Because I prefer the cryptic PostScript language (even though I don't understand well what Herbert wrote). :-) Other answers are good of course. Shuffling for either the position of slides or the order of appearance is almost identical, so it was not taken under my consideration. – kiss my armpit Sep 7 '12 at 13:49

## 4 Answers

\documentclass[pstricks]{standalone}
\usepackage{multido}
\usepackage{graphicx}
\def\txG{ true setglobal globaldict begin }
\def\etxG{ end false setglobal }

\def\Columns{4}  \def\Rows{5}
\pstFPmul\MaxElements{\Columns}{\Rows}

\pstVerb{\txG
/u.n \Columns\space \Rows\space mul def
/Elements [ 0 1 u.n 1 sub { } for ] def
realtime srand
/GetElement {
rand u.n mod /Random ED
Random
Elements length mod Elements exch get dup
5 mod /u.Col ED % col
5 div cvi /u.Row ED % row
Elements aload length dup 1 sub /u.n ED
Random sub -1 roll pop u.n array astore /Elements ED
} def
\etxG }

\newsavebox\IBox
\savebox\IBox{\includegraphics{dante22}}
\psset{xunit=\dimexpr\wd\IBox/\Columns,  yunit=\dimexpr\ht\IBox/\Rows}
\SpecialCoor
\begin{document}

\multido{\iA=1+1}{\MaxElements}{%
\begin{pspicture}(\Columns,\Rows)
\rput[lb](!0 0){%
\psclip{\psframe[linestyle=none]%
(! \txG GetElement u.Row u.Col \etxG)
(! \txG u.Row 1 add u.Col 1 add \etxG)} \usebox\IBox
\endpsclip}
\end{pspicture}}%

\end{document}


-
One glitch found. You need to specify the clipping frame with either linewidth=0pt or dimen=middle to remove the inter-cell space. – kiss my armpit Sep 7 '12 at 15:38

Here is a simple LuaTeX/ConTeXt based solution.

\shuffle[nx=..., ny=...]{<box>}


where nx is the number of horizontal slices that you want, and my is the number of vertical slices that you want. The macro is based on \setupclipping and which does the actual hard work of clipping the image. This macro effective generates:

\clip[nx=...,ny=...,x=...,y=...]{<box>}


by randomly varying x and y over all possible values. To generate such x and y, I simply generate all possible values and shuffle the result. AFAIK, Lua does not have a shuffle function, so I implemented one based on the standard Fisher Yates algorithm.

Here is the result of \shuffle[nx=3,ny=2]{\externalfigure[hacker]} (hacker is one of the sample images distributed with ConTeXt).

And finally, the macro:

\startluacode
local random = math.random
local insert = table.insert
local format = string.format
-- Note that ConTeXt stores the value of the random seed
-- in the tuc file to ensure that you get the random numbers
-- don't change across runs. If you want a different set of random
-- numbers just delete the tuc file and compile again

-- A function to shuffle the contents of a table
local function shuffle_table(data)
-- implementation of Fisher Yates shuffle
local t
for i=#data,1,-1 do
local j = random(1,i)
-- Swap i and j location
t       = data[i]
data[i] = data[j]
data[j] = t
end
return data
end

local function shuffle_box(nx, ny, box)
-- Generate table of all possible indices
local indices = {}
for i=1,nx do
for j=1,ny do
insert(indices, {i,j})
end
end
indices = shuffle_table(indices)
-- table.print(indices)

local x, y, settings
context("\\vbox\\bgroup")
context("\\baselineskip\\zeropoint \\lineskip\\zeropoint")
for i = 1,nx do
context("\\hbox\\bgroup") -- This can be frame for more control
for j=1,ny do
x, y = indices[(i-1)*nx+j][2], indices[(i-1)*nx+j][2]
settings = format("nx=%d, ny=%d, x=%d, y=%d", nx, ny, x, y)
-- print(settings)
context.clip({settings}, box)
end
context("\\egroup")
end
context("\\egroup")

end
commands.shuffle = shuffle_box

\stopluacode

\unprotect
\unexpanded\def\shuffle
{\dosingleargument\shuffle_indeed}

\def\????shuffle{@@@@shuffle}

\def\shuffle_indeed[#1]#2% #2 should be some boxed material
{\getparameters[\????shuffle][\c!nx=4,\c!ny=4,#1]%
\ctxcommand{shuffle(\@@@@shufflenx, \@@@@shuffleny, \!!bs #2 \!!es)}}

\starttext
\shuffle[nx=3,ny=3]{\externalfigure[cow]}
\stoptext

-
random(1,i) can be simplified as random(i). – kiss my armpit Apr 2 '13 at 11:29

Here is another one. The code is a little messy so I'll divide the output:

First of all I needed to get a random list, I did it via first declaring a regular increasing numbers list. Then I picked up one from it and put it into a new one. At the same time, I've deleted that number from the old list and repeated this until we run out of numbers.

So the output looks like this

The picked up number switches to our new list on the right (then we remove the initial comma).

Then (counting as 11-> 8+3 second row, third column) We get the random number from our list, convert to the cell coordinate and shift the image behind the node according to the idea that our famous Paulo Cereda has given in the blog post about sprite sheets. I've chosen 4 by 4 grid but can be changed. Also note that the underlying coordinate system is scaled to match the width and height of the image.

I've used the Hilton Hotel in Paris and the image is from their website because I can't stand those celebrities. So the output is

# The Code

(as Peter Grill would do)

\documentclass{article}
\usepackage{tikz,xstring}
% Declare the image
\pgfdeclareimage[interpolate=true,width=8cm,height=5cm]{hotel}{hiltonparis.jpg}
\def\mylist{}
\def\myrandlist{}
\foreach \x in {1,...,16}{ %Generate list
\xdef\mylist{\mylist\noexpand{\x\noexpand}}
}

\begin{document}

\pgfmathdeclarerandomlist{mynum}{\mylist} %Define the list
\foreach \x in {1,...,16}{
\pgfmathrandomitem{\mynum}{mynum} % Pick one from that list
\xdef\myrandlist{\myrandlist,\mynum} % place in the new list
\StrSubstitute{\mylist}{{\mynum}}{}[\sublist] % Delete that entry from the list
\global\let\mylist\sublist % Update the main list
\pgfmathdeclarerandomlist{mynum}{\mylist} % Redefine the list

\mylist\hfill \myrandlist%Let's see if we succeeded removing duplicates. Remove later
}

% Remove the first comma
\StrGobbleLeft{\myrandlist}{1}[\myrandlist]
\xdef\myrandlist{{\myrandlist}} % After all, it's a stupid shuffle

\pgfuseimage{hotel}

\vspace{1cm}
\begin{tikzpicture}[xscale=2,yscale=1.25, %Scaling according to the image
path image/.style args={#1 shifted #2 and #3}{%
path picture={
\node[anchor=north west,outer sep=0]
at ([shift={(-#2,#3)}]path picture bounding box.north west) {\pgfuseimage{#1}};
}
}]
\foreach \x in {0,...,3}{
\foreach \y in {0,...,3}{
\pgfmathtruncatemacro{\yy}{4*\x+\y}
\pgfmathtruncatemacro{\xx}{\myrandlist[\yy]}
\pgfmathtruncatemacro{\curry}{Mod(\xx,4)}
\pgfmathtruncatemacro{\currx}{(\xx)/4} % Integer part
\path[path image=hotel shifted \currx cm and \curry cm] %Shifts the image
(\x cm,-\y cm) rectangle +(1cm,1cm); %The size is the unit shift size
}
}
\end{tikzpicture}
\end{document}

-
Why can't you stand? :-) – kiss my armpit Sep 10 '12 at 4:23
@GarbageCollector Do you know the slang phrase waste of space? – percusse Sep 10 '12 at 11:55
I understood after reading and watching this video. – kiss my armpit Sep 11 '12 at 4:30
@GarbageCollector :) Nice. – percusse Sep 11 '12 at 7:51

Because of the first comment given to the question, I don't shuffle the grid position. I shuffle the order of cells taken to compose the animation frames instead. The essence remains unchanged.

A hybrid solution with C# is as follows. This code has been reviewed and optimized by an expert.

/*===================================*
* Compile it to produce Shuffle.exe *
* ==================================*/
using System;
using System.Collections.Generic;
using System.IO;

namespace Shuffle
{
class Program
{
static void Main(string[] args)
{
int columns = int.Parse(args[0]);
int rows = int.Parse(args[1]);
int seed = int.Parse(args[2]);
string outputFilename = args[3];

string[] elements = new string[columns * rows];
for (int column = 0; column < columns; column++)
for (int row = 0; row < rows; row++)
elements[column * rows + row] = string.Format("{{{0},{1}}}", column, row);

Random random = new Random(seed);
for (int i = elements.Length - 1; i >= 0; i--)
{
int swapIndex = random.Next(i + 1);
string tmp = elements[i];
elements[i] = elements[swapIndex];
elements[swapIndex] = tmp;
}

File.WriteAllLines(outputFilename, elements);
}
}
}


\documentclass[pstricks,border=12pt]{standalone}
\usepackage{multido}
\usepackage{graphicx}

\def\Columns{10}% columns
\def\Rows{10}% rows
\def\Filename{parishilton}
\def\Scale{1}

\newsavebox\IBox
\savebox\IBox{\includegraphics[scale=\Scale]{\Filename}}

\psset
{
xunit=\dimexpr\wd\IBox/\Columns,
yunit=\dimexpr\ht\IBox/\Rows,
}

\SpecialCoor
\newread\myfile

\def\tempii#1,#2{%
\pspicture(\Columns,\Rows)
\psclip{\psframe[linestyle=none,linewidth=0pt](!#1 #2)(!#1 1 add #2 1 add)}
\rput[bl](0,0){\usebox\IBox}
\endpsclip
\endpspicture}

\def\tempi#1{\expandafter\tempii#1\relax}

\begin{document}

\immediate\write18{cmd /C del data.txt}
\immediate\write18{Shuffle.exe \Columns\space \Rows\space 1 data.txt}

\openin\myfile=data.txt\relax
\loop
\read\myfile to \dd
\unless\ifeof\myfile
\expandafter\tempi\dd\relax
\repeat
\closein\myfile

\end{document}

-
Oops then I completely misunderstood the question. – percusse Sep 6 '12 at 21:59
@percusse: No. You understood the question well. – kiss my armpit Sep 6 '12 at 22:00
Your algorithm does not produce good shuffles... Look at Aditya's answer with the Fisher Yates shuffle. – Paul Gaborit Sep 6 '12 at 22:15
Fisher Yates algorithm is O(n) and is truly random (as far as the pseudo-random generator) and all permutations are equiprobable. Your method requires many more iterations to tend towards the same result. – Paul Gaborit Sep 6 '12 at 22:23
@PaulGaborit: Now I used the best algorithm. – kiss my armpit Sep 10 '12 at 4:33