# Help me sell old donuts

You work at a bakery, and every day you make pastries. You make 100 of each of several different types. However customers are less predictable. Some days they order all of one kind of pastry and you run out, some days they order hardly any and you have some left over. So your boss has made up a chart which tells you how many days each type of pastry can last before it's too old and can't be sold anymore. When there are leftover pastries the customers will always buy the freshest pastries first.

As an example lets use donuts, which (according to your boss's chart) can be sold 2 days after they are baked. Lets say you start the week with 0 donuts left over and the following are the orders for 5 days:

Mon Tue Wed Thu Fri
25 75 55 155 215
• On Monday you bake 100 donuts and sell 25, you have 75 left over.
• On Tuesday you bake 100 donuts and sell 75. Since customers prefer fresh donuts, all 75 donuts sold were ones baked on Tuesday. You have 75 still left over from Monday and 25 left over from Tuesday.
• On Wednesday you bake 100 donuts and sell 55. Since 55 is less than 100, all the donuts sold are fresh from that day. The 75 from Monday are now 2 days old and have to be thrown out. You have 25 still left from Tuesday and 45 from Wednesday.
• On Thursday you bake 100 donuts, and get 155 orders. The 100 fresh donuts get sold first, leaving 55 more orders to be filled, you sell all 45 donuts from Wednesday leaving 10 more orders which can be filled with donuts from Tuesday. At the end of the day you have 15 donuts from Tuesday which have to be thrown out.
• On Friday you bake 100 more donuts and get 215 orders. You only have 100 donuts so you only sell 100 donuts.

## Challenge

Your program will take as input the number of days a particular pastry lasts (e.g. 2 for donuts) and the number of orders for that pastry each day over a period of time. The output will be how many pastries will be sold over that period of time.

This is so the goal is to minimize the size of your source code as measured in bytes.

## Test cases

1 [100,100,100] -> 300
1 [372,1920,102] -> 300
1 [25,25,25] -> 75
1 [25,100,120] -> 225
1 [25,100,100,120] -> 325
1 [0,200] -> 200
1 [0,175,75] -> 250
1 [75,150,150] -> 300
1 [0,101,199]-> 201
1 [200,0] -> 100
2 [100,100,100] -> 300
2 [372,1920,102] -> 300
2 [25,25,25] -> 75
2 [25,100,120] -> 245
2 [25,100,100,120] -> 325
2 [0,200] -> 200
2 [0,175,75] -> 250
2 [75,150,150] -> 300
2 [0,101,199]-> 300
2 [200,0] -> 100

• This is a variation of this earlier challenge posted with permission from the original author. Commented Feb 2, 2023 at 15:54
• Did you have trouble getting in contact with the "original author"? Commented Feb 2, 2023 at 15:59
• @mousetail No they are fairly active on the site, plus I know them personally. Commented Feb 2, 2023 at 15:59
• I was gonna CV this until i saw the comments :P Commented Feb 2, 2023 at 16:13
• I still want a bagel. Commented Feb 2, 2023 at 20:09

# Vyxal, 19 bytes

ȧ₁?›(-½:ȧ~+^-Þr)_-∑


# J, 59 bytes

1 :'1#.]<.##&>@{.[:(a(#~u>:])@,1+}.)&.>/@|.\(<a=.100\$0),;/'


Try it online!

Probably not the golfiest possible J approach but I liked the simplicity of it...

Rather than working with numbers that represent pastry count, we use a unary number system, representing every pastry with its own number. For counting available pastires, the number itself is irrelevant (any number = 1 pastry), but we also let the number represent pastry age, so we can use it to filter too-old pastries.

Thus, we seed the reduction with 100 zeroes, representing the first day's fresh pastries.

Now we simply:

• Kill }. n elements where n is the days order
• Add 1 to every number remaining on our list
• Prepend a fresh 100 zeroes to the list
• Filter away numbers that have exceeded the input limit

Finally, we do a scan of the reduction so we have the intermediate results, min those with the input, and sum.

• This is genius, it cut a third off the length of my answer!
– Neil
Commented Feb 3, 2023 at 10:44

# Charcoal, 51 34 bytes

≔⟦⟧ζＦη«Ｆ¹⁰⁰⊞ζθＦιＦ¬¬ζ⊞υ⊟ζ≔⊖Φζκζ»ＩＬυ


Try it online! Link is to verbose version of code. Explanation: Now uses @Jonah's method.

≔⟦⟧ζ


Ｆη«


Loop over the orders.

Ｆ¹⁰⁰⊞ζθ


Bake 100 fresh pastries.

ＦιＦ¬¬ζ⊞υ⊟ζ


For each ordered pastry, try moving the freshest remaining pastry from the shelf to the customer.

≔⊖Φζκζ


Remove the stalest left-overs and decrease the freshness of the remaining left-overs. (This is actually ≔⁻Φζκ¹ζ on TIO because its version of Charcoal can't decrement an empty list and I'm too lazy to switch the links over to ATO where it works.)

»ＩＬυ


Output the final count of sales.

# C (clang), 125 123 121 bytes

s;f(*o,n,d){for(int l[n],a,i,j=s=0;j<n;s-=*o++)for(l[i=j++]=100,s+=*o;~i&&j+~i<=d;*o-=a)l[i--]-=a=fmin(*o,l[i]);o[-n]=s;}


Try it online!

# Go, 169 bytes

func(n int,a[]int)(s int){b:=[]int{100}
for _,q:=range a{x:=0
for i,v:=range b{if i>n{x=0}else if v<q{x=v}else{x=q}
q-=x;s+=x;b[i]-=x}
b=append([]int{100},b...)}
return}


Attempt This Online!

Port of Arnauld's solution.

# JavaScript (ES6), 80 bytes

Expects (days)(orders).

n=>a=>a.map(q=>b=[100,...b].map((v,i)=>(q-=x=i>n?0:v<q?v:q,t+=x,v-x)),b=[t=0])|t


Try it online!

### Commented

n =>             // outer function taking n (number of days)
a =>             // inner function taking a[] (list of orders)
a.map(q =>       // for each number q of orders for each day:
b =            //   update b[], an array keeping track of remaining
//   pastries in reverse chronological order
[100, ...b]    //   create 100 pastries for today
.map((v, i) => //   for each stock value v for today minus i days:
( q -=       //     subtract from q
x =        //     the number x of pastries sold, defined as:
i > n ?    //       if i is greater than n (beyond expiry date):
0        //         nothing
:          //       else:
v < q ?  //         if the stock is less than the orders:
v      //           the entire stock
:        //         else:
q,     //           the remaining number of orders
t += x,    //     add x to the total t
v - x      //     subtract x from v and store this in b[]
)            //     as the remaining stock for this day
),             //   end of inner map()
b = [t = 0]    //   start with t = 0 and b[] = [ 0 ]
) | t            // end of outer map(); return t


# Python, 105 bytes

f=lambda n,d,i=0,x="":d>[]and len((x:=str(i)*100+x)[:d[0]])+f(n,d[1:],i+1,(x+" ")[d[0]:x.find(str(i-n))])


I would be very surprised if this was optimal.

# Wolfram Language (Mathematica), 150 bytes

Since in any case the WL will not be the winner, I allowed myself to be creative to the challenge.
So we start one day in the morning with non-negative array of donuts: $$\[50, 50, 0, 25, …]\$$

First item (here is $$\50\$$) means how many donuts are baked every day. In the original challenge it is constant $$\100\$$. Other items are numbers of donuts leftover from: yesterday, 2 days before etc.
So the length of this array is the shelf life + 1.
The second input is an array of orders.

Last@With[{d=#1[[1]]},Fold[{Prepend[Rest@Most@FoldList[If[#1<0,#1+#2,#2]&,-#2,#1[[1]]]/._?Negative->0,d],#1[[2]]+Min[Total@#1[[1]],#2]}&,{#1,0},#2]]&


So test cases from the original challenge will be looks like:
$$\[100, 0] [372,1920,102]\$$
$$\[100, 0, 0] [372,1920,102]\$$ etc.

Here are some advanced test cases:

Every day we bake 50 donuts, from last day leftover 25 donuts, shelf life is 1 day:
$$\[50, 25] \$$
Orders:
$$\[372,1920,102]\$$
Output: $$\175\$$

Every day we bake 125 donuts, from 2 days before leftover 10 donuts, shelf life is 3 days:
$$\[125, 0, 10, 0] \$$
Orders:
$$\[25,100,100,120]\$$
Output: $$\345\$$

Try it online!

Non-golfed version with named variables:

bakery[donuts_List, orders_List] :=
Last@With[{daily = First@donuts},
Fold[
{Prepend[
Rest@
Most@FoldList[If[#1  0
, daily],
#1[[2]] + Min[Total@#1[[1]], #2]
} &, {donuts, 0}, orders]
];