Bowl Filled with Water

19

3

You should write a program or function which receives the volume of a bowl and the volume of the water in it as input and outputs or returns an ASCII representation of a bowl with water in it with the desired volumes.

A bowl has the following structure:

 \     /
  \___/

The bowl has at least one _ character. The count of \'s and /'s are also positive and they are equal due to symmetry.

The volume of the bowl is the total number of _ and space characters between the \'s and /'s plus one for every pair of \ and /. This means the above bowl has the volume of 10:

 \     /  =>  xxxxx x (the last one is for the \/ pair)
  \___/        xxx x (the last one is for the \/ pair)

Note that two different bowl could have the same volume. E.g. both the following bowls have a volume of 18:

\       /
 \     /      \         /
  \___/        \_______/

We can pour some water into the bowl. The water is represented as a row of ~ characters instead of spaces inside the bowl. The bottom row has no spaces so it can not contain the ~'s. This means our example can be filled with water in only one way:

 \~~~~~/
  \___/

Other bowls could be filled in multiple ways:

 \~~~~~/   \     /
  \   /     \~~~/
   \_/       \_/

The volume of the water in a bowl is the volume of the bowl rows below the ~ characters. The above examples have water volumes of 4, 6 and 2 respectively.

Input

  • Two positive integers, the volume of the bowl and the volume of the water.
  • You can choose the order of the two numbers.
  • The two integer can be inputted in any common list format (list, tuple, array, etc.) or as two separate integers.
  • At least one valid bowl-water configuration is guaranteed for the input values.

Output

  • The ASCII representation of a bowl with water where the bowl and water volumes match the input.
  • If you choose to return the result instead of printing, it should be returned as single string (or your language's closest alternative).
  • Any trailing whitespace is allowed.
  • No unnecessary leading whitespace is allowed.
  • If there are multiple correct configurations you are free to choose which one you output but you can only output one of them.

Examples

Each input integer pair is followed by its one or more possible outputs.

6 2
\~~~/
 \_/

10 4
\~~~~~/
 \___/

24 8
\        /
 \~~~~~~/
  \    /
   \__/

42 12 //either of the two output is correct
\           /
 \         /
  \~~~~~~~/
   \     /
    \   /
     \_/

\               /
 \~~~~~~~~~~~~~/
  \___________/

90 68
\~~~~~~~~~~~~~~~~~~~~~/
 \                   /
  \                 /
   \               /
    \_____________/

102 42
\                     /
 \                   /
  \~~~~~~~~~~~~~~~~~/
   \               /
    \             /
     \___________/

This is code golf so the shortest entry wins.

randomra

Posted 2015-07-30T16:51:38.493

Reputation: 19 909

Answers

6

CJam, 72 70 69 bytes

q~:QW=3m*{:,2ff*),)ff+}%{::)1fbQ=}=~W%ee_,S*W'_t@,~'~t.{S\+.*"\/".+N}

Try it online in the CJam interpreter.

Run time and memory usage are O(scary), so the last three test cases should be verified using the Java interpreter (and extra heap space).

Example run

$ time java -Xmx4G -jar cjam-0.6.5.jar bowl.cjam <<< '[42 102]'
\                     /
 \                   /
  \~~~~~~~~~~~~~~~~~/
   \               /
    \             /
     \___________/

real    0m40.669s
user    3m13.100s
sys     0m11.690s

How it works

q~:Q     e# Read from STIDN, evaluate and save the result in Q.
W=       e# Select the last element of Q (bowl volume B).
3m*      e# Push all vectors of {0,...,B-1} × {0,...,B-1} x {0,...,B-1}.

{        e# For each vector [X Y Z]:
  :,     e#   Push [[0 1 ... X-1] [0 1 ... Y-1] [0 1 ... Z-1]].
  2ff*   e#   Multiply each coordinate by 2.
  ),)    e#   Pop the last vector, compute its length and increment.
  ff+    e#   Add the result to each component of each vector.
}%       e# Result: [[Z Z+2 ... Z+2(X-1)] [Z Z+2 ... Z+2(Y-1)]]

{        e# Find:
  ::)    e#   Increment each coordinate (to account for the volume in "\/").
  1fb    e#   Sum the coordinate of both vectors.
  Q=     e#   Compare the result to Q (desired volumes).
}=       e# If they match, push the array and break.

~        e# Dump both vectors on the stack.
W%       e# Reverse the rightmost one (corresponds to the bowl volume).
ee       e# Enumerate its coordinates.
         e# [Z+2(Y-1) ... Z+2 Z] -> [[0 Z+2(Y-1)] ... [Y-2 Z+2] [Y-1 Z]].
_,S*     e# Compute the length (Y) and push a string of Y spaces.
W'_t     e# Replace the last space with an underscore.
@        e# Rotate the leftmost vector (corresponds to the water volume) on top.
,        e# Compute its length (X).
~'~t     e# Replace the space at index X from the right with a tilde.

.{       e# For each enumerates coordinate and the corresponding character:
  S\+    e#   Append the character to the string " ".
  .*     e#   Vectorized repetition: [1 2] " ~" -> [" " "~~"]
  "\/".+ e#   Append the first (second) solidus to the first (second) string.
  N      e#   Push a linefeed.
}

Dennis

Posted 2015-07-30T16:51:38.493

Reputation: 196 637

2

C, 231 229 bytes

Early submission :) There's lots more golfing to do here.

v,V,w,h,H,i,j;main(c,a)char**a;{V=atoi(a[1]);v=atoi(a[2]);for(;++H;)for(h=0;h++<H;){for(w=1;h*h+w*h-h<v;++w);if(H*H+w*H-H==V){for(;H--;){printf("%*s",++i,"\\");for(j=0;j++<w-1+2*H;)putchar(H?H==h?'~':32:95);puts("/");}exit(0);}}}

Ungolfed:

int v,V,w,h,H,i,j;
int main(int c, char **a)
{
    V=atoi(a[1]); /* Volume of bowl */
    v=atoi(a[2]); /* Volume of water */

    for(;++H;) /* Make the bowl taller */
    {
        for(h=0;h++<H;) /* Make the water taller */
        {
            for(w=1;h*h+w*h-h<v;++w); /* Make the bowl wider until the water volume matches */
            if(H*H+w*H-H==V) /* if the bowl volume matches, then we're good */
            {
                for(;H--;) /* Print out the bowl, one line at a time */
                {
                    printf("%*s",++i,"\\"); /* Print the left edge */
                    /* Print the inside (either with air/water, the top of the water, or the bottom of the bowl */
                    for(j=0;j++<w-1+2*H;)
                        putchar(H?H==h?'~':32:95);
                    /* Print the right edge of the bowl */
                    puts("/");
                }
                exit(0); /* die, we're done */
            }
        }
    }
}

Cole Cameron

Posted 2015-07-30T16:51:38.493

Reputation: 1 013

Is it possible to encounter a bowl that matches the bowl volume but cannot meet a water volume? – Vartan – 2015-07-30T20:14:11.843

At least one valid bowl-water configuration is guaranteed for the input values. - OP – Cole Cameron – 2015-07-30T20:46:31.030

2

Javascript ES5, 364 bytes

This is what i could come up with quickly during my lunch, help me golf it out while my shift ends!

Source

function V(x,v) { // calculate volume of bowl/water
    for(i=v,j=x;i--;j+=2) {
      v+=j; 
    }
    return v
}
function B(x,y,l) { // draw bowl/water
    for(s="",h=y,w = x+2*y;y--;s+="\n")
        for(i=w;i--;) {
            f= i>h-y-1 && w-i > h-y;
            s+=i==h-y-1?"/": 
                w-i == h-y? "\\":
                y==l-1 && f? "~" :
                !y && f?"_":" "
        }
    return s;
}
n=prompt().split(" ");
b=+n[0]; // bowl volume
w=+n[1]; // water volume
for(x=b;x;x--)  // loop through possible widths
  for(y=b;y;y--)  // loop through possible heights
    if(V(x,y)==b) // check if we found bowl volume
       for(y2=y;y2;y2--) { // check possible water heights
         v = V(x,y2-1);
         if(v==w){ // see if volume matches
          alert(B(x,y,y2));
          x=1;break;
         }
       }

Golfed:

(ran through minifier to compress, lunch shift ended)

function V(f,r){for(i=r,j=f;i--;j+=2)r+=j;return r}function B(r,y,n){for(s="",h=y,w=r+2*y;y--;s+="\n")for(i=w;i--;)f=i>h-y-1&&w-i>h-y,s+=i==h-y-1?"/":w-i==h-y?"\\":y==n-1&&f?"~":!y&&f?"_":" ";return s}for(n=prompt().split(" "),b=+n[0],w=+n[1],x=b;x;x--)for(y=b;y;y--)if(V(x,y)==b)for(y2=y;y2;y2--)if(v=V(x,y2-1),v==w){alert(B(x,y,y2)),x=1;break}

Vartan

Posted 2015-07-30T16:51:38.493

Reputation: 231

2

Perl, 227 172 bytes

Run with -n option:

/ /;for$h(1..$`){for$w(1..$`){for$l(1..($h*($w+$h)==$`)*$h){if($l*($w+$l)==$'){for(0..$h-1){print$"x$_."\\".($_<$h-1?$_==$h-$l-1?"~":$":"_")x($w+($h-$_-1)*2)."/
"}exit}}}}

Thanks to Dennis for help golfing this down.

Calculates bowl volume as height * (width + height), where width is the number of _ characters and height is the number of \ characters.

Each combination of height and width is tested in a pair of nested loops until the correct bowl volume is found, then another loop over possible water height levels is done to find if a the correct water volume is possible with that width.

It is possible to remove the third loop by just calculating the water level using the quadratic formula with a as 1, b as the width and c as the negative of the desired water volume, and checking if it's an integer, but that takes more bytes than just doing a loop. Here it is anyway (183 bytes):

/ /;for$h(1..$`){for$w(1..$`){if($h*($w+$h)==$`){$l=(sqrt($w*$w+4*$')-$w)/2;if(int$l==$l){for(0..$h-1){print$"x$_."\\".($_<$h-1?$_==$h-$l-1?"~":$":"_")x($w+($h-$_-1)*2)."/
"}exit}}}}

samgak

Posted 2015-07-30T16:51:38.493

Reputation: 1 577

2

Python 2, 162 bytes

V,W=input()
r=1
while r*r<V:a=V/r-r;k=1;exec"if(a+k)*k==W*(V%r<1):i=1;exec\"print' '*~-i+'\%s/'%(' _~'[(i==r)-(i==r-k)]*(a+2*(r-i)));i+=1;\"*r;r=V\nk+=1\n"*r;r+=1

A little messy, but here's my first attempt. It tries all possible numbers of rows r, setting the number of base underscores to be a = V/r-r. Then it tries all possible water level heights k and checks if the bowl is valid, printing it if so.

Sp3000

Posted 2015-07-30T16:51:38.493

Reputation: 58 729

1

Python 2.7, 284 270 260 Bytes

def f(b,w,i=1,e='while s<%s:j+=2;s+=j'):
 while 1:
    i+=1;j=s=i;exec e%w
    if s==w:p=j;exec e%b
    if s==b:break
 h=(j-i)/2+1;t=w=i+(h-1)*2+1
 for j in range(h):r,s,t=((' '*(t-2),'_'*(i-1))[j==h-1],'~'*(t-2))[j==h-(p-i)/2-2],(w-t)/2,t-2;print" "*s+"\\"+r+"/"+" "*s

This basically calculates the height and width of the bucket and water and prints them.

Tried hard to remove the ugly while loop part at the start(wherein I calculate the height of the bucket and the height from where water should be drawn. Right now, all lines in the code except for the last one are for calculating the width and height). Still trying :P

Testing it for different cases -

>>> execfile("buckets.py")
(6, 2)
\~~~/
 \_/

(10, 4)
\~~~~~/
 \___/

(24, 8)
\        /
 \~~~~~~/
  \    /
   \__/

(42, 12)
\           /
 \         /
  \~~~~~~~/
   \     /
    \   /
     \_/

(90, 68)
\~~~~~~~~~~~~~~~~~~~~~/
 \                   /
  \                 /
   \               /
    \_____________/

(102, 42)
\                     /
 \                   /
  \~~~~~~~~~~~~~~~~~/
   \               /
    \             /
     \___________/

Kamehameha

Posted 2015-07-30T16:51:38.493

Reputation: 553