1 #!/usr/bin/perl -w
2
3 # Perl script that implements the Lambda Lounge Vending Machine Specification
4 # Tom Wheeler: Mon Apr 6 22:12:27 CDT 2009
5
6 use strict;
7
8 my $money_in = 0;
9
10 # current stock of items for sale
11 my %item_count = (
12 'a' => 10, 'b' => 10, 'c' => 10,
13 );
14
15 my %item_value = (
16 'a' => 65, 'b' => 100, 'c' => 150,
17 );
18
19 # current stock of various coins
20 my %coin_count = (
21 'nickel' => 10, 'dime' => 10, 'quarter' => 10, 'dollar' => 10,
22 );
23
24 my %coin_value = (
25 'nickel' => 5, 'dime' => 10, 'quarter' => 25, 'dollar' => 100,
26 );
27
28 prompt();
29 while (chomp(my $input = <>)) {
30 if ($input =~ /^EXIT$/i) { exit; }
31 elsif ($input =~ /^NICKEL$/i) { insert('nickel'); }
32 elsif ($input =~ /^DIME$/i) { insert('dime'); }
33 elsif ($input =~ /^QUARTER$/i) { insert('quarter'); }
34 elsif ($input =~ /^DOLLAR$/i) { insert('dollar'); }
35 elsif ($input =~ /^GET-A$/i) { sell('a'); }
36 elsif ($input =~ /^GET-B$/i) { sell('b'); }
37 elsif ($input =~ /^GET-C$/i) { sell('c'); }
38 elsif ($input =~ /^COIN RETURN$/i) { coin_return(); }
39 elsif ($input =~ /^SERVICE$/i) { service(); }
40 else {
41 print "\tIgnoring unrecognized command '$input'\n";
42 }
43
44 prompt();
45 }
46
47 sub prompt {
48 print "> ";
49 }
50
51 sub insert {
52 my $coin = shift;
53 my $value = $coin_value{$coin};
54
55 $money_in += $value;
56 $coin_count{$coin} = $coin_count{$coin} + 1;
57
58 my $count = $coin_count{$coin};
59 print "\t$coin (value: $value cents) accepted; credit: $money_in cents\n";
60 }
61
62 sub sell {
63 my $item = shift;
64
65 my $count = $item_count{$item};
66 if ($count <= 0) {
67 print "\tSorry, we're out of stock on item '$item'\n";
68 return;
69 }
70
71 my $value = $item_value{$item};
72 if ($value > $money_in) {
73 my $shortage = $value - $money_in;
74 print "\tSorry, that costs $value. Insert $shortage cents, please.\n";
75 return;
76 }
77
78 $item_count{$item} = $item_count{$item} - 1;
79 $money_in = $money_in - $value;
80
81 print "\tSold item '" . uc($item) . "' for $value cents; returning change\n";
82 coin_return();
83 }
84
85 sub coin_return {
86 # sort coins by descending order of value
87 my @sorted_coins = sort {
88 $coin_value{$b} <=> $coin_value{$a};
89 } keys %coin_count;
90
91 foreach my $coin(@sorted_coins) {
92 my $coin_value = $coin_value{$coin};
93 next if $money_in < $coin_value;
94
95 my $num_coins = int($money_in / $coin_value);
96 my $count = $coin_count{$coin};
97 $num_coins = $count if $num_coins > $count;
98
99 $coin_count{$coin} = $count - $num_coins;
100 $money_in = $money_in - $num_coins * $coin_value;
101
102 print "\tReturned $num_coins " . uc($coin) . "s\n";
103 }
104
105 if ($money_in) {
106 print "\tInsufficient change: You have a credit of $money_in cents\n";
107 }
108 }
109
110 sub service {
111 print "\tEntering machine service mode\n";
112
113 print "\tCoins\n";
114 add_coins_or_items(\%coin_count);
115
116 print "\tItems\n";
117 add_coins_or_items(\%item_count);
118
119 print "\tExiting machine service mode\n";
120 }
121
122 sub add_coins_or_items {
123 my $hash_ref = shift;
124 my %hash = %$hash_ref;
125
126 print "\n";
127 foreach my $thing(keys %hash) {
128 my $count = $hash{$thing};
129 print "\tHow many " . uc($thing) . "s to add (there are now $count)?\n";
130 prompt();
131 my $line = <STDIN>;
132
133 last if $line =~ /END/i;
134 unless ($line && $line =~ /^[0-9]+$/) {
135 print "Ignoring invalid input\n";
136 next;
137 }
138
139 my $num_to_add = int($line);
140 next unless $num_to_add > 0;
141
142 $hash{$thing} = $count + $num_to_add;
143 }
144
145 show_counts(\%hash);
146 }
147
148 sub show_counts {
149 my $hash_ref = shift;
150 my %hash = %$hash_ref;
151
152 foreach my $thing(keys %hash) {
153 my $count = $hash{$thing};
154 print "\tThere are currently $count of '" . uc($thing) . "'\n";
155 }
156 }
syntax highlighted by Code2HTML, v. 0.9.1