Black and white shirts

This puzzle is based on this Math.SE post. A more complex version of this problem can be found over here.

Assume I have some number of black shirts and some number of white shirts, both at least 1. Both colors of shirt have a non-zero durability. All shirts of a given color start with the same durability.

Every day, I pick out a clean shirt to wear, and it becomes dirty. Once I run out of all clean black shirts or all clean white shirts, I wash all my dirty shirts of both colors and start over. Clean shirts do not get washed. Whenever a shirt gets washed, its durability goes down by one. Immediately after washing, if the durability of a shirt reaches 0, it must be thrown out.

When picking which shirt to wear of a particular color, I always choose a shirt with the highest durability of that color to ensure even wear and tear among shirts.

Challenge:

Take in a sequence of two characters of infinite length (eg. b b b w b w w b...) representing my choice of shirt to wear on that day. Continue execution until either my last black shirt or my last white shirt is thrown out. Once this occurs, stop consuming input and halt execution immediately. Note that the program must not consume any more input than is required before halting.

Inputs:

Number of black shirts, number of white shirts, durability of black shirts, durability of white shirts, and an infinite number of two single characters, your choice (eg. b and w)

Note: if your language of choice does not support reading input of an infinite length (i.e. from a stream), assume an input of arbitrary length that is at least long enough for one color of shirt to run out.

Output:

None. The program must simply immediately halt when the last shirt of either color is thrown away.

Note: if your language does not support reading input of infinite length, then instead you should output the number of characters processed.

Test cases:

The following test cases represent the amount of input the program should process before halting. The sequence of w’s and b’s is infinite. The parenthetical afterwards is not part of the input or output, but simply represents the end state of how many shirts of each color have not been thrown out.

1 1 1 1 b
(0 b, 1 w left)

1 999 1 999 b
(0 b, 999 w left)

1 999 1 999 w w w w w w w w b
(0 b, 999 w left)

2 999 1 999 b w w w b
(0 b, 999 w left)

2 999 2 999 b w w w b w b w w w b
(0 b, 999 w left)

5 6 3 1 w w w w w b b b b b b b b b b b b b b w
(5 b, 0 w left)


General rules:

• This is , so shortest answer in bytes wins.
• Default input rules apply for the first four arguments. For the arbitrarily long input sequence after the first four arguments, input must come from a source which can provide input one character or byte at a time, of theoretically infinite length, such as STDIN or some other stream. If your language of choice does not support these features, see above.
• Having to output by ceasing to consume input excludes some languages and complicates testing, but otherwise great first challenge. Perhaps the specification could be amended to allow for a finite input to be slurped, and the number of items processed before running out of shirts of a color output, with the behavior when the shirts don't run out before the end of the list undefined? – Unrelated String Aug 8 at 5:23
• Is the sequence of selected shirts guaranteed to be at least long enough for all of one type of shirt to be thrown out? – attinat Aug 8 at 5:56
• Further to the points raised by Unrelated String and Kevin Cruijssen I think this could be rephrased as a decision problem - "given nBlack, durabilityBlack, nWhite, durabilityWhite, [usage requests] are all the shirts thrown out?" and work quite nicely (allowing easier testing and more languages to partake). – Jonathan Allan Aug 8 at 10:10
• You may find the following links to meta useful. As a rule of thumb, it is recommended to allow flexible I/O and to accept either full programs or functions, without making assumptions about language features (not even that they usually take input from STDIN). The ideas behind that are 1) to allow as many languages as possible and 2) that people can focus on solving the problem rather than dealing with cumbersome I/O formats. – Arnauld Aug 8 at 14:34
• With the halt in the middle of an infinite string and no output, I don't see how the answers can be reliably tested. – Xcali Aug 8 at 22:05

05AB1E, 14 bytes

*Š*‚[ICÓ-W_iõq


Try it online!

Uses p instead of b, because pink is prettier than black.

Explanation:

*             # number of white shirts * durability of white shirts
Š            # swap
*           # number of pink shirts * durability of pink shirts
‚          # pair the two products in a list
[             # infinite loop
I            # get the next input
=           # print (only in the TIO version, not actually needed)
C          # convert from binary (this yields 51 for p and 58 for w, don't ask why)
Ó         # list of exponents in the prime factorization
-        # subtract from the durability list
W_i     # if the minimum of the list is now 0
õq   # exit without printing anything

• The convert from binary/hexadecimal are sometimes so weird when using characters that aren't part of their conversion.. :S – Kevin Cruijssen Aug 9 at 15:49

05AB1E, 28 22 bytes

*U*V[XY*_iõq}©XαUY®≠-V


Inputs are separated by newlines in the order amountOfWhiteShirts, whiteDurability, amountOfBlackShirts, blackDurability, shirtDigits..., where white shirts are 1 and black shirts are 0.

-3 bytes thanks to @Grimy by bringing to my attention that an input of 1/0 instead of "w"/"b" is allowed for the shirts.

Explanation:

*          # Multiply the first two (implicit) input-integers
U         # Pop and store it in variable X
*          # Multiply the next two (implicit) input-integers
V         # Pop and store it in variable Y
[          # Start an infinite loop:
XY*_i  }  #  If either X or Y is 0:
õ    #   Push an empty string, since we don't want any (implicit) output
q   #   And stop the program
©         #  Store the next (implicit) input in variable ® (without popping)
Xα       #  Get it's absolute difference with X (basically X-input)
U      #  Pop and store it as new value for X
®≠       #  Push ® falsified (1→0; 0→1)
Y  -      #  Then subtract it from Y: Y-falsified(®)
V     #  And also pop and store it as new value for Y

• *U*X‚ could be *Š*‚. The challenge allows using arbitrary characters instead of b and w, so 'wQ could be entirely removed (just choose 1 for white and 0 for black). – Grimy Aug 8 at 11:09
• I’ve updated the problem to reinforce the idea that an infinite loop is impossible. – Ed Marty Aug 8 at 11:37
• @Grimy I've removed the second program now that the specs have been improved. Thanks for bringing to my attention that 1/0 is allowed for this shirts, though. – Kevin Cruijssen Aug 8 at 11:54
• 14, using 1 and 2 for white and black: *Š*‚[āIQ-W_iõq (TIO) – Grimy Aug 8 at 12:06
• @Grimy Oh, very nice approach! Love the ā. It looks nothing like my answer though. Maybe it's better if you post it yourself? Apart from the iõq I see nothing of my answer in yours. ;) – Kevin Cruijssen Aug 8 at 12:10

Charcoal, 22 bytes

Ｆ²⊞υ×ＮＮＷ∧⌊υＳ§≔υ℅ι⊖§υ℅ι


Try it online! Link is to verbose version of code. Requires both black shirt values, then both white shirt values, then a stream of b and w characters on separate lines, otherwise behaviour is undefined. On TIO if you don't provide enough shirts you can see Charcoal attempt to prompt for input; if you ran locally then you would be able to continue enter b and w characters until you ran out of shirts at which point the program would exit. Explanation:

Ｆ²⊞υ×ＮＮ


Calculate the lifetimes of each colour of shirt.

Ｗ∧⌊υＳ


Repeat until one colour is exhausted.

§≔υ℅ι⊖§υ℅ι


Reduce the lifetime of a shirt according to the worn colour.

C(tcc), 117116 90 bytes

main(a,b,c,d){scanf("%d%d%d%d",&a,&b,&c,&d);a*=c;for(b*=d;a*b;~c?b-=!c:a--)c=getchar()-2;}


Try it online!

• How can I tell it's working from the link? I think you'd need to use some bash for that, but I have no clue how – Unrelated String Aug 8 at 5:45
• Thank you, you found a problem. I am currently working on it. I believe you do not need bash for testing this program. – A _ Aug 8 at 5:50

C# .NET, 260 bytes

class P{static void Main(string[]a){int b=int.Parse(a[0]);int g=int.Parse(a[1]);int q=g;int r=int.Parse(a[2]);int t=int.Parse(a[3]);int w=t;while(true){if(System.Console.ReadKey().KeyChar<104)q--;else w--;if(q<1){q=g;b--;}if(w<1){w=t;r--;}if(r<1|b<1)return;}}}


No TIO :(
Not the shortest but does the job great!
EDIT: NOTE: uses no spaces in input and (g)reen and (r)ed instead of (b)lack and (w)hite

New contributor
canttalkjustcode is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

Perl 5, 205 bytes

sub f{@s=map[$_>$_[0]?'w':'b',$_>$_[0]?$_[3]:$_[2],1],1..$_[0]+$_[1];while(join('',map$$_[0],@s)=~/bw|wb/){c=&{_[4]};(@w=grep_[2]&&_[0]eqc,@s)[0][2]=0;@s=grep_[2]||++_[2]&&--$$_[1],@s if@w<2}@s}


Try it online!

I assumed that picking the least worn out shirt each day doesn't actually influence the result. Any clean shirt of the chosen color will do. I also think that 2 shirts of durability 5 is the same as 1 shirt of durability 10, so we can simplify this to have just two shirts, one black and one white, but that affects the printed (x b, y w left) result so I didn't go that direction.

Ungolfed:

sub f0 {                                                     #as f() but ungolfed
my($countb,$countw,$durb,$durw,$get_todays_color)=@_; #inputs my @s=( (map{{col=>'b',dur=>$durb,clean=>1}}1..$countb), #init @shirts (map{{col=>'w',dur=>$durw,clean=>1}}1..\$countw) );
while(join("",sort(map$$_{col},@s))=~/bw/){ #while still both colors available my col = &get_todays_color; #todays color my @w = grep _{clean} && _{col} eq col, @s; #wearable shirts my s = (sort{b{dur}<=>a{dur}}@w)[0]; #pick shirt with most durability left for today s{clean}=0; #dirty in the evening map{_{clean}=1;_{dur}--}grep!_{clean},@s if @w==1; #wash if there was only one this morning @s=grep$$_{dur}>0,@s;                                    #toss out worn outs
}
@s                                                         #return not worn out
}


Python 2, 54 bytes

b,w,B,W=input()
l=[B*b,W*w]
while all(l):l[input()]-=1


Try it online!