Let's continue the fibonacci based challenges stream, here's the next one:
Task
Draw a Fibonacci spiral ascii-art of n segments where starting from the first term:
- each nth segment has a length of nth Fibonacci term.
- each segment is joined to the end of the previous, rotated by 90 degrees taking the end of previous segment as center of rotation.
- you can choose any printable ascii character chars to draw the spiral with, although the background must be spaces.
- You can draw the spiral in any orientation and turning clockwise or counterclockwise
- Leading/trailing whitespace is allowed within reason
Example
Let's explain it with the help of a visual example:
Beginning of segments are highlighted with an arrow character (> < ^ v) to indicate the direction.
End of segments highlighted with o
to indicate the pivot for the rotation of next segment.
Taking the first 9 terms [0,1,1,2,3,5,8,13,21] (the first term(0) doesn't draw anything) we draw clockwise.
o###################<o
#
#
#
#
#
#
#
o#<o #
v ^ #
# oo #
# #
# ^
o>######o
As you can see we start with one character(a segment of length 1) then add one to the right, then add two by rotating 90 degrees, then 3, then 5 .. and so on.
You can choose 0 or 1 indexing in the Fibonacci sequence, f(0) can draw anything or a single character, just be consistent on this.
Some more examples
n==1 (0-indexed) or n==0 (1-indexed)-> [1]
*
n==2 -> [1,1]
2 1 or 21
1 or 2 or 12
here we used '1' for the first segment and '2' for the second
n==3 ->[1,1,2]
1 or 12 or...
233 3
3
Rules
- This is code-golf: all the usual golfing rules apply.
- Either a function or a full program is fine.
- Input/output can be given by any convenient method.
-
\$\begingroup\$ Related \$\endgroup\$AZTECCO– AZTECCO2022年03月05日 21:30:49 +00:00Commented Mar 5, 2022 at 21:30
-
1\$\begingroup\$ A few test cases would be needed, to know exactly where each segment ends or how it is joined to the previous one (first turn, then join it seems) \$\endgroup\$Luis Mendo– Luis Mendo2022年03月05日 22:38:09 +00:00Commented Mar 5, 2022 at 22:38
-
\$\begingroup\$ Also, is it ok if the program fails for large inputs (or not so large) due to floating point precision errors? \$\endgroup\$Luis Mendo– Luis Mendo2022年03月05日 22:47:09 +00:00Commented Mar 5, 2022 at 22:47
-
1\$\begingroup\$ Please also clarify if the output can be rotated so that the last segment is always in the same direction \$\endgroup\$Luis Mendo– Luis Mendo2022年03月05日 22:52:01 +00:00Commented Mar 5, 2022 at 22:52
-
1\$\begingroup\$ Thanks for clarifying. I hope it gets reopened soon (only one vote left). My question about floating-point precision was because of Binet's formula. But I agree that it seems better not to allow floating-point errors, as the challenge can be done using only integers \$\endgroup\$Luis Mendo– Luis Mendo2022年03月06日 16:32:35 +00:00Commented Mar 6, 2022 at 16:32
8 Answers 8
MATL, 25 bytes
TF0i:"P!1bYs:Q1&(3MPw]Zc&
Explanation
TF % Push [1, 0]. This array will contain the two most recent Fibonacci
% numbers in each iteration k: [f(k), f(k-1)]
0 % Push 0. This initiallizes the matrix M that will be used as output
i:" % Input n. Do the following n times
P! % Flip vertically, transpose. This rotates tmatrix M by 90 degrees
1 % Push 1 (*)
b % Bubble up: moves the array [f(k), f(k-1)] to the top of the stack
Ys % Cumulative sum: gives [f(k), f(k+1)]
: % Range (uses first entry): [1, 2, ..., f(k)]
Q % Add 1, element-wise: gives [2, 3, ..., f(k)+1] (**)
1 % Push 1 (***)
&( % Write 1 (*) in M at the rows given by (**) and column 1 (***).
% This extends M with the new segment of the spiral, padding with 0
3M % Push [f(n), f(n+1)] again
P % Flip: gives [f(n+1), f(n)], ready for the next iteration
w % Swap: moves the extended M to the top of the stack
] % End
Zc % Convert values 1 in M into char '#', and 0 to space
& % Set alternative input/output spec for the next function, which is
% implicit display. This causes the function to use only one input,
% which means that only the top of the stack is displayed
Python 3.8 (pre-release), 99 bytes
f=lambda n:' #'[2*n:]or[k:='#'+''.join(l[1:])for l in zip(*f(n-1)[::-1])]+(k:=len(k)-1)*['#'+' '*k]
05AB1E, 9 bytes
LÅf0ŽPjSΛ
0-based and the spiral goes counterclockwise starting towards the left, similar as the example in the challenge.
Input \$n=0\$ will always draw a single character instead of an empty output.
Draws with character 0
, but this could alternatively be any other digit, the lowercase alphabet, the input digits, the digits of the 0-based \$n^{th}\$ Fibonacci number, etc. by replacing the 0
.
The start and direction of the spiral can also be changed by replacing ŽPjS
with Ž8O
for right counterclockwise; ŽG~S
for down counterclockwise; ŽNāS
for left clockwise; Ƶ‘0š
for up clockwise; Ž9¦S
for right clockwise; or ŽICS
for down clockwise (up counterclockwise is the only one that's a byte longer with Ž2„0š
).
Explanation:
L # Push a list in the range [1, (implicit) input-integer]
Åf # Get the (0-based) n'th Fibonacci number for each of these values
0 # Push character "0"
ŽPj # Push compressed integer 6420
S # Pop and convert it to a list of digits: [6,4,2,0]
Λ # Use the Canvas builtin with these three arguments
# (which is output immediately afterwards implicitly)
See this 05AB1E tip of mine (section How to compress large integers?) to understand why ŽPj
is 6420
.
As for some additional information about the Canvas builtin Λ
:
It takes 3 arguments to draw an ASCII shape:
- Length of the lines we want to draw
- Character/string to draw
- The direction to draw in, where each digit represents a certain direction:
7 0 1
↖ ↑ ↗
6 ← X → 2
↙ ↓ ↘
5 4 3
LÅf0Ž8OS
creates the following Canvas arguments:
- Length: the first input amount of 1-based Fibonacci numbers
- Character:
"0"
- Directions:
[6,4,2,0]
, which translates to \$[←,↓,→,↑]\$
Step 1: Draw 1 characters ("0"
) in direction 6/←
:
0
Step 2: Draw 1-1 characters (""
) in direction 4/↓
:
0
Step 3: Draw 2-1 characters ("0"
) in direction 2/→
:
00
Step 4: Draw 3-1 characters ("00"
) in direction 0/↑
:
0
0
00
Step 5: Draw 5-1 characters ("000"
) in direction 6/←
:
00000
0
00
Step 6: Draw 8-1 characters ("0000000"
) in direction 4/↓
:
00000
0 0
0 00
0
0
0
0
0
etc.
See this 05AB1E tip of mine for an in-depth explanation of the Canvas builtin.
-
\$\begingroup\$ -1 and fixed \$\endgroup\$emanresu A– emanresu A2022年06月02日 00:03:39 +00:00Commented Jun 2, 2022 at 0:03
Jelly, 22*? 27 bytes
ÆḞ€R¬W1ドル¦t6;ɗ0ドル¦Ṛz6ʋ/ZṚ8ドル¡Y
A full program that accepts an integer and prints a spiral using 1
s.
How?
ÆḞ€R¬W1ドル¦t6;ɗ0ドル¦Ṛz6ʋ/ZṚ8ドル¡Y - Main Link: integer, N
ÆḞ€ - first N Fibbonacci numbers
R - range -> [[1],[1],[1,2],[1,2,3],[1,2,3,4,5],...]
¬ - logical NOT -> [[0],[0],[0,0],[0,0,0],[0,0,0,0,0],...]
W1ドル¦ - wrap the first one
ʋ/ - reduce by - f(Current, Next):
ɗ0ドル¦ - apply to the final entry of Current:
t6; - trim spaces and concatenate Next
Ṛ - reverse
z6 - transpose with spaces
8ドル¡ - repeat N times:
Z - transpose
Ṛ - reverse
Y - join with newline characters
- implicit print
* Awaiting clarification on whether "output can be rotated so that the last segment is always in the same direction" - 22:
ÆḞ€R¬W1ドル¦t6;ɗ0ドル¦Ṛz6ʋ/Y
-
\$\begingroup\$ This seems to use a fixed ending direction, instead of a fixed starting one as the challenge seems to require. I was considering doing the same, so I've asked for clarification \$\endgroup\$Luis Mendo– Luis Mendo2022年03月05日 22:54:24 +00:00Commented Mar 5, 2022 at 22:54
-
1\$\begingroup\$ @LuisMendo I thought our choice under "Start rotating from left ,right,up or down as your wish." didn't need to be consistent across inputs ...hmm. \$\endgroup\$Jonathan Allan– Jonathan Allan2022年03月05日 22:56:25 +00:00Commented Mar 5, 2022 at 22:56
-
1\$\begingroup\$ @LuisMendo put in a version that has a fixed starting direction for now. \$\endgroup\$Jonathan Allan– Jonathan Allan2022年03月05日 23:03:25 +00:00Commented Mar 5, 2022 at 23:03
-
1\$\begingroup\$ Updated the question and your 22Byte answer should be fine \$\endgroup\$AZTECCO– AZTECCO2022年03月06日 17:54:44 +00:00Commented Mar 6, 2022 at 17:54
Charcoal, 18 bytes
⊞υ1FN«⌈υ↶⊞υΣ...⮌υ2»1
Try it online! Link is to verbose version of code. Explanation:
⊞υ1
Start with 1
.
FN«
Repeat n
times.
⌈υ
Output the latest Fibonacci number in unary.
↶
Rotate ready for the next Fibonacci number.
⊞υΣ...⮌υ2
Calculate the next Fibonacci number.
»1
Print a final character (this is because Charcoal is actually drawing the lines a character early, so it's drawing 1, 2, 3, 5, 8...
and the second 1
is missing).
It's possible to draw the lines according to the specification by rotating for the last character of the line, but in this case the spiral has to be drawn clockwise instead:
⊞υ1FN«¶⌈υ¶↷⊞υΣ✂υ±2
Try it online! Link is to verbose version of code. Explanation:
⊞υ1
Start with 1
.
FN«
Repeat n
times.
¶⌈υ¶
Output the latest Fibonacci number in unary, but positioned rotated from the end of the previous one.
↷
Rotate ready for the next Fibonacci number.
⊞υΣ✂υ±2
Calculate the next Fibonacci number, but repeating the initial 1
the first time.
-
\$\begingroup\$ It seems to skip the first term or the second, they are both 1 \$\endgroup\$AZTECCO– AZTECCO2022年03月06日 17:16:36 +00:00Commented Mar 6, 2022 at 17:16
-
\$\begingroup\$ @AZTECCO Actually according to Charcoal's drawing approach I was skipping the very last character, but of course your example didn't show that so I hadn't realised my mistake. I've added it in and also come up with an alternative approach which follows your method more closely (except it now has to do it in a different direction). \$\endgroup\$Neil– Neil2022年03月06日 17:50:42 +00:00Commented Mar 6, 2022 at 17:50
-
\$\begingroup\$ Neil I'm sorry for the discomfort, yes adding a character at the end would be fine. Your answer works perfectly now! \$\endgroup\$AZTECCO– AZTECCO2022年03月06日 18:04:04 +00:00Commented Mar 6, 2022 at 18:04
Python3, 326 bytes:
R=range
f=lambda n,a=1,b=1:[b]+f(n-1,b,a+b)if n else[]
def g(b,e,x,y,q,w):
if e:x+=q;y+=w;b[x][y]=1;return g(b,e-1,x,y,q,w)
return x,y
def d(b,r,x,y,c=1):
if r:d(b,r,*g(b,r.pop(),x,y,0+c%2*[1,-1][c%4==1],0+(c%2==0)*[-1,1][c%4==2]),c+1)
def F(n):
r=f(n);b=[[0 for _ in R(r[-2]+1)]for _ in R(r[-1])];d(b,r,len(b),0);return b
-
\$\begingroup\$ It seems it doesn't work properly for the first few terms \$\endgroup\$AZTECCO– AZTECCO2022年03月06日 17:19:18 +00:00Commented Mar 6, 2022 at 17:19
-
\$\begingroup\$ @AZTECCO Can you clarify, the spiral generated for terms 1 to 3 matches your posted output. \$\endgroup\$Ajax1234– Ajax12342022年03月06日 17:30:56 +00:00Commented Mar 6, 2022 at 17:30
-
\$\begingroup\$ Ajax your answer prints nothing for 0 and may be fine, but still prints nothing for 1 and that would be fine if you 1-index in [0,1,1,...], for 2 seems to print a [1,2] spiral skipping one term, and seems to start from 2nd term for any input(e.g. [1,2,3,5..]. Anyway I updated the question and hopefully it's going to be reopened, check it out and if you have any doubt don't hesitate to ask clarifications \$\endgroup\$AZTECCO– AZTECCO2022年03月06日 17:41:45 +00:00Commented Mar 6, 2022 at 17:41