[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/CSapprenticeWT/OnJava8-Examples/master/enums/VendingMachine.java [Back]  [Original]

// enums/VendingMachine.java
// (c)2021 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// {java VendingMachine VendingMachineInput.txt}
import java.util.*;
import java.io.IOException;
import java.util.function.*;
import java.nio.file.*;
import java.util.stream.*;

enum Category {
  MONEY(Input.NICKEL, Input.DIME,
        Input.QUARTER, Input.DOLLAR),
  ITEM_SELECTION(Input.TOOTHPASTE, Input.CHIPS,
                 Input.SODA, Input.SOAP),
  QUIT_TRANSACTION(Input.ABORT_TRANSACTION),
  SHUT_DOWN(Input.STOP);
  private Input[] values;
  Category(Input... types) { values = types; }
  private static EnumMap categories =
    new EnumMap(Input.class);
  static {
    for(Category c : Category.class.getEnumConstants())
      for(Input type : c.values)
        categories.put(type, c);
  }
  public static Category categorize(Input input) {
    return categories.get(input);
  }
}

public class VendingMachine {
  private static State state = State.RESTING;
  private static int amount = 0;
  private static Input selection = null;
  enum StateDuration { TRANSIENT } // Tagging enum
  enum State {
    RESTING {
      @Override void next(Input input) {
        switch(Category.categorize(input)) {
          case MONEY:
            amount += input.amount();
            state = ADDING_MONEY;
            break;
          case SHUT_DOWN:
            state = TERMINAL;
          default:
        }
      }
    },
    ADDING_MONEY {
      @Override void next(Input input) {
        switch(Category.categorize(input)) {
          case MONEY:
            amount += input.amount();
            break;
          case ITEM_SELECTION:
            selection = input;
            if(amount < selection.amount())
              System.out.println(
                "Insufficient money for " + selection);
            else state = DISPENSING;
            break;
          case QUIT_TRANSACTION:
            state = GIVING_CHANGE;
            break;
          case SHUT_DOWN:
            state = TERMINAL;
          default:
        }
      }
    },
    DISPENSING(StateDuration.TRANSIENT) {
      @Override void next() {
        System.out.println("here is your " + selection);
        amount -= selection.amount();
        state = GIVING_CHANGE;
      }
    },
    GIVING_CHANGE(StateDuration.TRANSIENT) {
      @Override void next() {
        if(amount > 0) {
          System.out.println("Your change: " + amount);
          amount = 0;
        }
        state = RESTING;
      }
    },
    TERMINAL {@Override
    void output() { System.out.println("Halted"); } };
    private boolean isTransient = false;
    State() {}
    State(StateDuration trans) { isTransient = true; }
    void next(Input input) {
      throw new RuntimeException("Only call " +
        "next(Input input) for non-transient states");
    }
    void next() {
      throw new RuntimeException(
        "Only call next() for " +
        "StateDuration.TRANSIENT states");
    }
    void output() { System.out.println(amount); }
  }
  static void run(Supplier gen) {
    while(state != State.TERMINAL) {
      state.next(gen.get());
      while(state.isTransient)
        state.next();
      state.output();
    }
  }
  public static void main(String[] args) {
    Supplier gen = new RandomInputSupplier();
    if(args.length == 1)
      gen = new FileInputSupplier(args[0]);
    run(gen);
  }
}

// For a basic sanity check:
class RandomInputSupplier implements Supplier {
  @Override public Input get() {
    return Input.randomSelection();
  }
}

// Create Inputs from a file of ';'-separated strings:
class FileInputSupplier implements Supplier {
  private Iterator input;
  FileInputSupplier(String fileName) {
    try {
      input = Files.lines(Paths.get(fileName))
        .skip(1) // Skip the comment line
        .flatMap(s -> Arrays.stream(s.split(";")))
        .map(String::trim)
        .collect(Collectors.toList())
        .iterator();
    } catch(IOException e) {
      throw new RuntimeException(e);
    }
  }
  @Override public Input get() {
    if(!input.hasNext())
      return null;
    return Enum.valueOf(
      Input.class, input.next().trim());
  }
}
/* Output:
25
50
75
here is your CHIPS
0
100
200
here is your TOOTHPASTE
0
25
35
Your change: 35
0
25
35
Insufficient money for SODA
35
60
70
75
Insufficient money for SODA
75
Your change: 75
0
Halted
*/

Web Proxy Viewer  |  New URL  |  Original Page