Bucket interpreter

5

1

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.

Your program should ask for 3 inputs:

  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.

Andrew

Posted 2019-08-10T11:20:31.520

Reputation: 2 067

Thank you very much for requesting implementations of my language! (Although USACO invented it before me) – None – 2019-08-10T12:19:57.510

Oh, in the Bucket spec, pouring more liquid in any bucket than it can hold should output nothing. – None – 2019-08-10T12:46:01.720

Link because the link in the challenge was deleted and there is no description of Bucket. – None – 2019-08-10T13:44:51.177

No problem, A__. I found out about the language today and I thought I'd try it. Surprisingly, it's a good idea. – Andrew – 2019-08-10T13:52:47.167

pouring more liquid in any bucket than it can hold should cause no error -> may we also assume that the program will never try to pour liquid from an empty bucket? – Arnauld – 2019-08-10T16:13:55.933

Assume the program will never try to pour liquid from an empty bucket. If this happens, still no error output. - the second sentence is redundant, if we may assume no such input. – Jonathan Allan – 2019-08-10T17:02:25.973

@Arnauld When you try to pour liquid from an empty bucket, it already fullfills part of the condition "until the former is empty or the latter is full (whichever one happens first)" in the esolangs.org spec. So, the pouring stops. – None – 2019-08-10T18:04:14.623

@A__ The thing is that challenges should be self-contained. – Erik the Outgolfer – 2019-08-10T18:06:02.837

6Some test cases would be nice. – Xcali – 2019-08-10T19:03:47.527

4I'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 – 2019-08-10T19:21:59.207

2I corrected it. Any answers made in the interim period where my spec was wrong are no longer competing. – Andrew – 2019-08-10T21:07:08.980

Close vote retracted. – Jonathan Allan – 2019-08-10T21:18:43.657

Answers

1

Wolfram Language (Mathematica), 212 170 166 164 159 157 155 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                        *)
    {0,0},                 (* start with both buckets empty                             *)
    Characters[prog]]      (* fold over the characters in the program string            *)

Try it online!

Roman

Posted 2019-08-10T11:20:31.520

Reputation: 1 190

1

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!

Xcali

Posted 2019-08-10T11:20:31.520

Reputation: 7 671

1Changed it to match. – Xcali – 2019-08-11T01:06:52.957

0

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
      ),                  //
    b = [0, 0],           //   start with b = [0, 0]
    o = []                //   and initialize o[] to an empty array
  ) && o                  // end of map(); return o[]

Arnauld

Posted 2019-08-10T11:20:31.520

Reputation: 111 334

0

Charcoal, 66 bytes

NθNηF⁺eES≡ιf≔θζF≔ηεe≔⁰ζE≔⁰εpF∧ζ‹εη«≦⊖ζ≦⊕ε»PF∧η‹ζθ«≦⊖ε≦⊕ζ»o⟦Iζ⟧O⟦Iε

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:

NθNηF⁺eES≡ιf≔θζF≔ηεe≔⁰ζE≔⁰εpW∧ζ‹εη«≦⊖ζ≦⊕ε»PW∧η‹ζθ«≦⊖ε≦⊕ζ»o⟦Iζ⟧O⟦Iε

Try it online! Link is to verbose version of code. Explanation:

NθNη

Input the sizes of the buckets.

F⁺eES

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.

pW∧ζ‹εη«≦⊖ζ≦⊕ε»

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.)

PW∧η‹ζθ«≦⊖ε≦⊕ζ»

If P then pour a unit from the second bucket to the first until the second becomes empty or the first becomes full.

o⟦Iζ⟧

If o then output the first bucket on its own line.

O⟦Iε

If O then output the second bucket on its own line. (The is implicit, as is the skipping of unrecognised characters in the input.)

Neil

Posted 2019-08-10T11:20:31.520

Reputation: 95 035

1@JonathanAllan Well, I guess I can change the while (bool) into a for (bool) for the same byte count. – Neil – 2019-08-10T19:34:41.813

0

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.

Neil

Posted 2019-08-10T11:20:31.520

Reputation: 95 035

0

Stax, 50 bytes

╖z≈]Y`Zîú¬♣↑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~-,

recursive

Posted 2019-08-10T11:20:31.520

Reputation: 8 616

0

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.

Chas Brown

Posted 2019-08-10T11:20:31.520

Reputation: 8 959