21
\$\begingroup\$

Last time you made a square of text, but now, can you make a cube of text?

The Challenge

Given a string, output the string in the form of a cube.

You can assume the string will always have 2 chars or more, and will only have printable ascii characters.

How to Make a Text Cube

terrible mspaint skills.png

Test Cases

Input:
Test
Output:
 Test
 e ss
 s e e
tseT T
s e e
e ss
Test
Input:
Hello, world!
Output:
 Hello, world!
 e dd
 l l l
 l r r
 o o o
 , w w
 w , ,
 o o o
 r l l
 l l l
 d e e
!dlrow ,olleH H
d e e
l l l
r l l
o o o
w , ,
, w w
o o o
l r r
l l l
e dd
Hello, world!
Input:
Hi
Output:
 Hi
iHH
Hi

Reference Implementation in Python

text = raw_input("Enter a string: ")
print " " * (len(text) - 1) + text
spaces = len(text) - 2
_spaces = spaces
for i in range(1, len(text) - 2 + 1):
 print " " * spaces + text[i] + " " * _spaces + text[(i + 1) * -1] + " " * (_spaces - spaces) + text[(i + 1) * -1]
 spaces -= 1
print text[::-1] + " " * _spaces + text[0]
spaces = _spaces - 1
for i in range(1, len(text) - 2 + 1):
 print text[(i + 1) * -1] + " " * _spaces + text[i] + " " * spaces + text[i]
 spaces -= 1
print text

Rules

  • This is , so shortest answer in bytes wins! Tiebreaker is most upvoted.
  • Standard loopholes are disallowed.
  • Trailing newline and trailing spaces are allowed.

Leaderboard

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

/* Configuration */
var QUESTION_ID = 92410; // Obtain this from the url
// It will be like https://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 48934; // This should be the user ID of the challenge author.
/* App */
var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;
function answersUrl(index) {
 return "https://api.stackexchange.com/2.2/questions/" + QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}
function commentUrl(index, answers) {
 return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;
}
function getAnswers() {
 jQuery.ajax({
 url: answersUrl(answer_page++),
 method: "get",
 dataType: "jsonp",
 crossDomain: true,
 success: function (data) {
 answers.push.apply(answers, data.items);
 answers_hash = [];
 answer_ids = [];
 data.items.forEach(function(a) {
 a.comments = [];
 var id = +a.share_link.match(/\d+/);
 answer_ids.push(id);
 answers_hash[id] = a;
 });
 if (!data.has_more) more_answers = false;
 comment_page = 1;
 getComments();
 }
 });
}
function getComments() {
 jQuery.ajax({
 url: commentUrl(comment_page++, answer_ids),
 method: "get",
 dataType: "jsonp",
 crossDomain: true,
 success: function (data) {
 data.items.forEach(function(c) {
 if (c.owner.user_id === OVERRIDE_USER)
 answers_hash[c.post_id].comments.push(c);
 });
 if (data.has_more) getComments();
 else if (more_answers) getAnswers();
 else process();
 }
 }); 
}
getAnswers();
var SCORE_REG = /<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;
var OVERRIDE_REG = /^Override\s*header:\s*/i;
function getAuthorName(a) {
 return a.owner.display_name;
}
function process() {
 var valid = [];
 
 answers.forEach(function(a) {
 var body = a.body;
 a.comments.forEach(function(c) {
 if(OVERRIDE_REG.test(c.body))
 body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
 });
 
 var match = body.match(SCORE_REG);
 if (match)
 valid.push({
 user: getAuthorName(a),
 size: +match[2],
 language: match[1],
 link: a.share_link,
 });
 
 });
 
 valid.sort(function (a, b) {
 var aB = a.size,
 bB = b.size;
 return aB - bB
 });
 var languages = {};
 var place = 1;
 var lastSize = null;
 var lastPlace = 1;
 valid.forEach(function (a) {
 if (a.size != lastSize)
 lastPlace = place;
 lastSize = a.size;
 ++place;
 
 var answer = jQuery("#answer-template").html();
 answer = answer.replace("{{PLACE}}", lastPlace + ".")
 .replace("{{NAME}}", a.user)
 .replace("{{LANGUAGE}}", a.language)
 .replace("{{SIZE}}", a.size)
 .replace("{{LINK}}", a.link);
 answer = jQuery(answer);
 jQuery("#answers").append(answer);
 var lang = a.language;
 if (/<a/.test(lang)) lang = jQuery(lang).text();
 
 languages[lang] = languages[lang] || {lang: a.language, user: a.user, size: a.size, link: a.link};
 });
 var langs = [];
 for (var lang in languages)
 if (languages.hasOwnProperty(lang))
 langs.push(languages[lang]);
 langs.sort(function (a, b) {
 if (a.lang > b.lang) return 1;
 if (a.lang < b.lang) return -1;
 return 0;
 });
 for (var i = 0; i < langs.length; ++i)
 {
 var language = jQuery("#language-template").html();
 var lang = langs[i];
 language = language.replace("{{LANGUAGE}}", lang.lang)
 .replace("{{NAME}}", lang.user)
 .replace("{{SIZE}}", lang.size)
 .replace("{{LINK}}", lang.link);
 language = jQuery(language);
 jQuery("#languages").append(language);
 }
}
body { text-align: left !important}
#answer-list {
 padding: 10px;
 width: 290px;
 float: left;
}
#language-list {
 padding: 10px;
 width: 290px;
 float: left;
}
table thead {
 font-weight: bold;
}
table td {
 padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">
<div id="answer-list">
 <h2>Leaderboard</h2>
 <table class="answer-list">
 <thead>
 <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr>
 </thead>
 <tbody id="answers">
 </tbody>
 </table>
</div>
<div id="language-list">
 <h2>Winners by Language</h2>
 <table class="language-list">
 <thead>
 <tr><td>Language</td><td>User</td><td>Score</td></tr>
 </thead>
 <tbody id="languages">
 </tbody>
 </table>
</div>
<table style="display: none">
 <tbody id="answer-template">
 <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
 </tbody>
</table>
<table style="display: none">
 <tbody id="language-template">
 <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
 </tbody>
</table>

emanresu A
46.2k5 gold badges111 silver badges257 bronze badges
asked Sep 6, 2016 at 21:18
\$\endgroup\$
7
  • \$\begingroup\$ Are trailing spaces allowed? \$\endgroup\$ Commented Sep 6, 2016 at 23:36
  • \$\begingroup\$ @Neil Yes. (15 chars) \$\endgroup\$ Commented Sep 7, 2016 at 0:02
  • \$\begingroup\$ Just curious, what's with the additional characters in the challenge title? \$\endgroup\$ Commented Sep 7, 2016 at 18:12
  • \$\begingroup\$ @TimmyD "A cube of text" is 14 characters long, the title needs to be at least 15 characters long, so I added a small dot. I think it's this one. \$\endgroup\$ Commented Sep 7, 2016 at 18:30
  • \$\begingroup\$ Ah, OK. It shows up as a much larger circle in IE on my computer, hence my question. \$\endgroup\$ Commented Sep 7, 2016 at 18:35

9 Answers 9

4
\$\begingroup\$

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)
mbomb007
23.6k7 gold badges66 silver badges143 bronze badges
answered Sep 6, 2016 at 22:57
\$\endgroup\$
4
  • \$\begingroup\$ That's 203 bytes. Also, you can save 4 bytes by replacing raw_input() with input(). \$\endgroup\$ Commented Sep 6, 2016 at 23:19
  • \$\begingroup\$ x*(q)? You should be able to remove the parens, yes? \$\endgroup\$ Commented Sep 7, 2016 at 0:11
  • \$\begingroup\$ You're right, silly me ;) Fixing it now haha \$\endgroup\$ Commented Sep 7, 2016 at 0:13
  • \$\begingroup\$ x*(i-1) -> x*~-i \$\endgroup\$ Commented Sep 7, 2016 at 20:26
3
\$\begingroup\$

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.

answered Sep 7, 2016 at 18:07
\$\endgroup\$
3
\$\begingroup\$

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'
answered Sep 7, 2016 at 0:09
\$\endgroup\$
3
\$\begingroup\$

Vyxal, 13 bytes

L?∞Ṫ»∨102H»ø∧

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
 »∨102H» # Directions: digits of 24560125406
 .>2>.
 ⇗ ⇙v
 1 5 4
 ⇗ ⇙ v
.<6<. .
^ v ⇙
0 4 5
^ v⇙
.<6<.
answered May 30, 2024 at 20:53
\$\endgroup\$
2
\$\begingroup\$

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.

Try it online here!

answered Sep 9, 2016 at 21:20
\$\endgroup\$
2
\$\begingroup\$

05AB1E, (削除) 35 (削除ここまで) 12 bytes

gIû ̈•5ÏlÐθ•Λ

-23 bytes by porting emanresuA's Vyxal answer, so make sure to upvote that answer as well!

Try it online.

Original 35 bytes answer:

g ̧ÞI ̧Þð13ÅÉǝ•6 ́XdaÅ~ßмñD>γ•3в)øvy`Λ

Try it online.

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 ́XdaÅ~ßмñD>γ• # Push compressed integer 506660546965149280261611581961
 3в # 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 ́XdaÅ~ßмñD>γ• is 506660546965149280261611581961 and •6 ́XdaÅ~ßмñD>γ•3в 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:

  1. Length of the lines we want to draw
  2. Character/string to draw
  3. 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 ́XdaÅ~ßмñD>γ•3в)ø 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]]
  1. The first 13,"Hello, world!",1 will draw (all) 13 characters of string "Hello, world!" in direction 1/↗: try just this first step online;
  2. The second 13," ",8 will with special direction 8 reset back to the origin (the 13 and " " are ignored): try just the first two steps online;
  3. The third 13,"Hello, world!",84 will first reset back to the origin with direction 8 (step 2 is kinda a no-op to save a byte on the 13ÅÉ), and then again draw (all) 13 characters of string "Hello, world!" in direction 4/↓: try just the first three steps online;
  4. The fourth 13," ",80 will first reset back to the origin with direction 8 again, and then draw 13 space characters in direction 0/↑: try just the first four steps online;
  5. The fifth 13,"Hello, world!",2 will then continuing from that position to draw (all) 13 characters of string "Hello, world!" in direction 2/→: try just the first five steps online;
  6. etc. etc.
  • The sixteenth 13,"Hello, world!",86 will again reset, and then draw in direction 6/←, 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.

answered May 28, 2024 at 9:16
\$\endgroup\$
2
  • 1
    \$\begingroup\$ You might want to look at how my vyxal answer avoids canvas backtracking \$\endgroup\$ Commented May 30, 2024 at 20:54
  • \$\begingroup\$ @emanresuA Thanks, that's indeed 1/3rd of the byte-count. ;) \$\endgroup\$ Commented May 31, 2024 at 0:00
1
\$\begingroup\$

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`
`)}
answered Sep 6, 2016 at 22:54
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice, although golfable: (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`\n` (using \n because you can't put newlines in comments). \$\endgroup\$ Commented Sep 7, 2016 at 0:03
1
\$\begingroup\$

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}

Try it online!

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}

Try it online!

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
answered May 29, 2024 at 23:28
\$\endgroup\$
0
\$\begingroup\$

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円',' '));}}

Try it here!

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円',' '));
 }
}
answered Sep 9, 2016 at 20:41
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.