Black and white shirt 2

2

This is a more complicated version of this puzzle. The premise is the same but a few rules differ in a few key places, making for a more complex problem.

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 specify whether I choose a shirt with highest (h) or lowest (l) remaining durability.

Challenge:

Take in an arbitrarily long sequence of four indicators (eg. bh bh bl wl bl wh wl bh...) 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 print out the remaining shirts’ durabilities.

Inputs:

Number of black shirts, number of white shirts, durability of black shirts, durability of white shirts, and a sequence of shirt selections of arbitrary length at least long enough for one color of shirt to run out (can be considered infinitely long). The selection can be represented by a character pair (eg. bh, bl, wh, wl), or a single character (eg. b, B, w, W). Your choice, as long as there are four distinct inputs of 1 or 2 characters.

Output:

Status of each remaining shirt, sorted by durability. All shirts will be of one color.

Test cases:

The following test cases represent the amount of input the program should need to process before halting. The input is arbitrarily long otherwise.

1 1 1 1 bh
1

1 3 1 10 wh bh
10 10 9

1 5 2 10 wh wh bh wl wl wl bh
10 10 9 8 8

2 5 1 10 bh wh wh wl bl
10 10 9 9 9

1 5 6 5 wl wh bl wl wh bl wl wh bl wl wl bl wl wl wl bl wl wl wl wl bl
4 3 2 1

1 1 1 10 bl wh wh wh wh wh wh wh wh wh wh wh wh
10
#note the processing would stop occurring after the first bl and everything else should be ignored.

General rules:

  • This is , so shortest answer in bytes wins.
  • Default I/O rules apply

Ed Marty

Posted 2019-08-08T12:31:00.263

Reputation: 265

2

Since no one had suggested it yet in your first challenge, it might be a good idea to start using the Sandbox. There you can perfect a challenge and answer questions from users, making modifications where necessary, before posting them to main. Not that anything is wrong with this challenge, since it seems clear to me now that I understand the first challenge. But it's usually still a good idea to use the Sandbox for any new challenge imho, since you might always overlook some edge-cases or unclarities.

– Kevin Cruijssen – 2019-08-08T13:10:22.227

I did post the first challenge in the sandbox, but I got no responses after about a day. How long should I normally need to wait? – Ed Marty – 2019-08-08T13:16:17.507

4

Typically you want to wait around 48 hours; I sometimes leave challenges there for a week but that's for more complex ones. You can also advertise sandbox challenges in the site chat here before posting for more final feedback -- usually gets me some feedback.

– HyperNeutrino – 2019-08-08T13:17:20.487

1I usually leave challenges for a week no matter what kind of challenge it is; It is simpler and works for all challenges. Also, even for simple challenges, there might be many problems with them. – None – 2019-08-08T13:25:27.237

2

I did post feedback on your Sandbox question, but you posted it without addressing it.

– Jo King – 2019-08-08T22:38:33.757

Answers

1

Perl 5, 254 bytes

sub f{@s=map[$_>$_[0]||0,$_>$_[0]?$_[3]:$_[2],1],1..$_[0]+$_[1];while(join('',map$$_[0],@s)=~/01|10/){($c,$p)=&{$_[4]};(@w=sort{$p*($$b[1]<=>$$a[1])}grep$$_[2]&&$$_[0]eq$c,@s)[0][2]=0;@s=grep$$_[2]||++$$_[2]&&--$$_[1],@s if@w<2}sort{$b<=>$a}map$$_[1],@s}

Try it online!

Ungolfed but same – with tests:

use Test::More tests=>6;
sub fu {
  my($countb,$countw,$durb,$durw,$get_todays)=@_;            #get 5 inputs
  my @s=( (map{{col=>'b',dur=>$durb,clean=>1}}1..$countb),   #init shirts array
          (map{{col=>'w',dur=>$durw,clean=>1}}1..$countw) );
  while(join('',map$$_{col},@s)=~/bw|wb/){                   #while still both colors left
    my($col,$p) = &$get_todays;                              #todays color and preference
    my @w = grep $$_{clean} && $$_{col} eq $col, @s;         #@w=wearable shirts
    my $shirt = (sort{$p*($$b{dur}<=>$$a{dur})}@w)[0];       #pick todays shirt w/most|least durability left 
    $$shirt{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
  }
  return sort{$b<=>$a}map$$_{dur},@s
}
my @test=(
'1 1 1 1 bh',                                                             '1',
'1 3 1 10 wh bh',                                                         '10 10 9',
'1 5 2 10 wh wh bh wl wl wl bh',                                          '10 10 9 8 8',
'2 5 1 10 bh wh wh wl bl',                                                '10 10 9 9 9',
'1 5 6 5 wl wh bl wl wh bl wl wh bl wl wl bl wl wl wl bl wl wl wl wl bl', '4 3 2 1',
'1 1 1 10 bl wh wh wh wh wh wh wh wh wh wh wh wh',                        '10'  #should see sequence not empty
);
while(@test){
  my($countb,$countw,$durb,$durw,@col)=split' ',shift@test;
  my @expected                        =split' ',shift@test;
  my $msg='';
  my $feederu=sub{ (shift(@col)//do{@expected='!',$msg='sequence ran out!'})
                   =~/(.)(.)/;($1,{h=>1,l=>-1}->{$2}) };
  my $feeder=sub{ (shift(@col)//do{@expected='!',$msg='sequence ran out!'})
                   =~/(.)(.)/;($1 eq 'w'||0,{h=>1,l=>-1}->{$2}) };
  my @got=fu($countb,$countw,$durb,$durw,$feederu);
 #my @got=f($countb,$countw,$durb,$durw,$feeder);
  $msg='sequense not empty' if @col;
  is(join(" ",@got),
     join(" ",@expected), $msg);
}

Kjetil S.

Posted 2019-08-08T12:31:00.263

Reputation: 1 049