# Bucket interpreter

Create a program that interprets the programming language Bucket.

Bucket works on two buckets: the first can hold A and the second can hold B units of liquid. The things you can do with these buckets are:

f: fill bucket A

F: fill bucket B

e: empty bucket A

E: empty bucket B

p: pour units of liquid from A to B until one is empty or the other is full, whichever happens first

P: same as the command p, but from B to A

o: output the value of bucket A

O: output the value of bucket B

These examples assume A is less than or equal to B in the tuple (A,B), which is the main tuple determining which variant of the language is to be interpreted. A is the lesser-or-equal value of a bucket here and B is the larger-or-equal value: substitute as you need.

1. the element A in the tuple (A,B):
2. the element B in (A,B):
3. the program to interpret.

The tuple (A,B) determines which variant of the language Bucket is interpreted.

As a general rule, make sure the first two inputs can range from 0 to 2,147,483,647.

Any characters in the third input other than fFeEpPoO do not need to be handled. Assume no characters other than these will be in the source.

Any commands equal to pouring more liquid in any bucket than it can hold do not need to be handled.

Assume the program will never try to pour liquid from an empty bucket.

This is code golf, so the shortest solution wins.

Any programs made before I changed the specifications to be correct are now non-competing.

• Thank you very much for requesting implementations of my language! (Although USACO invented it before me) – A̲̲ Aug 10 at 12:19
• Oh, in the Bucket spec, pouring more liquid in any bucket than it can hold should output nothing. – A̲̲ Aug 10 at 12:46
• Some test cases would be nice. – Xcali Aug 10 at 19:03
• I've VTC as unclear until Roman's point has been explicitly addressed (as an answer has already been posted implementing Bucket's p and P)... I understand that, as it is, the self-contained post is actually clear, but think the point is worth addressing that much that it'd be nice to stop answers coming in in the interim. – Jonathan Allan Aug 10 at 19:21
• I corrected it. Any answers made in the interim period where my spec was wrong are no longer competing. – Andrew Aug 10 at 21:07

# Perl 5, 194 bytes

$x='if(e>$B-E){e-=$B-E;E=$B}l{E+=e;e=0}';$y=y/eEAB/EeBA/r;($A,$B,$_)=<>;s/[^fepo]//gi;s/e/$&=0;/gi;s/o/say$&|0;/gi;s/F/O=$B;/g;s/f/o=$A;/g;s/p/$x/g;s/P/$y/g;s'e|o'$a'g;s'E|O'$b'g;s/l/else/g;eval


Try it online!

• Changed it to match. – Xcali Aug 11 at 1:06

# Wolfram Language (Mathematica), 212170166164159157155 153 bytes

A_~J~B_=Fold[Switch[{a,b}=#;#2,3,Echo@a;#,4,#+Min[a,B-b]z,5|6,{#2A-5A,b},7,Echo@b;#,8,#-Min[b,A-a]z,_,{a,#2B-9B}]&,z={-1,1};0z,ToCharacterCode@#~Mod~12]&


Try it online!

Calling J[A,B] returns an interpreter for the (A,B)-bucket system, which can be applied to a program with J[A,B]["prog"]. The "o" and "O" commands print using Echo, and the return value of the program is the final bucket state.

The program is a big Switch statement folded over the character codes (modulo 12) of the program, step-wise updating the contents of the buckets. Dispatching the Switch takes a shortcut by defaulting to E|F (9|10), as the spec says that there are no characters to be expected other than "fFeEpPoO".

Debugging is done by replacing Fold with FoldList, so that the return value of the program becomes the sequence of bucket states traversed during program execution. Un-golfed version:

J[A_,B_][prog_] :=
FoldList[                (* debug version                                             *)
Switch[{a,b}=#;        (* initialize a and b to the current bucket contents         *)
#2,             (* switch as a function of the next character in the program *)
"f", {A,b},          (* f: fill first bucket, leave second bucket unchanged       *)
"F", {a,B},          (* F: fill second bucket, leave first bucket unchanged       *)
"e", {0,b},          (* e: empty first bucket, leave second bucket unchanged      *)
"E", {a,0},          (* E: empty second bucket, leave first bucket unchanged      *)
"p", {a,b}+{-1,1}*Min[a,B-b],  (* p: pour first bucket into second bucket         *)
"P", {a,b}+{1,-1}*Min[b,A-a],  (* P: pour second bucket into first bucket         *)
"o", Echo@a;{a,b},   (* o: print contents of first bucket                         *)
"O", Echo@b;{a,b}]&, (* O: print contents of second bucket                        *)
Characters[prog]]      (* fold over the characters in the program string            *)


Try it online!

# Retina 0.8.2, 184 bytes

\d+
$*1, [^FfEePpOo](?=.*$)

{(1+),1*¶((.+¶)f|F)
$1,$1¶$3 ,1*¶((.+¶)e|E) ,¶$2
(1?)(¶\1(1*)1*,\3)¶p
$2$1¶
^((1*)(1?)1*,\2)(¶1+,1*)\3¶P
$1$3$4¶ }s,(1*)(¶(.+¶)o|¶O)(.*) ,$1$3¶$4¶$.1 3A  Try it online! Implements the variant of Bucket specified in the question. For the original version, the ?s can be changed to *s for the same byte count: \d+$*1,
[^FfEePpOo](?=.*$) {(1+),1*¶((.+¶)f|F)$1,$1¶$3
,1*¶((.+¶)e|E)
,¶$2 (1*)(¶\1(1*)1*,\3)¶p$2$1¶ ^((1*)(1*)1*,\2)(¶1+,1*)\3¶P$1$3$4¶
}s,(1*)(¶(.+¶)o|¶O)(.*)
,$1$3¶$4¶$.1
3A


Try it online! Explanation:

\d+
$*1,  Convert the sizes to unary and add separators to provide space for the current values. [^FfEePpOo](?=.*$)


Delete unrecognised commands.

{
}


Loop over the commands.

(1+),1*¶(F|(.+¶)f)
$1,$1¶$3  For f or F, fill the appropriate bucket by copying its size. ,1*¶((.+¶)e|E) ,¶$2


For e or E, empty the appropriate bucket.

(1*)(¶\1(1*)1*,\3)¶p
$2$1¶


For p, pour from the first bucket to the second, taking care not to overflow it. $1 = amount to pour, $3 = amount already in second bucket.

^((1*)(1*)1*,\2)(¶1+,1*)\3¶P
$1$3$4¶  For P, pour from the second bucket to the first, taking care not to overflow it. $2 = amount already in first bucket, $3 = amount to pour. }s,(1*)(¶(.+¶)o|¶O)(.*) ,$1$3¶$4¶$.1  For o or O, convert the appropriate bucket to decimal and append it to the end. 3A  Delete the input at the end of the loop. # Charcoal, 66 bytes ＮθＮηＦ⁺eEＳ≡ιf≔θζF≔ηεe≔⁰ζE≔⁰εpＦ∧ζ‹εη«≦⊖ζ≦⊕ε»PＦ∧η‹ζθ«≦⊖ε≦⊕ζ»o⟦Ｉζ⟧O⟦Ｉε  Try it online! Link is to verbose version of code. Implements the variant of Bucket specified in the question. For the original version, the Ｆs can be changed to Ｗs for the same byte count: ＮθＮηＦ⁺eEＳ≡ιf≔θζF≔ηεe≔⁰ζE≔⁰εpＷ∧ζ‹εη«≦⊖ζ≦⊕ε»PＷ∧η‹ζθ«≦⊖ε≦⊕ζ»o⟦Ｉζ⟧O⟦Ｉε  Try it online! Link is to verbose version of code. Explanation: ＮθＮη  Input the sizes of the buckets. Ｆ⁺eEＳ  Loop over the commands, but prepend eE so that the buckets are in a known state. ≡ι  Switch over the current command. f≔θζ  If f then fill the first bucket. F≔ηε  If F then fill the second bucket. e≔⁰ζ  If e then empty the first bucket. E≔⁰ε  If E then empty the second bucket. pＷ∧ζ‹εη«≦⊖ζ≦⊕ε»  If p then pour a unit from the first bucket to the second until the first becomes empty or the second becomes full. (Interestingly this seems to be the golfiest way to express the concept in Charcoal.) PＷ∧η‹ζθ«≦⊖ε≦⊕ζ»  If P then pour a unit from the second bucket to the first until the second becomes empty or the first becomes full. o⟦Ｉζ⟧  If o then output the first bucket on its own line. O⟦Ｉε  If O then output the second bucket on its own line. (The ⟧ is implicit, as is the skipping of unrecognised characters in the input.) • @JonathanAllan Well, I guess I can change the while (bool) into a for (bool) for the same byte count. – Neil Aug 10 at 19:34 # Stax, 50 bytes ╖z≈]YZîú¬♣↑e█■X▲håR⌐├~@»3é±óè♂╓_§8F|╢╖r╥ë$%6Æ▲¡↓!


Run and debug it

Unpacked and ungolfed it looks like this. You can nearly see some kind of structure in it even if you don't know stax. It loops over the program, and dispatches to a block based on the index of the instruction in the literal "fFeEpPo". Capital O gives an index of -1.

sYdZZF
"fFeEpPo"I
{xs}
{dy}
{Z}
{d0}
{+cyG}
{+cxGs}
{nP}
{Q}
8l@!
}tc~-,


# Python 2, 194 152 bytes

def f(A,B,s,a=0,b=0):
while s:c='fFeEoOpP'.find(s[0]);W='a,b,A,B=b,a,B,A;'*c;exec W+['a=A','a=0','print a','v=min(a,B-b);a-=v;b+=v'][c/2]+';'+W;s=s[1:]


Try it online!

c is even when the command deals with the A bucket (feop) and odd when it deals with the B bucket (FEOP). So W creates a string which, when exec'd, swaps the roles of A and B either an even number of times (i.e., no effect), or an odd number of times (same as a single swap).

This allows the code to only list the commands once instead of twice - if needed, we swap A and B then execute the A based command, and then swap again if needed, to get both A and B functionalities.

# JavaScript (Node.js), 129 bytes

Takes input as ([b, a])(code) where code is a string. Returns an array of output values.

B=>c=>Buffer(c).map(h=j=>(i=j>>5&1,k=j&3)?k>2?o.push(b[i]):b[i]=~-k*B[i]:b[i]&&b[k=i^1]<B[k]&&h(j,b[i]--,b[k]++),b=[0,0],o=[])&&o


Try it online!

### Commented

B => c =>                 // B = [b, a]; c = code string
Buffer(c)               // turn c into a buffer
.map(h = j =>           // for each ASCII code j:
( i = j >> 5 & 1,     //   i = 1 for lower case, 0 for upper case
k = j & 3           //   k = 0 for 'p', 1 for 'e', 2 for 'f', 3 for 'o'
) ?                   //   if k is not 0:
k > 2 ?             //     if k = 3:
o.push(b[i])      //       push b[i] in o[]
:                   //     else:
b[i] = ~-k * B[i] //       set b[i] to B[i] if k = 2, or 0 if k = 1
:                     //   else (k = 0):
b[i] &&             //     if b[i] is not empty
b[k = i ^ 1] < B[k] //     and the other bucket b[k] is not full:
&& h(               //       do recursive calls
j,                //       to pour as much as possible,
b[i]--,           //       decrementing b[i]
b[k]++            //       and incrementing b[k] at each iteration
),                  //