Reputation: 67252
The shortest code by character count to output an hourglass according to user input.
Input is composed of two numbers: First number is a greater than 1 integer that represents the height of the bulbs, second number is a percentage (0 - 100) of the hourglass' capacity.
The hourglass' height is made by adding more lines to the hourglass' bulbs, so size 2 (the minimal accepted size) would be:
_____
\ /
\ /
/ \
/___\
Size 3 will add more lines making the bulbs be able to fit more 'sand'.
Sand will be drawn using the character x
. The top bulb will contain N percent 'sand' while the bottom bulb will contain (100 - N) percent sand, where N is the second variable.
'Capacity' is measured by the amount of spaces () the hourglass contains. Where percentage is not exact, it should be rounded up.
Sand is drawn from outside in, giving the right side precedence in case percentage result is even.
Input:
3 71%
Output:
_______
\x xx/
\xxx/
\x/
/ \
/ \
/__xx_\
Input:
5 52%
Output:
___________
\ /
\xx xx/
\xxxxx/
\xxx/
\x/
/ \
/ \
/ \
/ xxx \
/xxxxxxxxx\
Input:
6 75%
Output:
_____________
\x x/
\xxxxxxxxx/
\xxxxxxx/
\xxxxx/
\xxx/
\x/
/ \
/ \
/ \
/ \
/ \
/_xxxxxxxxx_\
Code count includes input/output (i.e full program).
Upvotes: 51
Views: 4581
Reputation: 33607
rJ N 0% rN Wad1mpJ2 S{ \x/ }D0 Hc&[u[Z=~wA Qs^RTkW[isEL0c[skQdvK2][eEV?kQ[tlQ]]pcSeg--B0[eZ1 5]3]prRJ[si^DspSCsQfhS]eZ1[s+DcA+wMPc2no]]]Va|[mpAj**2]prSI^w{_}Ls+W2 h1tiVsb1n -1 chRVs{_}hLceVn1
It's competitive with the shorter solutions here, though it's actually solving the problem in a "naive" way. More or less it's doing the "sand physics" instead of exploiting symmetries or rotating matrices or anything.
H
defines a function for printing a half of an hourglass, to which you pass in a number which is how many spaces to print before you start printing "x" characters. If you're on the top half, the sand string is constructed by alternating appends to the head and the tail. If you're on the bottom it picks the insertion source by skipping into the middle of the string. Commented source available at:
http://github.com/hostilefork/rebmu/blob/master/examples/hourglass.rebmu
But the real trick up Rebmu's sleeve is it's a thin dialect that doesn't break any of the parsing rules of its host language (Rebol). You can turn this into a Doomsday visualization by injecting ordinary code right in the middle, as long you code in lowercase:
>> rebmu [rJ birthday: to-date (ask "When were you born? ") n: (21-dec-2012 - now/date) / (21-dec-2012 - birthday) Wad1mpJ2 S{ \x/ }D0 Hc~[u[Ze?Wa Qs^RTkW[isEL0c[skQdvK2][eEV?kQ[tlQ]]pcSeg--B0[eZ1 5]3]prRJ[si^DspSCsQfhS]eZ1[s+DcA+wMPc2no]]]Va|[mpAj**2]prSI^w{_}Ls+W2h1tiVsb1n -1 chRVs{_}hLceVn1]
Input Integer: 10
When were you born? 23-May-1974
_____________________
\ /
\ /
\ /
\ /
\ /
\ /
\ /
\x xx/
\xxx/
\x/
/ \
/ \
/ xx \
/xxxxxxx\
/xxxxxxxxx\
/xxxxxxxxxxx\
/xxxxxxxxxxxxx\
/xxxxxxxxxxxxxxx\
/xxxxxxxxxxxxxxxxx\
/xxxxxxxxxxxxxxxxxxx\
O noes! :)
(Note: A major reason I'm able to write and debug Rebmu programs is because I can break into ordinary coding at any point to use the existing debugging tools/etc.)
Upvotes: 8
Reputation: 304147
Be sure not to have a newline after the % for the input
eg
$ echo -n 3 71%|./golfscript.rb hourglass.gs
You can animate the hourglass like this:
$ for((c=100;c>=0;c--));do echo -n "15 $c%"|./golfscript.rb hourglass.gs;echo;sleep 0.1;done;
Golfscript - 136 Chars
Make sure you don't save it with an extra newline on the end or it will print an extra number
);' ': /(~:
;0=~100.@-
.**\/:t;'_':&&
*.n
,{:y *.'\\'+{[&'x':x]0t(:t>=}:S~
(y-,{;S\+S+.}%;'/'++\+}%.{&/ *}%\-1%{-1%x/ *&/x*}%) /&[*]++n*
Golfscript - 144 Chars
);' ':|/(~:^.*:X ;0=~100.@-X*\/ X'x':x*'_':& @*+:s;&&&+ ^*n^,{:y |*.[92 ]+{s [) \# :s;] }:S~^( y-,{;S\+ S+.}%;'/'+ +\+}%.{&/|*} %\-1%{-1%x/|*& /x*}%)|/&[*]++n*
How it works
First do the top line of underscores which is 2n+1
Create the top half of the hourglass, but use '_' chars instead of spaces, so for the 3 71% we would have.
\x__xx/
\xxx/
\x/
Complete the top half by replacing the "_" with " " but save a copy to generate the bottom half
The bottom half is created by reversing the whole thing
/x\
/xxx\
/xx__x\
Replacing all the 'x' with ' ' and then then '_' with 'x'
/ \
/ \
/ xx \
Finally replace the ' ' in the bottom row with '_'
/ \
/ \
/__xx_\
Roundabout but for me, the code turned out shorter than trying to generate both halves at once
Upvotes: 21
Reputation: 116137
I thought I would give bash a try (haven't seen much code-golfing in it). (my version: GNU bash, version 3.2.48(1)-release (i486-pc-linux-gnu))
Based on Mobrule's nice python answer.
Optimizations must still be available, so all suggestions are welcome!
Start from the command line, e.g. : ./hourglass.sh 7 34%
function f () { for i in `seq $1`;do printf "$2";done; }
N=$1;S=$[$1*$1-$1*$1*$[100-${2/\%/}]/100]
b='\';o=$b;n="\n";r=1;while [ $N -gt 0 ];do
N=$[N-1];z=" ";s=$r;[ $N -eq 0 ]&& z=_;[ $S -lt $r ]&& s=$S
S=$[S-s];t=$[r-s];v=$[s/2];w=$[s-v];r=$[r+2]
o=$n`f $N " "`$b`f $v x;f $t " ";f $w x`/$o$b$n`f $N " "`/`f $w "$z";f $t x;f $v "$z"`$b
done;f $r _;echo -e "${o/\/\\\\//}"
Upvotes: 3
Reputation: 118605
N,p=map(int,raw_input()[:-1].split())
S=N*N-N*N*(100-p)/100
_,e,x,b,f,n=C='_ x\/\n'
o=""
r=1
while N:N-=1;z=C[N>0];s=min(S,r);S-=s;t=r-s;v=s/2;w=s-v;r+=2;o=n+e*N+b+x*v+e*t+x*w+f+o+n+e*N+f+z*w+x*t+z*v+b
print _*r+o
Upvotes: 14
Reputation: 146043
Ruby, 297 254 (after compression)
Run both with ruby -a -p f.rb
n,p = $F.map{|i|i.to_i}
r="\n"
y=''
g,s,u,f,b=%w{x \ _ / \\}
$> << u*2*n+u+r # draw initial underbar line
a=u
c=100.0/n/n # amount of sand a single x represents
e = 100.0 # percentage floor to indicate sand at this level
n.times{ |i|
d=2*n-1-2*i # number of spaces at this level
e-= c*d # update percentage floor
x = [((p - e)/c+0.5).to_i,d].min
x = 0 if x<0
w = x/2 # small half count
z = x-w # big half count
d = d-x # total padding count
$> << s*i+b+g*w+s*d+g*z+f+r
y=s*i+f+a*z+g*d+a*w+b+r+y
a=s
}
$_=y
Ruby, 211
This is mobrule's tour de force, in Ruby. (And still no final newline. :-)
m,p=$F.map{|i|i.to_i}
q=m*m-m*m*(100-p)/100
_,e,x,b,f=%w{_ \ x \\ /}
n="\n"
o=''
r=1
while m>0
m-=1
z=m>0?e:_
s=q<r ?q:r
q-=s
t=r-s
v=s/2
w=s-v
r=r+2
o=n+e*m+b+x*v+e*t+x*w+f+o+n+e*m+f+z*w+x*t+z*v+b
end
$_=_*r+o
Upvotes: 0
Reputation: 3707
PHP - 361
<?$s=$argv[1];$x='str_pad';$w=$s*2-1;$o[]=$x('',$w+2,'_');
$r=$s*ceil($w/2);$w=$r-($r*substr($argv[2],0,-1)/100);$p=0;
$c=-1;while($s){$k=$s--*2-1;$f=$x($x('',min($k,$w),' '),$k,'x',2);
$g=$x($x('',min($k,$w),'x'),$k,' ',2);$w-=$k;$o[]=$x('',$p)."\\$f/";
$b[]=$x('',$p++)."/$g\\";}$b[0]=str_replace(' ','_',$b[0]);
krsort($b);echo implode("\n",array_merge($o,$b));?>
Upvotes: 2
Reputation: 35054
x n c=h s++'\n':reverse(h(flip s)) where h s=r w '-'++s '+' b(w-2)0 p;w=(t n);p=d(n*n*c)100
s x n i o p|i>0='\n':l++s x n(i-2)(o+1)(max(p-i)0)|True=[] where l=r o b++'\\':f d++r(i#p)n++f m++'/':r o b;f g=r(g(i-(i#p))2)x
b=' '
r=replicate
t n=1+2*n
d=div
(#)=min
m=(uncurry(+).).divMod
Run with e.g. x 5 50
Upvotes: 6
Reputation: 90422
A c++ answer, is 592 chars so far, still having reasonable formatting.
#include<iostream>
#include<string>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef string S;
typedef int I;
typedef char C;
I main(I,C**v){
I z=atoi(v[1]),c=z*z,f=ceil(c*atoi(v[2])/100.);
cout<<S(z*2+1,'_')<<'\n';
for(I i=z,n=c;i;--i){
I y=i*2-1;
S s(y,' ');
C*l=&s[0];
C*r=&s[y];
for(I j=0;j<y;++j)
if(n--<=f)*((j&1)?l++:--r)='x';
cout<<S(z-i,' ')<<'\\'<<s<<"/\n";
}
for(I i=1,n=c-f;i<=z;++i){
I y=i*2-1;
S s(y,'x');
C*l=&s[0];
C*r=&s[y];
for(I j=0;j<y;++j)
if(n++<c)*(!(j&1)?l++:--r)=(i==z)?'_':' ';
cout<<S(z-i,' ')<<'/'<<s<<"\\\n";
}
}
If i decide to just forget formatting it reasonably, i can get it as low as 531:
#include<iostream>
#include<string>
#include<cstdlib>
#include<cmath>
using namespace std;typedef string S;typedef int I;typedef char C;I main(I,C**v){I z=atoi(v[1]),c=z*z,f=ceil(c*atoi(v[2])/100.);cout<<S(z*2+1,'_')<<'\n';for(I i=z,n=c;i;--i){I y=i*2-1;S s(y,' ');C*l=&s[0];C*r=&s[y];for(I j=0;j<y;++j)if(n--<=f)*((j&1)?l++:--r)='x';cout<<S(z-i,' ')<<'\\'<<s<<"/\n";}for(I i=1,n=c-f;i<=z;++i){I y=i*2-1;S s(y,'x');C*l=&s[0];C*r=&s[y];for(I j=0;j<y;++j)if(n++<c)*(!(j&1)?l++:--r)=(i==z)?'_':' ';cout<<S(z-i,' ')<<'/'<<s<<"\\\n";}}
Upvotes: 4
Reputation: 118605
205 199 191 chars.
$S=-int((1-.01*pop)*($N=pop)*$N)+$N*$N;$S-=$s=$S>++$r?$r:$S,
$\=$/.$"x$N."\\".x x($v=$s/2).$"x($t=$r++-$s).x x($w=$v+.5)."/$\
".$"x$N."/".($^=$N?$":_)x$w.x x$t.$^x$v."\\"while$N--;print$^x++$r
Explicit newline required between the 2nd and 3rd lines.
And with help of the new Acme::AsciiArtinator module:
$S=-int((1-.01*pop)*($N=pop
) *
$ N
) +
$ N
*$N;( ${B},$
F,${x})=qw(\\ / x
);while($N){;/l
ater/g;$S-=$s
=$S>++$r?$r
:$S;'than
you';@o
=(" "
x--
$ N
. $
B .
x x
( $
v =
$ s
/ 2
) .$"x($t= $
r++-$s).x x($w=$v+.5)
.$F,@o,$"x$N.$F.($^=$N?
$":_)x$w.x x$t.$^x$v.$B);
$,=$/}print$^x++$r,@o;think
Upvotes: 23
Reputation: 12993
Exabyte18's java converted to C#, 655 bytes:
public class M {public static void Main(){int h = Convert.ToInt32(Console.ReadLine());
int s = Convert.ToInt32(h * h * Convert.ToInt32(Console.ReadLine()) / 100);r(h,h-1,s,true);
r(h,h-1,s,false);Console.ReadLine();}static void r(int h, int c, int r, bool t){
if(c<0) return;int u=2*(h-c)-1;if (t&&c==h-1)p(2*h+1,0,'_','_',true,0,false);
int z=r>=u?u:r; r-=z;if (t)M.r(h,c-1,r,true); p(u,z,t?'x':((c==0)?'_':' '), t?' ':'x',t,c,true);
if(!t)M.r(h,c-1,r,false);}static void p(int s, int n, char o, char i, bool t, int p, bool d)
{int f=(s-n);int q=n/2+(!t&&(f%2==0)?1:0);int e=q+f;string z="";int j;for(j=0;j<p+4;j++) z+=" ";if(d)z+=t?'\\':'/';
for (j=0;j<s;j++) z+=(j>=q&&j<e)?i:o; if(d)z+=t?'/':'\\';Console.WriteLine(z);}}
Upvotes: 1
Reputation: 304147
X,p=map(int,raw_input()[:-1].split())
k=X*X;j=k*(100-p)/100
n,u,x,f,b,s='\n_x/\ '
S=list(x*k+s*j).pop;T=list(s*k+u*(2*X-j-1)+x*j).pop
A=B=""
for y in range(X):
r=S();q=T()
for i in range(X-y-1):r=S()+r+S();q+=T();q=T()+q
A+=n+s*y+b+r+f;B=n+s*y+f+q+b+B
print u+u*2*X+A+B
Upvotes: 1
Reputation: 19
public class M{public static void main(String[] a){int h=Integer.parseInt(a[0]);int s=(int)Math.ceil(h*h*Integer.parseInt(a[1])/100.);r(h,h-1,s,true);r(h,h-1,s,false);}static void r(int h,int c,int r,boolean t){if(c<0)return;int u=2*(h-c)-1;if(t&&c==h-1)p(2*h+1,0,'_','_',true,0,false);int z=r>=u?u:r;r-=z;if(t)r(h,c-1,r,true);p(u,z,t?'x':((c==0)?'_':' '),t?' ':'x',t,c,true);if(!t)r(h,c-1,r,false);}static void p(int s,int n,char o,char i,boolean t,int p,boolean d){int f=(s-n);int q=n/2+(!t&&(f%2==0)?1:0);int e=q+f;String z = "";int j;for(j=0;j<p+4;j++)z+=" ";if(d)z+=t?'\\':'/';for(j=0;j<s;j++)z+=(j>=q&&j<e)?i:o;if(d)z+=t?'/':'\\';System.out.println(z);}}
I need to find a better set of golf clubs.
Upvotes: 2
Reputation: 9193
Takes input as parameters: a.out 5 52%
#include<stdio.h>
#include<memory.h>
#include<stdlib.h>
#define p printf
int h,c,*l,i,w,j,*q,k;const char*
z;int main(int argc,char**argv)
{h=atoi(argv[1]);c=(h*h*atoi(
argv[2])+99)/100;l=new int[
h*3];for(q=l,i=0,w=1;i<h;
i++,c=(c-w)&~((c-w)>>31
),w+=2)if(c>=w){*q++=
0;*q++ =0;* q++=w;}
else {*q++=(c+1)/
2;*q++=w-c;*q++
=c/2;}p("_");
for(i=0;i<h
;i ++)p (
"__");p
("\n"
);q
=
l+h
*3-1;
for (i=
--h;i>=0;
i--){p("%*"
"s\\",h-i,"")
; z= "x\0 \0x";
for(k=0;k<3;k++,q
--,z+=2)for(j=0;j<*
q;j++)p(z);q-=0;p("/"
"\n");}q=l;for(i=0;i<=h
;i++){z =i==h? "_\0x\0_":
" \0x\0 ";p("%*s/",h-i,"");
for(k=0;k<3;k++,q++,z+=2)for(
j=0;j<*q;j++)p(z);p("\\\n") ;}}
...and the decrypted version of this for us mere humans:
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#define p printf
int h, c, *l, i, w, j, *q, k;
const char *z;
int main(int argc, char** argv)
{
h = atoi(argv [1]);
c = (h*h*atoi(argv[2])+99)/100;
l = new int[h*3];
for (q = l,i = 0,w = 1; i<h; i++,c = (c-w)&~((c-w)>>31),w += 2) {
if (c>=w) {
*q++ = 0;
*q++ = 0;
*q++ = w;
} else {
*q++ = (c+1)/2;
*q++ = w-c;
*q++ = c/2;
}
}
p("_");
for (i = 0; i<h; i++) {
p("__");
}
p("\n");
q = l+h*3-1;
for (i = --h; i>=0; i--) {
p("%*s\\",h-i,"");
z = "x\0 \0x";
for (k = 0; k<3; k++,q--,z += 2) {
for (j = 0; j<*q; j++) {
p(z);
}
}
p("/\n");
}
q = l;
for (i = 0; i<=h; i++) {
z = i==h ? "_\0x\0_" : " \0x\0 ";
p("%*s/",h-i,"");
for (k = 0; k<3; k++,q++,z += 2) {
for (j = 0; j<*q; j++) {
p(z);
}
}
p("\\\n") ;
}
}
Upvotes: 36