Black Friday Queue Managment

10

0

Introduction

You are the manager of the electronics department in a major retail store and the biggest sales day of the year is this Friday. To help manage the crowds, your store is implementing a ticket system for the biggest deals, where customers must present a ticket before purchasing an item. Your job is to write a program to validate the tickets.

Since the only available computer in the store (due to budget cuts) is a dinosaur with a broken keyboard, (and all you have is USB keyboards, which aren't compatible) you'll have to input your program with a mouse. Therefore, your program should be as short as possible.

Products

You store is running sales on the five different products listed below. Each product has an all lowercase name and different rules on how many can be purchased and at what time of day.

  • television: There are 5 flat-screen televisions in stock that may be purchased from 00:00:00 (midnight) to 00:59:59.
  • smartphone: There are 10 smartphones in stock, but any customer in line from 00:00:00 (midnight) to 00:59:59 receives a voucher for one once they run out.
  • tablet: There are 10 tablets that may be purchased at anytime.
  • laptop: There are an unlimited number of laptops that may be purchased from 00:00:00 (midnight) to 07:59:59.
  • lightbulb: There are an unlimited number of light bulbs that may be purchased at anytime.

Input

A multi-line string with each line in the following format. Lines are sorted by the time-stamp.

<time stamp> <product name> <ticket number>
  • The ticket number is 8 digits long. The last digit is a check-digit equal to the sum of the first seven digits modulo 10. To be valid, a ticket number must have the correct check-digit and must be strictly greater than all previous ticket numbers.
  • The product name is one of the string listed above.
  • The time stamp is the time of day in the format HH:MM:SS where HH is the two-digit hour from 00-23, and MM and SS are the two-digit minute and second respectively.

Output

The output is one of the following strings, with one line per ticket. The conditions must be applied in order.

  1. Expired offer (Applies to televisions, smartphones, and laptops.) The time-stamp of the ticket is after the cutoff to buy the product.
  2. Invalid ticket Either the ticket number is less than or equal to the number of the previous ticket, or the check-digit is invalid.
  3. Give voucher (Applies to smartphones.) The product is out of stock, but all the customers in line before the offer expires get a rain check.
  4. Out of stock (Applies to televisions and tablets.) All of the product has been sold. Sorry, quantity was limited.
  5. Accepted All conditions are met, so give them the product. Note that only accepted tickets reduce the number of items in stock.

Example

Input                           Output
----------------------------    --------------
00:00:00 television 00010001    Accepted
00:00:25 smartphone 00011697    Accepted
00:01:25 laptop 00030238        Accepted
00:02:11 smartphone 00037291    Accepted
00:02:37 lightbulb 00073469     Invalid ticket
00:03:54 smartphone 00096319    Accepted
00:05:26 tablet 00152514        Accepted
00:06:21 tablet 00169893        Accepted
00:07:10 television 00190268    Accepted
00:07:47 smartphone 00194486    Accepted
00:07:55 tablet 00220071        Accepted
00:08:20 lightbulb 00321332     Accepted
00:10:01 smartphone 00409867    Accepted
00:11:10 tablet 00394210        Invalid ticket
00:11:46 television 00581060    Accepted
00:12:44 lightbulb 00606327     Accepted
00:13:16 tablet 00709253        Accepted
00:13:53 television 00801874    Accepted
00:14:47 laptop 00832058        Accepted
00:15:34 smartphone 00963682    Accepted
00:16:24 smartphone 01050275    Accepted
00:17:45 tablet 01117167        Accepted
00:18:05 laptop 01107548        Invalid ticket
00:19:00 lightbulb 01107605     Invalid ticket
00:19:47 lightbulb 01492983     Accepted
00:19:50 smartphone 01561609    Accepted
00:21:09 television 01567098    Accepted
00:21:42 laptop 01597046        Accepted
00:22:17 smartphone 01666313    Accepted
00:24:12 tablet 01924859        Accepted
00:24:12 smartphone 02151571    Accepted
00:25:38 smartphone 02428286    Give voucher
00:31:58 television 02435284    Out of stock
00:35:25 television 02435295    Out of stock
00:52:43 laptop 02657911        Invalid ticket
00:53:55 smartphone 02695990    Give voucher
01:08:19 tablet 02767103        Accepted
01:34:03 television 02834850    Expired offer
01:56:46 laptop 02896263        Accepted
02:02:41 smartphone 03028788    Expired offer
02:30:59 television 03142550    Expired offer
02:51:23 tablet 03428805        Accepted
03:14:57 smartphone 03602315    Expired offer
03:27:12 television 03739585    Expired offer
03:56:52 smartphone 03997615    Expired offer
04:07:52 tablet 04149301        Accepted
04:12:05 lightbulb 04300460     Invalid ticket
04:24:21 laptop 04389172        Accepted
04:40:23 lightbulb 04814175     Accepted
04:40:55 tablet 04817853        Accepted
04:42:18 smartphone 04927332    Expired offer
05:06:43 tablet 05079393        Out of stock
05:16:48 tablet 05513150        Out of stock
05:33:02 television 05760312    Expired offer
05:43:32 tablet 06037905        Out of stock
06:12:48 smartphone 06440172    Expired offer
06:35:25 laptop 06507277        Accepted
06:42:29 lightbulb 06586255     Invalid ticket
06:55:31 lightbulb 06905583     Accepted
06:55:33 lightbulb 06905583     Invalid ticket
07:40:05 smartphone 07428006    Expired offer
07:49:12 television 07588086    Expired offer
08:14:56 laptop 08111865        Expired offer

I have tried to make the example cover every possible output scenario, but please leave a comment if anything is unclear.

This is , you may write a program or function, and standard loop-holes are disallowed.

intrepidcoder

Posted 2015-11-25T21:51:09.487

Reputation: 2 575

Answers

5

Javascript(ES6), 396 433 419 bytes

h=0;f=1/0;i={television:{c:5,s:0,e:1},smartphone:{c:10,s:0,e:1,v:1},tablet:{c:10,s:0,e:24},laptop:{c:f,s:0,e:8},lightbulb:{c:f,s:0,e:24}};while(1){t=prompt().split(' ');a=t[0];r=a[0]+a[1]-0;o=i[t[1]];m=0;z='Accepted';u=t[2]-0;u<=h||(u-u%10+'').split('').reduce((p,c)=>-(-p-c))%10!=u%10?m='Invalid ticket':0;r<o.s||r>=o.e?m='Expired offer':0;if(!m)o.c?o.c--:(o.v?z='Give voucher':m='Out of stock');!m?h=u:0;alert(m?m:z)}

Edit: Reduced size by using es6 big arrow function

More readable:

h=0
f=1/0
i={television:{c:5,s:0,e:1},smartphone:{c:10,s:0,e:1,v:1},tablet:{c:10,s:0,e:24},laptop:{c:f,s:0,e:8},lightbulb:{c:f,s:0,e:24}}
while(1){t=prompt().split(' ')
a=t[0]
r=a[0]+a[1]-0
o=i[t[1]]
m=0
z='Accepted'
u=t[2]
if(u<=h||(u-u%10+'').split('').reduce(function(p,c){return-(-p-c)})%10!=u%10)m='Invalid ticket'
if(r<o.s||r>=o.e)m='Expired offer'
if(!m){if(o.c)o.c--
else o.v?z='Give voucher':m='Out of stock'}if(!m)h=u
alert(m?m:z)}

Interestingly the longer code is faster: http://jsperf.com/compare-read

GUI with same logic:

var app = angular.module('app', []);

app.controller('MainCtrl', function MainCtrl ($scope) {
  $scope.items = {
    television: {c: 5, s:0, e: 1},
    smartphone: {c: 10, s:0, e: 1},
    tablet: {c:10, s:0, e: 24},
    laptop: {c:Infinity, s: 0, e: 8},
    lightbulb: {c: Infinity, s: 0, e: 24},
  };
  
  var h = -1;//highest
  
  $scope.hours_offset = 0;
  
  $scope.ticket = {};
  for (var i = 0; i < 8; i++) $scope.ticket[i] = 0;
  
  $scope.selected_item = -1;
  
  $scope.nums = new Array(10);
  
  $scope.history = [];
  
  $scope.buy = function() {
    
  }
  $scope.selectItem = function($i) {
    $scope.selected_item = $i;
  }
  
  $scope.purchase = function() {
    if ($scope.selected_item === -1)
      return;

    var ticnum = '';
    var msg = 'Accepted';
    
    for(var key in $scope.ticket)
      ticnum+=$scope.ticket[key];
    
    var d = new Date();
    
    //Variable declarations to setup for code like the code I designed for console
    r = d.getHours()-$scope.hours_offset;//hour
    o = $scope.items[$scope.selected_item];//item
    m = 0//msg
    z = 'Accepted'//default_msg
    u=ticnum
    
    //This is copied from my console code
    if(ticnum<=h||(ticnum-ticnum%10+'').split('').reduce(function(p,c){return-(-p-c)})%10!=ticnum%10)m='Invalid ticket'
 if(r<o.s||r>=o.e)m='Expired offer'
 if(!m){if(o.c)o.c--
 else o.v?z='Give voucher':m='Out of stock'}if(!m)h=ticnum
 
    msg = m?m:z;
    
    $scope.history.unshift({
      time: time(d),
      item: $scope.selected_item,
      ticket_num: ticnum,
      message: msg
    });
    
  }
});

function time(date) {
  return padToTwo(date.getHours()) + ':' + padToTwo(date.getMinutes()) + ':' + padToTwo(date.getSeconds());
}
    
function padToTwo(number) {
  return number = ("00"+number).slice(-2);
}
#parent {
  width: 100vw;
  height: 100vh;
  
  padding-bottom: 25vh;
}
#parent > div {
  padding-top: 25vh;
  
  -webkit-display: flex;
  display: flex;
  
  -webkit-flex-direction: row;
  flex-direction: row;
  
  -webkit-align-items: flex-start;
  align-items: flex-start;
  -webkit-justify-content: center;
  justify-content: center;
}

#items {
  width: 15vw;
  min-width: 110px;
  margin-right: 4vw;
  background-color: #222223;
  color: #eeeeef;
  border-radius: 4px;
  border: 2px solid black;
}

#items > span {
  box-sizing: border-box;
  display: block;
  padding: 5px;
  
  -webkit-transition: .2s background-color ease-in-out;
  transition: .2s background-color ease-in-out;
  
  text-align: center;
  
  width: 100%;
  
  border-radius: 4px;
}
#items > span:hover, #ticket p:hover {
  background-color: gray;
}
#items > span.selected, #ticket p.selected {
  background-color: #999999;
}
#ticket {
  -webkit-display: flex;
  display: flex;
  
  -webkit-flex-direction: row;
  flex-direction: row;
  
  margin-right: 4vw;
  
  color: #eeeeef;
}

#ticket p {
  margin: 1px;
  padding: 3px;
  width: 20px;
  text-align: center;
  background-color: #22222f;
  border: 2px solid black;
  border-radius: 3px;
}

#purchase {
  padding: 15px;
  padding-top: 6px;
  padding-bottom: 6px;
  
  background-color: #22222f;
  border: 2px solid black;
  border-radius: 3px;
  color: #eeeeef;
}
#purchase:active {
  background-color: gray;
}

#error {
  margin-top: 15px;
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
<div id="parent" ng-app="app" ng-controller="MainCtrl">
  For testing hours-offset (If it's 6:00 setting this to 18 would simulate it being midnight): <input ng-model="hours_offset" type="number"></input>
  <div>
    <div id="items">
      <span ng-attr-class="{{selected_item===name ? 'selected' : ''}}" ng-repeat="(name, obj) in ::items track by $index" ng-click="selectItem(name)">{{::name}}<br></span>
    </div>
    <div id="ticket">
      <span ng-repeat="(ticket_index, val) in ::ticket">
        <p ng-attr-class="{{ticket[ticket_index]===$index ? 'selected' : ''}}" ng-repeat="nothing in ::nums track by $index" ng-click="ticket[ticket_index] = $index">{{::$index}}</p>
      </span>
    </div>
    <span id="purchase" ng-click="purchase()">Purchase</span>
  </div>
  <div id="error">{{error_msg}}</div>
  <table id="output">
    <tr ng-repeat="item in history track by $index">
      <td ng-repeat="(key, value) in item track by $index">{{value}}</td>
    </tr>
  </span>
</div>

csga5000

Posted 2015-11-25T21:51:09.487

Reputation: 360

Welcome to PPCG. While your GUI is something, the object of code golf is to write the shortest program possible. Since you're using JavaScript, you could take the input string as function parameter and return the output. You should also remove unnecessary whitespace and shorten variable names. Why don't you look at some other questions to get an idea for how the site works? – intrepidcoder – 2015-11-26T02:39:13.353

@intrepidcoder Of course you would minify the code afterwards! But based on the scenario it would seem to me console would be ineffective without a keyboard! – csga5000 – 2015-11-26T02:56:38.850

1

Per the rules outlined in our help center, this post is off topic in its current state. All solutions to challenges should: [...] Be a serious contender for the winning criteria in use. For example, an entry to a code golf contest needs to be golfed[.]

– Dennis – 2015-11-26T03:00:12.143

That was an absurd rational for short code length and had nothing to do with the actual problem. The combined size of your three programs is 4.51 KB. If you don't try to make it smaller, you post will probably be deleted.

– intrepidcoder – 2015-11-26T03:03:52.947

@intrepidcoder Oh yes! I forgot about that, there were a lot of constraints xD. When you say last digit you do you mean the MSB or the LSB? I'm guessing the LSB but I wish to be sure. – csga5000 – 2015-11-27T18:53:09.340

I mean the least-significant digit. E.g. for the 1st invalid example 00073469 is 0+0+0+7+3+4+6 = 20 % 10 = 0 != 9 – intrepidcoder – 2015-11-27T19:34:44.837

@intrepidcoder Great, thanks! See my latest edit. – csga5000 – 2015-11-28T02:35:21.007

Congratulations, this now passes all test cases. +1 I can also give some tips to make this smaller if you'd like. – intrepidcoder – 2015-11-28T03:29:03.890

@intrepidcoder Sure, how can it be shrunk? – csga5000 – 2015-12-01T01:11:05.223

@intrepidcoder Thanks for the edit, it is cleaner now. I believe you typo'd the byte count, I changed it back to 433 (and double checked that was correct using 2 byte counters). – csga5000 – 2015-12-01T01:19:21.610

Usually those are more important. But this is code-golf. :) To start you can use an arrow function, for instead of a while loop, | instead of || (some places). Look at this post for more tips.

– intrepidcoder – 2015-12-01T01:28:16.410

Sorry for accidentally changing the byte count. – intrepidcoder – 2015-12-01T01:29:41.117