Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

How strings are twisted

The twisting algorithm is very simple. Each column is shifted down by its index (col 0 moves down 0, col 1 moves 1, ...). The column shift wraps to the top. It works like this:

aaaa
bbbb
cccc

Becomes:

a
ba
cba
----
 cba
  cb
   c

With everything under the line wrapping to the top. Real example:

Original:
\\\\\\\\\\\\
............
............
............

Twisted:
\...\...\...
.\...\...\..
..\...\...\.
...\...\...\

Input

Input is either an array of strings, or a multi-line string. All lines have the same length.

Output

The twisted string, multi-line output to std-out (or closest alternative).

Examples:

(> denotes input, trailing space is important)

>Hello, world!
>I am another 
>string to be 
>twisted!     

Hwrmoe oo br!
Ieii ,dttr e 
s lsna !ohl  
ttaltgnw  ed 


>\\\\\\\\\\\\
>............
>............
>............

\...\...\...
.\...\...\..
..\...\...\.
...\...\...\


>abcdefg
>.......

a.c.e.g
.b.d.f.


>abcdefghij
>..........
>..........

a..d..g..j
.b..e..h..
..c..f..i.


>\\\\.....././
>...../.......
>........././.
>..../.^\\....

\.........../
.\....^..../.
..\../.\../..
...\/...\/...

>cdeab
>deabc
>eabcd
>abcde

cbbbb
ddccc
eeedd
aaaae


>aeimquy37
>bfjnrvz48
>cgkosw159
>dhlptx260

ahknqx147
beloru258
cfipsvy69
dgjmtwz30


>abcdefghi
>jklmnopqr
>stuvwxyz1
>234567890

a3ume7yqi
jb4vnf8zr
skc5wog91
2tld6xph0
share|improve this question
10  
There better not be a Mathematica builtin for this. – Mama Fun Roll Feb 1 at 16:38
1  
Can we assume that the input will only contain ASCII? Or only printable ASCII + linefeeds or something? – Martin Ender Feb 1 at 19:10
    
Yes, just ASCII and newline (unless you take input as an array). – J Atkin Feb 1 at 19:22

15 Answers 15

up vote 3 down vote accepted

TeaScript, 10 bytes

xHl@C(r╢tD

Thanks to TeaScript 3's extremely concise syntax, this is really short :D

Would be 1-byte shorter if Sigma loop weren't buggy

Try it online

Explanation

      // Implicit, x = input
xH    // Transpose input
l@    // Loop
 C(r╢   // Cycle column by index
        // `╢` exits loop
t    // Transpose
D    // Join on \n
share|improve this answer
    
Impressive! (4 more) – J Atkin Feb 2 at 1:15

Pyth, 11

jC.>R~hZC.z

Try it here

jC.>R~hZC.z    ##  implicit: .z = list of input split by lines
        C.z    ##  transpose .z to get columns
  .>R~hZ       ##  shift each column by it's index
               ##  equivalent to .e.>bk
jC             ##  transpose back and join by newlines
share|improve this answer

Retina, 111 101 92 87 bytes

Byte count assumes ISO 8859-1 encoding.

(?<=((.))*)(?=(?<1>.*¶)*.*(?<=(?=(?<-2>.)*(.))(?<-1>.+¶)*.*(.(?<=^(?<-1>¶?.+)*))*)).
$3

Woo, solved it in a single regex substitution. :) (Chances are, there's a shorter solution by using several, but where's the fun in that...)

Try it online!

Explanation

This requires some basic knowledge of balancing groups. In short, .NET's regex flavour allows you to capture multiple times with a single group, pushing all captures onto a stack. That stack can also be popped from, which allows us to use it for counting things inside the regex.

(?<=((.))*)

This pushes one capture onto both groups 1 and 2 for each character in front of the match (in the current line). That is, it counts the horizontal position of the match.

The rest is in a lookahead:

(?=(?<1>.*¶)*.* [...] )

We match each line and also push it onto group 1, such that group 1 is now the sum of the horizontal and vertical position (where the latter is counted from the bottom). This essentially labels the diagonals of the grid with increasing values starting from the bottom left corner. That .* then just moves the engine's cursor to the end of the string.

We now switch into a lookbehind, which is matched from right to left in .NET:

(?<= [...] (.(?<=^(?<-1>¶?.+)*))*)

This will repeatedly pop exactly H captures from group 1 (where H is the height of the input). The purpose of that is to take the group modulo H. Afterwards, group 1 contains the row (counted from the bottom) from which to pick the new character in the current column.

(?=(?<-2>.)*(.))(?<-1>.+¶)*.*

Another lookbehind, again starting from the right. (?<-1>.+¶)*.+ now uses group 1 to find the row from which to pick the new character and then the lookahead finds the correct column using group 2.

The desired character is captured into group 3 and written back by the substitution.

share|improve this answer
    
Ah, reading Retina's source was nice and clear :) $+ looks useful... especially if you only want to do one substitution :^) – FryAmTheEggman Feb 1 at 18:00
    
@FryAmTheEggman $+ is actually pretty useless... it's description on MSDN sounds a lot more useful than it is because it implies that (a)|(b) --> $+$+ would double all as and bs but instead it removes all as, because it just refers to the syntactically last group. That means it's just a way to avoid counting all groups if you're too lazy (like I was). For golfing it only saves bytes when you have more than 9 groups, which is probably quite rare to begin with. – Martin Ender Feb 1 at 18:27
    
That is unfortunate... Perhaps retina could have a new replacement group type that would return the last non-empty match group? Anyway, thanks for the explanation! :) – FryAmTheEggman Feb 1 at 18:55
    
@FryAmTheEggman It will (it's one of the things I had in mind when rewriting Regex.Replace for Retina, but I didn't get around to implementing it yet). – Martin Ender Feb 1 at 19:05

CJam, 13 bytes

qN/zee::m>zN*

Test it here.

Explanation

q    e# Read all input.
N/   e# Split into lines.
z    e# Transpose to get an array of columns.
ee   e# Enumerate, pairing each column with its index.
::m> e# Map: fold: rotate (cyclically shifting each column by its index).
z    e# Transpose again.
N*   e# Join with linefeeds.
share|improve this answer
2  
You can almost pronounce that source code. – mınxomaτ Feb 1 at 17:12

Python 3, 164 bytes

Not the best answer by a long shot, but the first in Python...

s=list(zip(*open(0).readlines()))[:-1]
r=[[s[i][(j-i)%len(s[i])] for j in range(len(s[i]))] for i in range(len(s))]
print('\n'.join([''.join(l) for l in zip(*r)]))
share|improve this answer
    
You can save a handful of bytes by taking out the space which follows a ) or ] in most cases, for example ''.join(l)for l in.... is perfectly valid – wnnmaw Feb 1 at 20:22

MATLAB, 92 36 bytes

s=bsxfun(@circshift,s,0:size(s,2)-1)

Assuming that the input string s is already in the form of a 2D char array/ matrix, e.g.

s = ['abcdefg';'.......'];
s = ['\\\\.....././';'...../.......';'........././.';'..../.^\\....'];

Explanation: iterate through the columns of the matrix. For each column perform a circular shift of its elements by the number of characters that equals the column index (-1 because of MATLAB indexing).

share|improve this answer

JavaScript, 92 89 bytes

3 bytes off thanks @Neil.

s=>(z=s.split`
`).map((m,i)=>m.replace(/./g,(n,j)=>z[((l=z.length)*j+i-j)%l][j])).join`
`

f=s=>
    (z=s.split`\n`).map((m,i)=>
        m.replace(/./g,(n,j)=>
            z[((l=z.length)*j+i-j)%l][j]
        )
    ).join`\n`

Input.value = `abcdefghij
..........
..........`
textarea{display:block;width:250px;height:75px;}
<textarea id='Input'></textarea>
<button id='Run' onClick='Output.value=f(Input.value);'>Run</button>
<textarea id='Output'></textarea>

share|improve this answer
    
You can save 3 bytes using replace: m.replace(/./g,(n,j)=>z[((l=z.length)*j+i-j)%l][j]). – Neil Feb 1 at 19:07
1  
Indeed, the [...m].map( all the way to and including the first .join. – Neil Feb 1 at 19:15

Python 2, 115 bytes

lambda s:'\n'.join("".join(s)for s in zip(*[k[-i%len(k):]+k[:-i%len(k)]for i,k in enumerate(zip(*s.split('\n')))]))

Thanks to the wonder of zip managed to get this down to one line. See it in action here.

share|improve this answer

MATL, 18 21 bytes

Zy2):"G@Z)@qYS]N$h

Input is of the form

['Hello, world!'; 'I am another '; 'string to be '; 'twisted!']

Try it online!

How it works:

Zy       % implicitly take input: 2D char array. Get its size
2)       % second element from size vector: number of columns, say n
:        % create vector [1,2,...,n]
"        % for each element k in that vector
  G      %   push input
  @      %   push k
  Z)     %   k-th column from input
  @qYS   %   circularly shift k-1 positions
]        % end for loop
N$h      % concatenate all stack contents horizontally
         % implicitly display
share|improve this answer

Brachylog, 96 bytes

$\:0{h_.|[M:I]hh:I{bh0,?h.|[C:I]h$)D,I-1=:Dr:2&.}C,I+1=J,Mb:J:1&:[C]rc.}$\{hA,[A]:"~s
"w,?b:3&;}

This expects a list of character codes strings as input and no output, e.g. brachylog_main([`aaaa`,`bbbb`,`cccc`],_).

That's one ridiculously long answer, and there's probably a much shorter way to do it.

Explanation

§ Main Predicate

$\:0{}$\{}                            § Create a list containing the transposed input and 0
                                      § Call sub-predicate 1 with this list as input
                                      § Transpose its output and pass it as input to
                                      § sub-predicate 3


§ Sub-predicate 1

h_.                                   § If the matrix is empty, output is empty list
   |                                  § Else
    [M:I]hh:I{}C,                     § Input is [M,I], call sub-predicate 2 with the first
                                      § line of M and I as input. Its output is C.
                 I+1=J,Mb:J:1&        § Call sub-predicate 1 with M minus the first line
                                      § and I+1 as input
                              :[C]rc. § Its output is appended after C, which is then
                                      § unified with the output of sub-predicate 1.


§ Sub-predicate 2

bh0,?h.                               § If the second element of the input list is 0,
                                      § output is the first element of the input
       |                              § Else
        [C:I]                         § Input is [C,I]
             h$)D,                    § Perform a circular permutation of C from left to
                                      § right (e.g. [a,b,c] => [c,a,b]) and unify it with D
                  I-1=:Dr:2&.         § Call sub-predicate 2 with D and I-1 as input, unify
                                      § its output with sub-predicate 2's output


§ Sub-predicate 3

hA,[A]:"~s\n"w,                       § Write the first line of the input as a char codes
                                      § string followed by a new line

               ?b:3&;                 § Call sub-predicate 3 with input minus the first
                                      § line. If it fails (empty input), terminate
share|improve this answer

F#, 105 bytes

My first stab at it (only a \n character is required):

let m x y=(x%y+y)%y
let f(a:string[])=Array.mapi(fun i x->String.mapi(fun j _->a.[m(i-j)a.Length].[j])x)a

Usage:

f [| @"\\\\\\\\\\\\"
     "............"
     "............"
     "............" |]
share|improve this answer
    
I don't think I have seen F# before on PPCG. – J Atkin Feb 2 at 14:07

Japt, 29 bytes

Uy £XsV=(Y*Xl -Y %Xl)+X¯V}R y

Test it online!

How it works

Uy        // Transpose rows and columns in the input string.
£     }R  // Map each item X and index Y in the result, split at newlines, to:
Y*Xl -Y   //  Take Y times X.length and subtract Y.
%Xl)      //  Modulate the result by X.length.
XsV=      //  Set V to the result of this, and slice off the first V chars of X.
+X¯V      //  Concatenate this with the first V chars of X.
y         // Transpose the result again.
          // Implicit: output last expression
share|improve this answer

Haskell, 81 bytes

let t=transpose in t.snd.mapAccumR(\c l -> 1+c,take(length l)(drop c$cycle l))0.t

reimplementation of the CJam example, though the reverse, map and enumerate is part of the mapAccumR, the snd removes the accumulator since we don't need it anymore, the reversal is just a side effect of the right fold.

share|improve this answer

Haskell, 65 bytes

g l@("":_)=l;g l|t<-tail<$>l=zipWith(:)(head<$>l)$g$last t:init t

Usage example: g ["1111","2222","3333"] -> ["1321","2132","3213"].

share|improve this answer

JavaScript (ES6), 73 bytes

t=>t.replace(/./g,(_,i)=>t[(i+s*l-i%l*l)%s],l=t.search`
`+1,s=t.length+1)

Explanation

t=>
  t.replace(/./g,(_,i)=> // replace each character at index i
    t[                   // get the character at index:
      (i                 // start at i
        +s*l             // add s*l to ensure the result is always positive for %s
        -i%l*l           // move the index upwards the num of chars from start of the line
      )%s                // shift the index into the the range of s
    ],
    l=t.search`
`+1,                     // l = line length
    s=t.length+1         // s = input grid length (+1 for the missing newline at the end)
  )

Test

var solution = t=>t.replace(/./g,(_,i)=>t[(i+s*l-i%l*l)%s],l=t.search`
`+1,s=t.length+1)
<textarea id="input" rows="5" cols="40">\\\\.....././
...../.......
........././.
..../.^\\....</textarea><br>
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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