| Bytes | Lang | Time | Link |
|---|---|---|---|
| 114 | Ruby | 240529T232819Z | Level Ri |
| 013 | Vyxal | 240530T205336Z | emanresu |
| 012 | 05AB1E | 240528T091622Z | Kevin Cr |
| 078 | Pyth | 160909T212058Z | Steven H |
| 283 | Java 7 | 160909T204122Z | QBrute |
| 144 | Ruby | 160907T000930Z | Value In |
| 198 | Javascript | 160906T225448Z | Hedi |
| 189 | Python 2 | 160906T225718Z | Joshua d |
| 126 | x86 IA32 machine code | 160907T180733Z | anatolyg |
Ruby, 114 bytes
->s{t="#{" "*w=2*v=s.size}
"*u=w-1
v.times{|i|9.times{|j|t[[u*v,~v,u][j/3]-[1,~w,w][j%3]*~(j%-4/3*2)*i]=s[~i]}}
t}
Ruby, 120 118 bytes
->s{w=2*v=s.size
t=(" "*w+$/)*w
v.times{|i|9.times{|j|t[[v*w+~v,~v*3,w-2][j/3]-[1,~w,w][j%3]*~(j%-4/3*2)*i]=s[~i]}}
t}
An anonymous function that takes the input string as an argument s and returns a string t.
Explanation
We start by setting up a field of w=2*s.size rows each of w spaces terminated by a newline.
We then substitute, character by character, nine copies of the input string, starting at the endpoint. There are 3 endpoints each with text in 3 different directions x,y,z. This is easier to handle than starting at the beginning, since there are 4 possible startpoints each with text either in 2 or 3 directions. Variable i denotes the distance from the endpoint and s[~i] represents the character in the string, indexed in the reverse direction.
The expressions for the three endpoints are [v*w+~v,~v*3,w-2] (note that ~v*3 is negative - Ruby counts negative numbers backwards from the end of the string starting at -1). The three forward directions (for text on the outside edge of the figure) are [1,~w,w]. w is the diagonal z direction (because each line is newline terminated it has 1+w characters, so w is 1 less than this.) 1 is the x direction and ~w = -(1+w) is the y direction.
Text for edges inside the figure (those that run from the top front right corner) run in the opposite direction. These edges are written when j/3==j%3 or equivalently j%4=0. This is managed by the expression (j%-4/3*2) which evaluates to either 0 or -2. The ~ outside the bracket converts this to -1 or 1. After applying this sign correction we multiply by i to find the right point in the output string.
Commented code
->s{ #take an input s
w=2*v=s.size #v is the input length. w is double this
t=(" "*w+$/)*w #set up a string of w rows of w spaces, newline terminated
v.times{|i| #iterate through characters in s
9.times{|j| #iterate though edges
t[[v*w+~v,~v*3,w-2][j/3]- #pick an end point based on j/3
[1,~w,w][j%3]* #subtract direction based on j%3 mutiplied by
~(j%-4/3*2)* #+1 or -1 depending on whether j/3==j%3
i]= #multipy by i
s[~i] #assign character from s to this cell
}
}
t} #return string t
Vyxal, 13 bytes
L?∞Ṫ»∨¹0²H»ø∧
Try it Online! Indirectly -1 byte thanks to Kevin Cruijssen, I forgot how canvas operator overloading works.
ø∧ # Draw on the canvas with
L # Line length: length of input
?∞Ṫ # String: Input, palindromised with last character removed
»∨¹0²H» # Directions: digits of 24560125406
.>2>.
⇗ ⇙v
1 5 4
⇗ ⇙ v
.<6<. .
^ v ⇙
0 4 5
^ v⇙
.<6<.
05AB1E, 35 12 bytes
gIû¨•5ÏlÐθ•Λ
-23 bytes by porting emanresuA's Vyxal answer, so make sure to upvote that answer as well!
Original 35 bytes answer:
g¸ÞI¸Þð13ÅÉǝ•6´XdªÅ~ßмñD>γ•₃в)øvy`Λ
Explanation:
g # Push the length of the (implicit) input-string
I # Push the input-string
û # Palindromize it
¨ # And then remove the last character
•5ÏlÐθ• # Push compressed integer 24560125406
Λ # Use the Canvas builtin with those three arguments
# (which is output immediately as result)
g # Push the length of the (implicit) input-string
¸Þ # Wrap it into a list, and repeat it infinitely
I # Push the input-string
¸Þ # Repeat it infinitely as well
ð # Push a space character " "
13ÅÉ # Push a list of odd integers <= 13: [1,3,5,7,9,11,13]
ǝ # Insert spaces at those 0-based indices into the infinite list
•6´XdªÅ~ßмñD>γ• # Push compressed integer 506660546965149280261611581961
₃в # Convert it to base-95 as list:
# [1,8,84,80,2,80,5,82,0,82,5,85,2,85,0,86]
) # Wrap all three lists on the stack into a list
ø # Zip/transpose; swapping rows/columns,
# which also discards the infinite portions
vy # Loop over each triplet:
` # Pop and push the three values in the triplet to the stack
Λ # Use the Canvas builtin with these three values as arguments
# (which is output immediately every iteration)
See this 05AB1E tip of mine (sections How to compress large integers? and How to compress integer lists?) to understand why •6´XdªÅ~ßмñD>γ• is 506660546965149280261611581961 and •6´XdªÅ~ßмñD>γ•₃в is [1,8,84,80,2,80,5,82,0,82,5,85,2,85,0,86].
Additional explanation of 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
And there are certain special 'directions': +×8.
g16иI16иð13ÅÉǝ•6´XdªÅ~ßмñD>γ•₃в)ø with input Hello, world! creates the following list of Canvas arguments:
[[13,"Hello, world!",1],
[13," ",8],
[13,"Hello, world!",84],
[13," ",80],
[13,"Hello, world!",2],
[13," ",80],
[13,"Hello, world!",5],
[13," ",82],
[13,"Hello, world!",0],
[13," ",82],
[13,"Hello, world!",5],
[13," ",85],
[13,"Hello, world!",2],
[13," ",85],
[13,"Hello, world!",0],
[13,"Hello, world!",86]]
- The first
13,"Hello, world!",1will draw (all)13characters of string"Hello, world!"in direction1/↗: try just this first step online; - The second
13," ",8will with special direction8reset back to the origin (the13and" "are ignored): try just the first two steps online; - The third
13,"Hello, world!",84will first reset back to the origin with direction8(step 2 is kinda a no-op to save a byte on the13ÅÉ), and then again draw (all)13characters of string"Hello, world!"in direction4/↓: try just the first three steps online; - The fourth
13," ",80will first reset back to the origin with direction8again, and then draw 13 space characters in direction0/↑: try just the first four steps online; - The fifth
13,"Hello, world!",2will then continuing from that position to draw (all)13characters of string"Hello, world!"in direction2/→: try just the first five steps online; - etc. etc.
- The sixteenth
13,"Hello, world!",86will again reset, and then draw in direction6/←, which also fixes the space at the origin position to the first letter of the input: try all sixteen steps online (feel free to remove trailing lines to see the other untreated intermediate steps).
See this 05AB1E tip of mine to learn more about the Canvas builtin.
Pyth, 78 bytes
AtBtlQJ_SH
+*dGQVJs[*Nd@Q-GN*dHK@QN*d-HNK;
++_Q*dHhQVJs[@QN*dH@Q-GN*dtN@Q-GN;
With trailing newline. Inspired by Joshua de Haan's Python 3 answer.
Java 7, 283 bytes
void a(String s){int h=s.length(),n=h*2-1,t=n-h,u=n-1;char[][]c=new char[n][n];for(int i=0;i<h;i++){c[0][t+i]=c[i][t-i]=c[t][t-i]=c[t+i][t]=c[t+i][u-i]=c[t-i][t+i]=c[t-i][u]=c[u][i]=c[u-i][0]=s.charAt(i);}for(int y=0;y<n;y++){System.out.println(new String(c[y]).replace('\0',' '));}}
Ungolfed:
void a(String s) {
int length=s.length(),
n=length*2-1,
mid=n-length,
doubleMid=n-1;
char[][]c=new char[n][n];
for(int i=0;i<length;i++) {
c[0][mid+i]=
c[i][mid-i]=
c[mid][mid-i]=
c[mid+i][mid]=
c[mid+i][doubleMid-i]=
c[mid-i][mid+i]=
c[mid-i][doubleMid]=
c[doubleMid][i]=
c[doubleMid-i][0]=s.charAt(i);
}
for(int y=0;y<n;y++){
System.out.println(new String(c[y]).replace('\0',' '));
}
}
Ruby, 148 144 bytes
+1 byte from the n flag. Shows newlines instead of semicolons for readability (same functionality).
S=" "
X=S*s=$_.size-2
puts X+S+I=$_,(r=1..s).map{|i|c=I[~i];S*(s-i+1)+I[i]+X+c+S*~-i+c},I.reverse+X+I[0],r.map{|i|c=I[i];I[~i]+X+c+S*(s-i)+c},I
Run like so. Input is a line of STDIN, with no trailing newline, so it likely needs to be piped from file.
ruby -ne 'S=" ";X=S*s=$_.size-2;puts X+S+I=$_,(r=1..s).map{|i|c=I[~i];S*(s-i+1)+I[i]+X+c+S*~-i+c},I.reverse+X+I[0],r.map{|i|c=I[i];I[~i]+X+c+S*(s-i)+c},I'
Javascript, 225 198 bytes
Saved 27 bytes thanks to @Neil
f=(s,l=s.length-2,d=' ',r='repeat',t=d[r](l))=>[d+t+s,...a=[...Array(l)].map((_,i)=>d[r](l-i)+s[i+1]+t+(p=s[l-i])+d[r](i)+p),[...s].reverse().join``+t+s[0],...a.map(v=>v.trim()).reverse(),s].join`
`
- [...] instead of .concat
- [...]+map instead of for loop
- only one statement by moving variables as function parameters
- better initialization for l and t
Original answer:
f=s=>{l=s.length,d=' ',r='repeat',a=[],t=d[r](l-2)+s;for(i=1;i++<l-1;)a.push(d[r](l-i)+s[i-1]+d[r](l-2)+(p=s[l-i])+d[r](i-2)+p);console.log(d+[t].concat(a,[...t].reverse().join``+s[0],a.map(v=>v.trim()).reverse(),s).join`
`)}
Python 2, 228 223 221 203 199 195 189
t=input()
x=" "
l=len(t)-1
q=l-1
f=range(q,0,-1)
print x*l+t
for i in f:print x*i+t[l-i]+x*q+t[i]+x*(q-i)+t[i]
print t[::-1]+x*q+t[0]
for i in f:print t[i]+x*q+t[l-i]+x*(i-1)+t[l-i]
print t
Python 3, 192 188 182
t=input()
x=" "
l=len(t)-1
q=l-1
p=print
f=range(q,0,-1)
p(x*l+t)
for i in f:p(x*i+t[l-i]+x*q+t[i]+x*(q-i)+t[i])
p(t[::-1]+x*q+t[0])
for i in f:p(t[i]+x*q+t[l-i]+x*(i-1)+t[l-i])
p(t)
x86 (IA-32) machine code, 126 bytes
Hexdump:
60 8b f9 57 33 c0 f2 ae 5e 2b fe 4f 87 fa 8d 1c
12 8b c3 48 f6 e3 c6 04 07 00 48 c6 04 07 20 75
f9 8b ea 4d 53 8d 04 2a 50 53 8b c5 f6 e3 8d 44
68 01 50 53 2b c2 8b c8 50 4b 53 55 53 03 c5 50
f7 d3 53 50 53 95 f6 e2 6b c0 04 50 43 53 51 6a
01 4a 52 6a 01 50 6a ff 51 b0 0a 6a 0b 8b dc 59
8b 6c cb fc 88 04 2f 03 2c cb 89 6c cb fc 83 f9
0a 75 01 ac e2 ea 4a 79 e0 83 c4 58 61 c3
This is a bit long, so to explain it I'll give C code first:
void doit(const char* s, char out[])
{
int n = strlen(s);
int w = 2 * n;
int h = w - 1;
int m = n - 1;
memset(out, ' ', h * w);
out[h * w] = 0;
int offset1 = n + m;
int offset2 = w * m + 2 * m + 1; // 2 * n * n - 1
int offset3 = offset2 - n; // 2 * n * n - n - 1
int offset4 = 4 * n * m; // 4 * n * n - 4 * n
int offsets[] = {
offset3, -1,
offset4, 1,
m, 1,
offset3, 1 - w,
offset4, -w,
offset2 - 1, -w,
offset2 - 1, w - 1,
m, w - 1,
offset3, w,
offset2, w,
offset1, w,
};
do
{
char c = *s++;
for (int i = 0; i < 11; ++i)
{
if (i == 9)
c = '\n';
int offset = offsets[i * 2];
assert(offset > 0 && offset < w * h);
out[offset] = c;
offsets[i * 2] += offsets[i * 2 + 1];
}
} while (--n);
}
Here n is the length of the input string.
The dimensions of the output area are 2n (width) by 2n-1 (height). First, it fills everything with spaces (and adds a terminating null byte). Then, it travels along 11 straight lines in the output area, and fills them with text:
- 2 lines are filled with end-of-line bytes (=10)
- 9 lines are filled with the consecutive bytes of the input string
Each line is represented by two numbers, a start offset and a stride. I stuffed them both into the array offsets, to make access "easy".
The interesting part is filling the array. There is little importance for the order of the entries in the array; I tried to rearrange them to minimize the number of register conflicts. In addition, quadratic formulas have some freedom in choosing the way of calculation; I tried to minimize the number of subtractions (because additions can be implemented by the flexible LEA instruction).
Assembly source:
pushad;
; // Calculate the length of the input string
mov edi, ecx;
push edi;
xor eax, eax;
repne scasb;
pop esi; // esi = input string
sub edi, esi;
dec edi;
; // Calculate the size of the output area
xchg edi, edx; // edx = n
// edi = output string
lea ebx, [edx + edx]; // ebx = w
mov eax, ebx;
dec eax; // eax = h
mul bl; // eax = w * h
; // Fill the output string with spaces and zero terminate it
mov byte ptr [edi + eax], 0;
myfill:
dec eax;
mov byte ptr [edi + eax], ' ';
jnz myfill;
mov ebp, edx;
dec ebp; // ebp = m
; // Fill the array of offsets
push ebx; // w
lea eax, [edx + ebp];
push eax; // offset1
push ebx; // w
mov eax, ebp;
mul bl;
lea eax, [eax + 2 * ebp + 1];
push eax; // offset2
push ebx; // w
sub eax, edx;
mov ecx, eax; // ecx = offset3
push eax; // offset3
dec ebx;
push ebx; // w - 1
push ebp; // m
push ebx; // w - 1
add eax, ebp;
push eax; // offset2 - 1
not ebx;
push ebx; // -w
push eax; // offset2 - 1
push ebx; // -w
xchg eax, ebp; // eax = m
mul dl;
imul eax, eax, 4;
push eax; // offset4
inc ebx;
push ebx; // 1 - w
push ecx; // offset3
push 1;
dec edx; // edx = n - 1
push edx;
push 1;
push eax;
push -1;
push ecx;
; // Use the array of offsets to write stuff to output
myout:
mov al, '\n';
push 11;
mov ebx, esp;
pop ecx;
myloop:
mov ebp, [ebx + ecx * 8 - 4];
mov [edi + ebp], al;
add ebp, [ebx + ecx * 8];
mov [ebx + ecx * 8 - 4], ebp;
cmp ecx, 10;
jne skip_read;
lodsb;
skip_read:
loop myloop;
dec edx;
jns myout;
add esp, 11 * 8;
popad;
ret;
I used byte multiplications here, limiting the length of the input string to 127. This avoids clobbering the register edx - the product is calculated in ax instead.
A minor glitch: when filling the array, the length of the string gets decreased by 1. So I adjusted the loop exit condition:
jns myout
It counts down to -1.