Ghosts and Pumpkins
JavaScript (ES7), 166 164 159 bytes
Saved 5 bytes thanks to Neil
f=(p,g,j=(g*2)**.5+.5|0,G=j>p-1?p?p-1:0:j,P=`
`,i=~j?g-G*++G/2:G,n=i>0?i>g?g:i:0)=>p|g?f(0,g-n,-1,G-1,P+' ')+P+'((^v^)) '.repeat(p)+'\\{O.O}/ '.repeat(n):''
Formatted and commented
f = ( // given:
p, // - p = number of pumpkins
g, // - g = number of ghosts
j = (g * 2) ** .5 + .5 | 0, // - j = ceil(triangular root of g)
G = j > p - 1 ? p ? p - 1 : 0 : j, // - G = max(0, min(p - 1, j))
P = '\n', // - P = padding string (+ line-break)
i = ~j ? // - i =
g - G * ++G / 2 // first iteration: g - G * (G + 1) / 2
: G, // next iterations: G
n = i > 0 ? i > g ? g : i : 0 // - n = max(0, min(i, g)) = number of
) => // ghosts to print at this iteration
p | g ? // if there's still something to print:
f( // do a recursive call with:
0, // - no pumpkin anymore
g - n, // - the updated number of ghosts
-1, // - j = -1 (so that ~j == 0)
G - 1, // - one less ghost on the pyramid row
P + ' ' // - updated padding string
) + //
P + // append padding string
'((^v^)) '.repeat(p) + // append pumpkins
'\\{O.O}/ '.repeat(n) // append ghosts
: '' // else: stop
Underlying math
The tricky part is to find out the optimal width G
of the ghost pyramid.
The number of ghosts g
in such a pyramid is given by:
g = 1 + 2 + 3 + ... + G = G(G + 1) / 2
Reciprocally, the width of a pyramid containing g
ghosts is the real root of the resulting quadratic equation:
G² + G - 2g = 0
Δ = 1² - 4(-2g)
Δ = 8g + 1
G = (-1 ± √Δ) / 2
Which leads to the following real root (also known as the triangular root):
G = (√(8g + 1) - 1) / 2
However, the width of the pyramid is also limited by the number of pumpkins: we can have no more than p-1
ghosts over p
pumpkins. Hence the final formula used in the code:
j = ⌈(√(8g + 1) - 1) / 2⌉
G = max(0, min(p - 1, j))
ES6 version, 173 171 166 bytes
f=(p,g,j=Math.pow(g*2,.5)+.5|0,G=j>p-1?p?p-1:0:j,P=`
`,i=~j?g-G*++G/2:G,n=i>0?i>g?g:i:0)=>p|g?f(0,g-n,-1,G-1,P+' ')+P+'((^v^)) '.repeat(p)+'\\{O.O}/ '.repeat(n):''
Test cases (ES6)
f=(p,g,j=Math.pow(g*2,.5)+.5|0,G=j>p-1?p?p-1:0:j,P=`
`,i=~j?g-G*++G/2:G,n=i>0?i>g?g:i:0)=>p|g?f(0,g-n,-1,G-1,P+' ')+P+'((^v^)) '.repeat(p)+'\\{O.O}/ '.repeat(n):''
console.log(f(0, 1));
console.log(f(1, 0));
console.log(f(1, 1));
console.log(f(2, 1));
console.log(f(2, 2));
console.log(f(3, 1));
console.log(f(3, 2));
console.log(f(3, 3));
console.log(f(0, 4));
console.log(f(3, 0));
console.log(f(7, 6));
Perl, 246 bytes (newlines are not part of the code and are provided solely for readability)
($c,$d)=<>=~/(\d+)/g;
$p="((^v^)) ";$g="\\{O.O}/ ";
for($f[0]=$c;$d>0;$d--){$f[$b+1]+1<$f[$b]?$f[++$b]++:$f[$b]++;$f[0]+=$d,$d=0 if$b==$c-1;$f[$b]==1?$b=0:1}
$h[0]=($p x$c).$g x($f[0]-$c);$h[$_].=$"x(4*$_).$g x$f[$_]for(1..$#f);
say join$/,reverse@h;
Accepts two numbers: pumpkins first, followed by ghosts. Sample input:
5 20
Sample output:
\{O.O}/
\{O.O}/ \{O.O}/
\{O.O}/ \{O.O}/ \{O.O}/
\{O.O}/ \{O.O}/ \{O.O}/ \{O.O}/
((^v^)) ((^v^)) ((^v^)) ((^v^)) ((^v^)) \{O.O}/ \{O.O}/ \{O.O}/ \{O.O}/ \{O.O}/ \{O.O}/ \{O.O}/ \{O.O}/ \{O.O}/ \{O.O}/ \{O.O}/