Write a Rectangular Program that Outputs the Number of Times it was Rotated
APL (1x3 = 3)
5!3
This solution uses the extra rule that any output that is correct mod 4 works.
In APL, x!y
is the number of way to choose x
elements from y
, commonly known as binom(y,x)
or choose(y,x)
. Let's check that each rotation gives the right answer.
0 rotations
5!3
There's no way to choose 5 elements from 3, so we get 0, which is automatically printed.
1 CCW rotation
3
!
5
APL happily evaluates each line, getting the number 3
, the operator !
, and then the number 5
, printing only the last of these (5
), which is 1 mod 4.
2 CCW rotations
3!5
This is binom(5,3)
, which is (5*4*3*2*1)/(3*2*1)/(2*1) = 10
, which is 2 mod 4.
3 CCW rotations
5
!
3
As before, only the last-evaluated value of 3
is printer.
I don't actually know APL, so please tell me if I got any of the explanation wrong. I found it by trial and error as the first language on this site that:
- Automatically prints the result of an expression
- Given multiple lines of expressions, only outputs the last one
- Has no issue with an operator standing alone on a line
- Takes operators infix
- Has a single-character arithmetic binary operator that is asymmetric (aRb != bRa), and flexible enough to return a variety of numbers.
For (5), I went down the list of APL dyadic functions. My first candidate operation was the integer division /
of C and Python 2, but APL division ÷
gives floats. Exponentiation is tempting, but fails because a
and a^b
have the same parity but are gotten by consecutive rotations (unless b=0
, but then b^a=0
). Boolean operators like <
give 0
and 1
180 degrees apart, which doesn't work. Finally, I found the binomial operator !
and tried numbers until I got some that work.
Thanks to Quincunx for his confidence that there exists a smaller solution than 2x2.
Ruby, 7×9 (63)
30;p
0||p=p
0|0;p;p
;p;p|p;
p=p ||0
;p p;
2||p =p
00;1
p
A bit longer than the other solution, but at least this solution doesn't depend on any implicit printing or rule abuse. For all four rotations, the full code is parsed and other than some short-circuiting, all of it is executed. Surprisingly, there's absolutely no symmetry in the code
This solution relies on the fact that it's still possible to call the p
function (which is used to print the numbers) even if a variable with the same name has already been defined. For example, something like p p
calls the function p
with the variable p
as argument (thus, printing the value of p
).
Explanation for some of the common expressions used in the code:
p
: As mentioned above, this is either a function call or a variable. When the variable is not defined, this calls the functionp
without arguments, which does nothing and returnsnil
.p p
: Prints the variablep
.p|x
: Whenp
is the function, this is identical tonil|x
, which returns true/false depending on the value ofx
. Ifp
is an integer, it's bitwise or. Either way, this statement has no side effect.p=p||x
: Effectively the same asp||=x
(conditional assignment) with the advantage of being syntactically valid and a no-op when reversed.
Symmetric version (9×10 = 90)
p
0 * 0
00100
0||2* p
p *0||0
00300
0 * 0
p
This is the shortest symmetric solution (C2 when ignoring the numbers to print) I could come up with.
Test script
Here's a test script to verify the code above (the #
at the line ends have been added so that the whitespace doesn't get stripped and are removed before execution):
rotate=->s{s.split($/).map{|i|i.chars.reverse}.transpose.map(&:join).join($/)}
s=<<EOD.gsub(?#,"")
30;p #
0||p=p #
0|0;p;p#
;p;p|p;#
p=p ||0#
;p p;#
2||p =p#
00;1 #
p #
EOD
puts ">>> 0°"
eval s
puts ">>> 90°"
eval rotate[s]
puts ">>> 180°"
eval rotate[rotate[s]]
puts ">>> 270°"
eval rotate[rotate[rotate[s]]]
GolfScript, 4 (2x2)
43
12
Prints 4312
which is 0
(mod 4). The rotations print 3241
(1 mod 4), 2134
(2 mod 4), and 1423
(3 mod 4).
Prompted by:
If you wish you may output other legal "mod 90°" values instead of 0 1 2 3. So 8 is fine instead of 0, and -1 is fine instead of 3, etc.
There are actually many sets of numbers for which this works. I found these with this Python program:
def f(a,b,c,d):
return int("%i%i%i%i"%(a,b,c,d))
for a in range(10):
for b in range(10):
for c in range(10):
for d in range(10):
candidate = f(a,b,c,d) % 4 == 0
candidate &= f(b,d,a,c) % 4 == 1
candidate &= f(d,c,b,a) % 4 == 2
candidate &= f(c,a,d,b) % 4 == 3
if candidate:
print("%i, %i, %i, %i"%(a,b,c,d))
Although the program outputs 0
s (which probably wouldn't work), the valid solutions are of the form
ab
cd
Where a∈{4,8}
, b∈{3,7}
, c∈{1,5,9}
, d∈{2,6}
. IE (a,b,c,d)∈{4,8}×{3,7}×{1,5,9}×{2,6}
which is 24 solutions.