Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Your program gets a text as an input, at least 8 characters long, and always consisting of even number of characters. (no need to evaluate correctness of input).

Your goal is to display that text as a rectangle. For example, given HelloWorld as an input, display

Hell
d  o
lroW

Rules:

  • Text goes around clockwise (starting position as you like)
  • It will form a closed rectangle, sides 1 character wide.
  • The rectangle will have to encompass the most area inside. (just to rule out the trivial answer of displaying the text in two lines)
  • No other characters are printed besides the text itself and the necessary padding spaces and line feeds.

As code-golf, shortest code wins.

Winner is selected not sooner than 10 days after first valid answer.

share|improve this question

15 Answers 15

up vote 5 down vote accepted

GolfScript, 56 53 40 38 characters

1/..,4/):l<n@l>{)" "l*2>@(n@.,l-}do-1%

You may test the script online.

share|improve this answer

PostScript 50 binary, 113 ASCII

This uses graphical output. Hexdump of the program using binary tokens:

$ hexdump -C textRect_binary.ps 
00000000  74 5b 30 20 39 5b 74 92  62 34 92 36 92 38 92 10  |t[0 9[t.b4.6.8..|
00000010  32 92 19 5d 7b 92 2c 7b  32 92 19 7d 92 83 92 3e  |2..]{.,{2..}...>|
00000020  92 6e 7d 92 49 5d 39 20  39 92 6b 91 c7 39 92 8e  |.n}.I]9 9.k..9..|
00000030  92 c3                                             |..|
00000032

Download to try it. Using Ghostscript, the to-be-rendered text can be passed to the program as follows:

gs -st=helloworld textRect_binary.ps 

Graphical output looks like this:

rendered output

The same code using ASCII tokens looks like this:

t[0 9[t length
4 div dup
ceiling
2 copy]{cvi{2 copy}repeat
exch neg}forall]9 9 moveto/Courier 9 selectfont
xyshow

The strategy is to use xyshow for defining where we move after showing each character before showing the next character. We're starting in the lower left corner, moving clockwise, i.e. first up, then right, then down then left. We're always moving 9 units, so first we have a relative movement of 0 9, then 9 0, then 0 -9, then -9 0. We can get from one pair of these numbers to the next with the sequence exch neg.

We need to build an array for xyshow that holds these pairs of numbers, one pair for each character. This means, if we have helloworld as example string, which has 10 characters, we want to go up twice, then right thrice, then down twice and left thrice. We get these values (two and three) by dividing the string length by 8, once rounding to the floor, once to the ceiling.

So, we copy 0 9 twice, then switch to the relative x/y coordinates using exch neg, copy those thrice and so on.

This commented code shows what happens on the stack:

t[0 9                % t [ 0 9
[t length            % t [ 0 9 [ length
4 div dup            % t [ 0 9 [ length/4 length/4
ceiling              % t [ 0 9 [ length/4=height width
2 copy]              % t [ 0 9 [height width height width]
{%forall             % t [ 0 9 ... x y height_or_width
  cvi                % t [ 0 9 ... x y height_or_width_integer
  {2 copy}           % t [ 0 9 ... x y height_or_width_integer {2 copy}
  repeat             % t [ 0 9 ... x y .. x y
  exch neg           % t [ 0 9 ... x y .. y -x
}forall]             % t [0 9 ... -9 0]
9 9 moveto/Courier 9 selectfont
xyshow
share|improve this answer
    
+1 holy bajeezus. I'm seriously deficient in my knowledge of level-2 and beyond. –  luser droog Jan 20 '13 at 6:51
    
You mean xyshow? Happy to introduce you to this one--some time ago you introduced me to kshow, which I wasn't really aware of ;-). –  Thomas W. Jan 20 '13 at 7:22
    
@luserdroog: BTW: I'm pretty proud that the current GolfScript entry has more than 10% more characters than my binary entry, but it bugs me that my ASCII version is one character away from a draw with Ruby (actually, even three, because the Ruby code could be golfed further). Do you have any ideas for further optimization? –  Thomas W. Jan 20 '13 at 10:51
    
@ThomasW. Now my GolfScript entry is 24% shorter than your binary ;-) And I still think there is still the chance to shorten it even further by one or two chars. –  Howard Jan 24 '13 at 20:31
    
@Howard: Argh!!! Can anyone ever beat GolfScript? –  Thomas W. Jan 24 '13 at 21:08

Ruby 112 100

I'm new to Ruby and this is my first code golf. I drew upon memowe's perl implementation and tried to make a Ruby version of it. This is 112 100 characters and assumes you assign a string to x. Looking forward to seeing others.

l=x.size
puts x[0..w=l/2-h=l/4]
1.upto(h-1){|i|puts x[-i]+' '*(w-1)+x[w+i]}
puts x[w+h..l-h].reverse

Edited to implement suggestions. I think it's 100 characters now. Thanks guys!

share|improve this answer
    
Nice! You can save two chars in the 5th line (remove spaces). –  Thomas W. Jan 19 '13 at 21:00
    
I like it. Thanks. Looks good that Ruby strings can be accessed like an array, I had to built one by myself. :) –  memowe Jan 20 '13 at 14:16
    
You could replace x.length with x.size (Saves 2 characters) –  knut Jan 20 '13 at 22:22
1  
And 8 more using puts x[0..w=l/2-h=l/4]. –  Howard Jan 24 '13 at 20:34

Perl (124 118 109+3=112)

This formerly was pretty straightforward. Counted all command line options as 1 character each.

-nlE
$w=(@s=split//)/2-($h=int@s/4);say@s[0..$w--];say$s[1-$_].$"x$w.$s[$w+$_]for+2..$h;say+reverse@s[@s/2..@s-$h]

Example:

$ perl -nlE '$w=(@s=split//)/2-($h=int@s/4);say@s[0..$w--];say$s[1-$_].$"x$w.$s[$w+$_]for+2..$h;say+reverse@s[@s/2..@s-$h]'
abcdefghijklmnopqrstuvwxyz
abcdefgh
z      i
y      j
x      k
w      l
v      m
utsrqpon
share|improve this answer
    
This can be compacted: (1) (@s-$h*2)/2 == @s/2-$h (2) $w can be represented as $w=(@s=split//)/2-($h=int@s/4);, thus saving two semicolons –  amon Jan 20 '13 at 4:18
    
Thanks, @amon, that's great! :) –  memowe Jan 20 '13 at 14:08
    
Updated the code. –  memowe Jan 20 '13 at 14:14
    
Further interesting stuff: (1) the space is the default value of the array interpolation var $"–saves 1 char. (2) $w+$h == @s/2–saves 1 char. (3) If $w is smaller by one, we can simplify $"x($w-1). For this, the $_ has to be increased by 1. Saves like 3 chars. (4) The final semicolon is überflüssig, saves 1 char. This leads to the code fragment say@s[0..$w--];say$s[1-$_].$"x$w.$s[$w+$_]for+2..$h;say+reverse@s[@s/2..@s-$h] (with a few + for fun, so there isn't a single space left). –  amon Jan 20 '13 at 19:31
    
Excellent golfification, @amon, would you edit it in my post please? That way the world can see who did it. :) –  memowe Jan 20 '13 at 20:34

Brainfuck - 194 187

+>,[>+[>+<-],]
>-->++<[->-[>+>>]>[+[-<+>]>+>>]<<<<<]>[-]>[-]>[<<+<<+>>>>-]<<<<
[[<]>+[>]<-]<[<]>-
[>.[-]<[>+<-]>-]>[>]
++++++++++.<.[-]
>[>+++>>+<<<-]>++>--[<.>-]<<<<[<]>.[-]>[>]>>>>.
<<<<<[.<]
share|improve this answer
    
Nice try, but it does not work. The bottom line is in the wrong direction, contrary to rule 1, and it only has a fixed height, contrary to rule 3. –  vsz Jan 20 '13 at 19:04
    
Not sure why I flipped the last row. I totally had it in mind the correct way as I was writing it. The fix actually saves 7 commands. I did cop out on the fixed height thing, but its not the trivial, 2 line case you talked about. Maybe I'll make it better in the future. –  CMP Jan 22 '13 at 3:05

Mathematica 156 199 344

Edit : This is a major rewrite of earlier code. It works essentially the same, but now takes as input a string of length < 120 chars and automatically sizes the square.

It could still be golfed a bit but will not get down to the size of the earlier, and buggier, versions.

f@s_ := ({a, t, w, q} = {Automatic, Text, Quotient[StringLength@s, 2],
 Quotient[StringLength[s], 4] + 1};z = StringSplit[StringInsert[s <> ConstantArray[" ", 0],
 "*", {q, 2 q, 3 q}], "*"];
Graphics[{t[z[[1]], {0, q}],t[z[[2]], {q, 0}, a, {0, -1}],t[z[[3]], {0, -q}, a, {-1, 0}],
t[z[[4]], {-q, 0}, a, {0, 1}]},ImageSize -> 500,BaseStyle -> {FontFamily -> "Courier", 21},
PlotRange -> 34,ImagePadding -> 22])

Examples

f["Hello Code Golf World!"]
f["January, February, March,April, May, June, July"]
f["This text is normal, this goes downwards,this is upside-down, and this is upwards"]

pic1

pic2

pic3

share|improve this answer
    
Hey, an array of strings? That's really bending the rules, isn't it? –  Thomas W. Jan 20 '13 at 0:03
    
@ThomasW. The comments in the answer indicate it's not a final solution. –  kojiro Jan 20 '13 at 0:48
    
Ah, I see! Wonder whether I should take the challenge and try something similar in PostScript... –  Thomas W. Jan 20 '13 at 10:47
    
I like how it looks now! –  Thomas W. Jan 21 '13 at 19:30
    
@Thomas W. Thanks. Getting the format to look right for a wide range of string lengths cost a lot of bytes. –  David Carraher Jan 21 '13 at 20:41

Perl + Regexes: 104 (101+3)

(counting code + switches)

Here is a solution using nice Regexes, and a bit of Perl:

perl -plE'$w=($l=length)/2-($h=int$l/4);s/..{$w}\K.*/"\n".reverse$&/e;$"x=--$w;s/.\K(.*)(.)$/$"$2\n$1/while--$h'

This will only operate correctly on one input line.

Inspired by memowe, but essentially without any arrays.

share|improve this answer
    
Sorry for the dumb question: How can I try this out? I'm pasting your code to the command line, then type something, press enter and something comes out. But it's not a box. What am I doing wrong? –  Thomas W. Jan 21 '13 at 22:15
    
@ThomasW. It seems to work for me, for an arbitrary even number of chars. The above code is guaranteed to work under bash and perl version 5.12+. Input is accepted via STDIN, and only the first line is processed correctly. I don't know how to quote the code correctly for cmd.exe. –  amon Jan 22 '13 at 13:44
1  
Ah, was probably my mistake. I probably used a string of odd length. This works: echo thisworksgreat | perl -plE'$w=($l=length)/2-($h=int$l/4);s/..{$w}\K.*/"\n".reverse$&/e;$"x=--$w;s/.\K(‌​.*)(.)$/$"$2\n$1/while--$h' –  Thomas W. Jan 22 '13 at 13:59

Python 2.x: 137

I'm new to code golfing and quite sure this can be improved…

def s(t):c=len(t);w=1+c/4;h=(c-w-w)/2;u=w+h;n='\n';print t[:w]+n+n.join(map(((w-2)*' ').join,zip(t[:w+u-1:-1],t[w:u])))+n+t[w+u-1:u-1:-1]

Visual testing code:

from itertools import chain
from string import letters
for i in range(8,101,2):
    t = ''.join(chain(letters))[:i]
    print '%d: %s' % (i, t)
    s(t)
    print '-----'

Something of interest: This solution depends on integer math. If you just do the math symbolically, you'll find that h=(c-w-w)/2 => h=w-2, but if you substitute that result every other result will be missing two lower-left characters.

share|improve this answer

K, 84

{-1'(*r;((|r 3),\:(w-2)#" "),'r 1;|(r:(0,+\(w;h;w;h:_(l-2*w:-_-(1+(l:#x)%4))%2))_x)2);}

.

k){-1'(*r;((|r 3),\:(w-2)#" "),'r 1;|(r:(0,+\(w;h;w;h:_(l-2*w:-_-(1+(l:#x)%4))%2))_x)2);}"HelloWorld"
Hell
d  o
lroW

k){-1'(*r;((|r 3),\:(w-2)#" "),'r 1;|(r:(0,+\(w;h;w;h:_(l-2*w:-_-(1+(l:#x)%4))%2))_x)2);}"Hellooooooooooooooo Worlddddd!"
Hellooooo
!       o
d       o
d       o
d       o
d       o
d       o
lroW oooo
share|improve this answer

PostScript (106)

This is inspired by dude's Mathematica solution.

0{= =
4 add dup
t length mod 4
lt{-90 rotate}if}0[0 3 -3 0 9 9]concat
0 moveto/Courier 5 selectfont
t kshow

With Ghostscript call this like

gs -st=hello! boxtext.ps

It produces output like.

Hello_Code_Golf_World!

January,_February,_March,April,_May,_June,_July

It uses kshow to show the glyphs one by one. After enough glyphs for one side have been shown, everything is rotated by -90 degrees before continuing with the remaining glyphs.

To know when enough glyphs have been shown on the side, we increment a counter by 4 each time a glyph is shown. If the counter value modulo the string length is less than 4, then we know we have to rotate:

char  counter  mod 6  compared to 4
 h       4       4          =
 e       8       2          <   => rotate
 l      12       0          <   => rotate
 l      16       4          =
 o      20       2          <   => rotate
 !      24       0          <   => rotate

enter image description here

Commented and un-golfed source code:

0                      % n
{%kshow                % n char1 char2
  = =                  % n
  4 add dup            % n' n'
  t length mod         % n' (n' mod t_length)
  4 lt                 % n' bool
  {-90 rotate}if       % n'
}                      % n kshowProc
% First 0 for moveto. We add it here to take 
% advantage of the surrounding self delimiting tokens.
0                      % n kshowProc 0
% We change the graphics state so that the drawn
% text is at a nice size and not off screen.
[0 3 -3 0 9 9]concat   % n kshowProc 0
0                      % n kshowProc 0 0
moveto                 % n kshowProc
/Courier 5 selectfont  % n kshowProc
t                      % n kshowProc text
kshow                  % n
share|improve this answer

Scala (135)

The following snippet assumes that x contains the string to format, and should be pasted in the scala REPL:

val (h,w)=((x.size+3)/4,println(_:Any));val s=x.grouped(h)toSeq;w(s(0));for((l,r)<-s(1)zip(s(3)reverse))w(r+" "*(h-2)+l);w(s(2)reverse)

If you don't have scala installed, you can quickly check it using this online Scala interpreter: http://www.simplyscala.com/. Just paste the following text end press evaluate:

val x="HelloWorld"
val (h,w)=((x.size+3)/4,println(_:Any));val s=x.grouped(h)toSeq;w(s(0));for((l,r)<-s(1)zip(s(3)reverse))w(r+" "*(h-2)+l);w(s(2)reverse)
share|improve this answer

Python 3(120)

s=input()
n=len(s)
h=n//4
q=(n+2)//4-1
p=print
p(s[:q+2])
for i in range(1,h):p(s[n-i]+' '*q+s[q+1+i])
p(s[n-h:q+h:-1])

Test

input:

abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz

output:

abcdefghijklmn
z            o
y            p
x            q
w            r
v            s
u            t
t            u
s            v
r            w
q            x
p            y
o            z
nmlkjihgfedcba
share|improve this answer

PHP (149)

The text to print should be in a variable named $x.

@$s=substr;echo$s($x,-$w=($l=strlen($x)/2)-$h=$i=$l-2>>1).'
';while($i--)echo$x[$l+$i].str_repeat(' ',$w-2).$x[$h-$i-1].'
';echo$s(strrev($x),$l,$w);
share|improve this answer

Python2.7 (99)

t=''.join(raw_input().split())
u=len(t)/2-1
print t[:u]+"\n"+t[-1]+" "*(u-2)+t[u]+"\n"+t[-2:u:-1]

Edit: It apparently violates the rule of encompassing maximum area inside.

share|improve this answer

JAVA - 320

public class A{
public static void main(String[] a){
String s=a[0];
int l=s.length(),h=l/2,f=h-1,i=0;       
for(i=0;i<f;i++)
System.out.print(s.charAt(i));
System.out.print("\n"+s.charAt(l-1));
for(i=0;i<f-2;i++)
System.out.print(" ");
System.out.println(s.charAt(h-1));
for(i=l-2;i>h-1;i--)
System.out.print(s.charAt(i));}}

Note : - Input is taken from command line

Input : - HelloWorld

Output : -

Hell
d  o
lroW

Input : - abcdefghijklmnopqrstuvwxyz

Output : -

abcdefghijkl
z          m
yxwvutsrqpon
share|improve this answer
    
Please read the rules more carefully, especially nr. 3. –  vsz Jan 24 '13 at 9:14

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.