Rotate an ASCII art image

Out of all of the ASCII characters, it is easy to tell that some of them form groups that are rotations of the same basic character. For example, V > ^ <. This allows the possibility to construct ASCII art that can be rotated by multiples of 90 degrees and still remain ASCII art.

The Challenge

Your goal is to golf a program that accepts ASCII art and the number of degrees to rotate it from STDIN, and prints the rotated ASCII art to STDOUT.

On the first line of input, your program will receive a number N. This number represents the width and height of the ASCII art.

You will then receive N more lines of exactly N characters each (the newline is not counted in this number). The size of the art will always be a square, although it may have padding in the form of spaces to make it a square.

You will then receive one more number on a final line: 90, 180, or 270. This represents how many degrees clockwise the picture should be rotated.

Note: The inputted image will only contain characters that can be rotated by the correct amount. If the input does not match these requirements exactly, no specific behavior is required.

As output, your program should print exactly N lines of N characters, with newlines after each line. The image should be rotated so that each character in the original has been replaced by a rotated version and has been moved to the correct place in the image.

Examples (not very beautiful ASCII art)

Input

5
<- ||
|  |V
+->+
|O
<--+
90


Output

^ +-^
| | |
| V
+-+--
O <-


(Rotations by 90 and 270 won't look very good because the characters are not squares)

Input

6
+ /\ +
| \ \|
(  \/|
\   )
I \ /
:) V $180  Output $ ^ (:
/ \ I
(   \
|/\  )
|\ \ |
+ \/ +


Required Supported Characters

For all rotations (90, 180, and 270), the program should be able to rotate:

• Spaces, +, @, X and O which never change
• V > < ^
• | - and \ / (rotated by 180 they stay the same)

For 180 degree rotation, these additional characters must be supported

• I N Z % : 0 = S ~ \$ # which stay the same
• P d, ( ), [ ], { }, M W, and 9 6
• Your first example contains the lowercase v, which is not a supported character. I assume it was meant to be an uppercase V. Also, the last line in it is not padded to be 5 chars long. Mar 19, 2012 at 17:23
• @IlmariKaronen Good catch. It's fixed now. Mar 19, 2012 at 20:35
• P d, ( ), [ ], { }, M W, and 9 6 can ever be turned 90º or 270º? Mar 20, 2012 at 22:04
• No, the art will only contain characters that are designated to be able to rotate the correct amount. The last two bullets list characters can be rotated by 180º only. Your program will not be asked to rotate these by any other amount. Mar 20, 2012 at 22:09

C, 336 chars

I'm sure there's room for improvement.

char*a="<^>V|-|-/\\/\\ppdd(())[[]]{{}}MMWW9966",*p,*q;
n,x,y,r;
z(c){
return(q=strchr(a,c))?a[(q-a&-4)+(q-a+r&3)]:c;
}
#define A(r)(r&3^3?1-r%4:0)*
f(r){
return A(r)x+A(~-r)y+(r&2)/2*~-n;
}
main(){
scanf("%d\n",&n);
p=q=malloc(n*n+1);
for(y=n;y--;q+=n)gets(q);
scanf("%d",&r);
for(r/=90;++y<n;puts(""))for(x=0;x<n;x++)putchar(z(p[f(r)+n*f(r+1)],r));
}


GolfScript, 797573 67 chars

n%(;)~90/{-1%zip{{.'V<^>P(d)[{]}M9W6/\/\|-|'4/\+{.}%n+.@?)=}%}%}*n*


Looks like my and Peter Taylor's solutions are experiencing a certain amount of convergence. Anyway, looks like I'm still a few chars ahead for now. :-) Thanks (and +1) to both Peter and copy for ideas that I've shamelessly stolen.

This code completely ignores the size given on the first line, since it's redundant information. It should even handle inputs with non-square dimensions, but it very much depends on all the input lines being padded to the same length. Trying to rotate the characters P, d, (, ), [, ], {, }, M, W, 9, or 6 by 90 or 270 degrees may produce unexpected output; all other characters that are not explicitly remapped are retained unchanged.

Ps. Here's my original 79-char solution:

n%(;)~90/:z{-1%zip}*n*z'V<^>/|-\V>^<'{:c;{{.c?~.c=@if}%}*}:s~2z='P([{M96W}])d's

• Convergence? :P I liked your trick for doing the lookup without repeating (many) characters, but it doesn't seem to be compatible with my trick for avoiding the if. Mar 19, 2012 at 23:58

javascript (181 chars)

a=prompt(f="V<^>V|-|/\\/P(d)P([{]}[}M9W6M9").split(n="\n");c=a.pop()/90;for(
b=a[0];c--;a=d.split(n))for(e=d=n;e<b*b;++e%b||(d+=n))d+=f[f.indexOf(g=a[b-e


Requires every line to be padded to the given length.

• can you give me an example of what exactly I need to put on prompt? I tried replacing lines with \n, normal copy paste and balancing spaces to the first/last lines and failed to make it work Mar 20, 2012 at 18:04
• @ajax333221 Pasting multiple lines into an alert box only works in Chrome, I just noticed for the first time. Also make sure you're not copying a final newline.
– copy
Mar 20, 2012 at 19:07

Golfscript (80 79 78 77 76 chars)

n%(;)~90/{zip{-1%{'V<^>V|-|/\/''Pd()[]{}MW96'{.4*}%4/128,+{.}%+.@?)=}%}%}*n*


NB Entering the "undefined behaviour" permitted by invalid input can produce somewhat curious output, because of placeholder characters (outside ASCII) used for certain characters whose rotation by 90 degrees is not defined. For example, ( would be mapped to code point 160, which in ISO-8859-1 and Unicode is a non-breaking space.

Canvas, 7 bytes

╶╶90┤÷↷


Try it here!

basically cheating