<file_sep>/*******************************************************************************
* File:       main.cpp
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    
*******************************************************************************/
#include <iostream>
#include <queue>
#include "Event.h"
#include "Enums.h"
#include "Circuit.h"
#include "Gate.h"
#include <fstream>
#include <sstream>
#include <cstring>

using namespace Enums;

/**
 * Convert space-delimited string into vector<string>
 * @param {string} line: A space-delimited string to split
 */
std::vector<std::string> stringToVector(std::string line) {
  // Convert string into stringstream
  std::istringstream ss(line);

  // Extract into vector<string>
  std::string token;
  std::vector<std::string> result;
  while (!ss.eof()) {
    token = "";
    ss >> token;
    if (token != "") {
      result.push_back(token);
    }
  }

  return result;
}

void usage() {
  std::cout << "Options:\n-h\tShow usage statement\n-v\tPrint verbose output" 
    << std::endl;
}

int runSimulation(std::string circuitFile, std::string vectorFile, 
  bool verbose) {
  std::ifstream inFS;

  // Parse circuit file
  inFS.open(circuitFile);
  std::string line;

  if (!inFS.is_open()) {
    std::cout << "Unable to open file " << circuitFile << '.' << std::endl;
    return 1;
  }

  // Get first line of file to string
  std::getline(inFS, line);

  // Convert string line into delimited vector
  std::vector<std::string> stringVector = stringToVector(line);

  // If the file starts with CIRCUIT, we have the correct file
  if (stringVector.at(0) != "CIRCUIT") {
    std::cout << "File " << circuitFile << " is not a valid CIRCUIT file." 
      << std::endl;
    return 1;
  }

  std::cout << "Simulating " << circuitFile << "." << std::endl;

  // Declare circuit object
  Circuit circuit;

  // Initialize circuit with name on first line
  circuit = Circuit(stringVector.at(1));

  // Iterate through rest of circuit file, adding wires as appropriate
  while (!inFS.eof()) {

    // Get next line from file
    std::getline(inFS, line);

    // If the line is empty, stop
    if (line.length() == 0) {
      break;
    }

    // Separate line into vector
    stringVector = stringToVector(line);

    // If any exceptions are thrown, skip the line
    try {
      // Handle wire creation
      if (stringVector.at(0) == "INPUT" || stringVector.at(0) == "OUTPUT") {

        // If there are less than two arguments, invalid wire definition
        if (stringVector.size() < 3) {
          throw std::exception();
        }

        std::string wireName = stringVector.at(1);
        int wireNum = std::stoi(stringVector.at(2));

        // Create wire & set its name as defined
        circuit.getWire(wireNum)->setName(wireName);
      }

      // Handle gates
      // Special case: NOT gate only has 1 input
      else if (stringVector.at(0) == "NOT") {

        // If there are less than 4 arguments, invalid gate definition
        if (stringVector.size() < 4) {
          throw std::exception();
        }

        GateType gateType = strToGateType(stringVector.at(0));
        int delay = std::stoi(stringVector.at(1));
        int input1 = std::stoi(stringVector.at(2));
        int output = std::stoi(stringVector.at(3));

      Gate* gate = new Gate(gateType, delay, circuit.getWire(input1), nullptr, 
        circuit.getWire(output));

        circuit.getWire(input1)->setGate(gate);
      }
      else {

        // If there are less than 5 arguments, invalid gate definition
        if (stringVector.size() < 5) {
          throw std::exception();
        }

        GateType gateType = strToGateType(stringVector.at(0));
        int delay = std::stoi(stringVector.at(1));
        int input1 = std::stoi(stringVector.at(2));
        int input2 = std::stoi(stringVector.at(3));
        int output = std::stoi(stringVector.at(4));

        Gate* gate = new Gate(gateType, delay, circuit.getWire(input1), 
          circuit.getWire(input2), circuit.getWire(output));
        circuit.getWire(input1)->setGate(gate);
        circuit.getWire(input2)->setGate(gate);
      }
    }
    // Catch all exceptions caused by bad input file, and ignore them, skipping line
    catch (...) {
      std::cout << "Warning: Invalid wire or gate definition " << line << std::endl;
    }
  }

  // At this point, circuit structure should be complete
  inFS.close();

  if (verbose) {
    // Print finished circuit structure:
    circuit.printSummary();
  }

  // Parse vector file
  inFS.open(vectorFile);

  if (!inFS.is_open()) {
    std::cout << "Unable to open file " << vectorFile << '.' << std::endl;
    return 1;
  }

  // Get first line of file to string
  std::getline(inFS, line);

  // Convert string line into delimited vector
  stringVector = stringToVector(line);

  // If file starts with VECTOR, we have the right vector file
  if (stringVector.at(0) != "VECTOR") {
    std::cout << "File " << vectorFile << " is not a valid VECTOR file." 
      << std::endl;
    return 1;
  }

  // Iterate through rest of VECTOR file, scheduling events as appropriate
  while (!inFS.eof()) {

    // Get next line from file
    std::getline(inFS, line);

    // If the line is empty, stop and skip line
    if (line.length() == 0) {
      break;
    }

    // Separate line into vector
    stringVector = stringToVector(line);

    // Gather event details from vector
    // If there are any exceptions thrown skip line
    try {
      // If there are less than 4 arguments, invalid vector definition
      if (stringVector.size() < 4) {
        throw std::exception();
      }

      Wire* wire = circuit.getWire(stringVector.at(1));
      int time = std::stoi(stringVector.at(2));
      WireValue val = charToWireVal(stringVector.at(3)[0]);


      // Add event to event queue
      // Even though scheduleEvent takes a delay
      // we know that at this point currTime=0
      circuit.scheduleEvent(wire, val, time);
    }
    catch (...) {
      std::cout << "Warning: Invalid vector definition " << line << std::endl;
    }
  }

  // At this point, all events should be in the event queue.
  circuit.processEvents(verbose);
  circuit.printHistory();

  return 0;

}

int main(int argc, char** argv) {

  bool verbose = false;
  // If args provided, parse them
  if (argc >= 2) {
    for (int i = 1; i < argc; i++) {
      // User passed option
      if (argv[i][0] == '-') {
        // Print usage statement
        if (std::strchr(argv[i], 'h') != nullptr) {
          usage();
        }
        // Enable verbose output
        if (std::strchr(argv[i], 'v') != nullptr) {
          verbose = true;
        }
      }
    }
  }

  bool done = false;
  while (!done) {
    std::cout << "Enter the name of the circuit test file (base name only):  ";
    std::string baseName;
    std::cin >> baseName;

    std::string circuitFile = baseName + ".txt";
    std::string vectorFile = baseName + "_v.txt";

    int result = runSimulation(circuitFile, vectorFile, verbose);
    // function returned with error. Attempt to correct circuit name.
    if (result == 1) {
      std::cout << "Let's try again." << std::endl;
    }
    // circuit was processed normally
    else {
      // Loop until valid input
      while (true) {
        std::cout << "Would you like to simulate another circuit? (y/n):  ";
        std::string response;
        std::cin >> response;
        if (response.length() > 0) {
          char letter = tolower(response[0]);
          if (letter == 'n') {
            done = true;
            break;
          }
          if (letter == 'y') {
            break;
          }
        }
        // user didn't say yes or no
        std::cout << "Invalid input" << std::endl;
      }
    }
  }
}
<file_sep>/*******************************************************************************
* File:       Enums.cpp
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    Contains the enumerations needed for Gate type and Wire value, as
*             well as the required helper functions to handle them.
*******************************************************************************/
#pragma once
#include "Enums.h"

using namespace Enums;

/**
 * Convert string input to GateType.
 * Assumes valid input of one of the enums, returns NOT by default.
 */
GateType Enums::strToGateType(std::string str) {
  if (str == "AND") { return GateType::AND; }
  else if (str == "OR") { return GateType::OR; }
  else if (str == "XOR") { return GateType::XOR; }
  else if (str == "NAND") { return GateType::NAND; }
  else if (str == "NOR") { return GateType::NOR; }
  else if (str == "XNOR") { return GateType::XNOR; }
  else { return GateType::NOT; }
}

std::string Enums::gateTypeToStr(GateType type)
{
  if (type == GateType::AND) { return "AND"; }
  else if (type == GateType::OR) { return "OR"; }
  else if (type == GateType::XOR) { return "XOR"; }
  else if (type == GateType::NAND) { return "NAND"; }
  else if (type == GateType::NOR) { return "NOR"; }
  else if (type == GateType::XNOR) { return "XNOR"; }
  else { return "NOT"; }
}

WireValue Enums::charToWireVal(char c) {
  if (c == '0') { return WireValue::OFF; }
  else if (c == '1') { return WireValue::ON; }
  else { return WireValue::X; }
}

char Enums::wireValToChar(WireValue val) {
  switch (val) {
  case WireValue::OFF:
    return '_';
    break;
  case WireValue::ON:
    return '-';
    break;
  case WireValue::X:
  default:
    return 'X';
    break;
  }
}<file_sep>/*******************************************************************************
* File:       Enums.h
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    Contains the enumerations needed for Gate type and Wire value, as
*             well as the required helper functions to handle them.
*******************************************************************************/
#pragma once
#include <string>

/*
* Namespace to hold all the enums
*/
namespace Enums {

  // Represent valid type of logic gate
  enum GateType {
    AND,
    OR,
    XOR,
    NAND,
    NOR,
    XNOR,
    NOT
  };

  // Represent valid gate value
  enum WireValue {
    ON = 1,
    OFF = 0,
    X = -1
  };

  GateType strToGateType(std::string str);
  std::string gateTypeToStr(GateType type);

/**
 * Convert char to WireValue
 * @param {char} c char to convert to WireValue
 * @return {WireValue} WireValue representation of char
 */
  WireValue charToWireVal(char c);

/**
 * Convert WireValue to char
 * @param {WireValue} val WireValue to convert
 * @return {char} char representation of WireValue
 */
  char wireValToChar(WireValue val);
}
<file_sep>/*******************************************************************************
* File:       Event.cpp
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    Represents an event in the circuit simulation. Includes sorting
*             operator for use in priority queue, and print function
*******************************************************************************/
#include "Event.h"

Event::Event(Wire* wire, int time, WireValue value, int count)
  : wire()
{
  this->wire = wire;
  this->time = time;
  this->value = value;
  this->count = count;
}

bool operator<(const Event & e1, const Event & e2)
{
  // Since a priority queue is ordered biggest to smallest, 
  // we want the event with lowest time to return biggest.
  // If events have same time, return first event created.
  if (e1.time == e2.time) {
    return e1.count > e2.count;
  }
  else {
    return e1.time > e2.time;
  }
}

void Event::print() const {
  std::cout << "wire " << wire->getName() << " to " << value << " at " << time 
    << "ms. Event #" << count << std::endl;
}
<file_sep>/*******************************************************************************
* File:       Gate.h
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    Represents a logic gate with a type and Wire inputs and output.
*******************************************************************************/
#pragma once
#include "Enums.h"
using namespace Enums;

class Wire;

class Gate {
public:
  Gate(GateType t, int d, Wire* i1, Wire* i2, Wire* o);
  Wire* getOut() const { return out; }
  int getDelay() const { return delay; }
 
  /**
  * Process what the output of the gate should be given its current inputs
  * @return {WireValue} The value of the gate, used in scheduleEvent()
  */
  WireValue eval();

 /**
  * Process gate output if one of its inputs was changed to provided state
  * Used for calculating future gate output without actually making change
  * @param  {WireValue} state that the input is about to have
  * @param  {Wire*}     input the input that is about to change state
  * @return {WireValue} The value of the gate should the changes be made
  */
  WireValue eval(WireValue state, Wire* input);
  GateType getType() const { return type; }

private:
  WireValue doLogic(WireValue s1, WireValue s2);
  Wire* in1;
  Wire* in2;
  Wire* out;
  GateType type;
  int delay;
};<file_sep>/*******************************************************************************
* File:       Wire.h
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    Represents a logic wire with a hisory of past states and pointers
*             to connected Gates
*******************************************************************************/
#pragma once

#include <vector>
#include <string>
#include <iostream>
#include "Enums.h"

using namespace Enums;

class Gate;

class Wire {
public:
  Wire(std::string name = "");
  WireValue getState() const;
  WireValue getState(int time) const;

 /**
  * Set the state of the wire
  * @param {WireValue} state the value to set wire to
  * @param {int}       time  the time in history the
  * change should be made. Can be equal to or more than
  * current time. If time is equal, it will replace the
  * current history value rather than push_back(state)
  */
  void setState(WireValue state, int time = -1);

  Gate* getGate(int i) const { return output.at(i); }
  void setGate(Gate * g) { output.push_back(g); }
  int getNumGates() const { return (int)output.size(); }

  std::string getName() const { return name; }
  void setName(std::string name) { this->name = name; }

 /**
  * Print the full history of the wire.
  * @param {int} length Desired length of history, if more than actual history.
  * If desired length is greater than history length, it will print the last
  * value in the history to fill the difference
  */
  void printHistory(int length = -1) const;

private:
  std::vector<Gate*> output; // All the gates that the wire drives
  std::vector<WireValue> history; // Full history of wire 
                                  //(including current state)
  std::string name;
};<file_sep>/*******************************************************************************
* File:       Event.h
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    Represents an event in the circuit simulation. Includes sorting
*             operator for use in priority queue, and print function
*******************************************************************************/
#pragma once

#include <iostream>
#include "Enums.h"
#include "Wire.h"
using namespace Enums;

class Event {
public: 
  //ctor
  Event(Wire* wire, int time, WireValue value, int count);
  
  // sort function for use in priority queue
  friend bool operator< (const Event& e1, const Event& e2);

  // debug statement to show event details
  void print() const;

  Wire* getWire() { return wire; }
  WireValue getWireValue() { return value; }
  int getTime() { return time; }

private:
  Wire* wire;
  int time; // in milliseconds
  WireValue value;
  int count; // keep track of order events were created
};<file_sep>/*******************************************************************************
* File:       Circuit.h
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    Reperesents the logic circuit as a collection of Wires, Gates,
*             and Events, and runs the simulation.
*******************************************************************************/
#pragma once
#include <vector>
#include <queue>
#include "Wire.h"
#include "Gate.h"
#include "Event.h"

class Circuit {
public:
  
 /**
  * Constructor
  * @param {string} name (optional) the name of the circuit
  */
  Circuit(std::string name = "");

 /**
  * Get the wire at specified index. 
  * If none exists, create one and return it
  */ 
  Wire* getWire(int index);

 /**
  * Get the wire with a specified name.
  * If none exists, will return nullptr.
  */
  Wire* getWire(std::string name);
  
 /**
  * Add an event to the eventQueue.
  */
  void scheduleEvent(Event e);

/**
  * Add an event to the eventQueue by props
  * Creates new Event based on current "time"
  * @param {int} wireNum the wire being changed
  * @param {WireValue} value the target value
  * @param {int} delay gate delay of event
  */
  void scheduleEvent(Wire* wire, WireValue value, int delay);
  
 /**
  * Iterate through each Event in eventQueue,
  * processing them and causing the affected Gates
  * to generate new Events as needed
  * This function will process until (processDone)
  * or all events are processed
  * @param {bool} verbose whether to print each event while processing
  */
  void processEvents(bool verbose = false);

 /**
  * WARNING: This method is destructive and will empty the event queue.
  * Used for debugging purposes.
  * Prints all the events in the queue.
  */
  void printEvents();

 /**
  * Print the full history of each wire in Circuit.
  * Should be called after processEvents().
  */
  void printHistory() const;

 /**
  * Print summary of Wires and Gates in circuit
  * Used for debugging purposes
  */
  void printSummary() const;

private:
  int currTime;
  int eventCount;
  std::string name;
  void addWire(Wire* w, int index);
  void handleEvent(Event e);
  // Hold the number of milliseconds we have processed
  bool processDone;
  std::vector<Wire*> wireArray;
  std::priority_queue<Event> eventQueue;
};<file_sep>/*******************************************************************************
* File:       Circuit.cpp
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    Reperesents the logic circuit as a collection of Wires, Gates,
*             and Events, and runs the simulation.
*******************************************************************************/
#include "Circuit.h"

Circuit::Circuit(std::string name) 
  : name(name) {
  currTime = 0;
  eventCount = 0;
  processDone = false;
}

Wire* Circuit::getWire(int index) {
  if (wireArray.size() <= index || wireArray.at(index) == nullptr) {
    Wire* newWire = new Wire();
    addWire(newWire, index);
  }
  return wireArray.at(index);
}

Wire* Circuit::getWire(std::string name) {
  for (Wire* wire : wireArray) {
    if (wire != nullptr && wire->getName() == name) {
      return wire;
    }
  }
  return nullptr;
}

void Circuit::addWire(Wire* w, int index) {
  // If wireArray is wrong size, push back with nullptr
  while (wireArray.size() <= index) {
    wireArray.push_back(nullptr);
  }

  // Add wire pointer to array
  wireArray.at(index) = w;
}

void Circuit::scheduleEvent(Event e) {
  eventQueue.push(e);
  eventCount++;
}

void Circuit::scheduleEvent(Wire* wire, WireValue value, int delay) {
  Event e = Event(wire, currTime + delay, value, eventCount);
  scheduleEvent(e);
}

void Circuit::processEvents(bool verbose) {
  while (eventQueue.size() > 0 && !processDone) {
    // Print event details to debug 
    if (verbose) {
      eventQueue.top().print();
    }
    handleEvent(eventQueue.top());
    eventQueue.pop();
  }
}

void Circuit::handleEvent(Event e) {

  WireValue value = e.getWireValue();
  Wire* target = e.getWire();

  // If the event's effects have already happened, ignore the event
  if (target->getState() == value) {
    return;
  }

  // If a scheduled events time is more than 60 ms, stop processing
  if (e.getTime() > 60) {
    processDone = true;
    return;
  }

  // Set current time to event being processed
  currTime = e.getTime();

  // Check if change in wire will change a downstream gate's output
  for (int i = 0; i < target->getNumGates(); i++) {
    Gate* gate = target->getGate(i);

    // Get WireValue as the inputs currently stand
    WireValue currValue = gate->eval();

    // Get wire value if the target input were to change state to value
    WireValue futureValue = gate->eval(value, target);

    // If gate output will change, schedule event to update gate's output
    if (currValue != futureValue) {
      scheduleEvent(gate->getOut(), futureValue, gate->getDelay());
    }
  }
  
  // Use pointer to target wire to peform changes
  target->setState(value, currTime);
}

void Circuit::printEvents() {
  int size = eventQueue.size();
  for (int i = 0; i < size; i++) {
    eventQueue.top().print();
    eventQueue.pop();
  }
}

void Circuit::printHistory() const {
  std::cout << "Circuit name: " << name << std::endl;
  for (Wire* wire : wireArray) {
    // We only want to print the wires that have names
    if (wire != nullptr && wire->getName() != "") {
      std::cout << wire->getName() << ":\t";
      wire->printHistory(currTime + 1);
      std::cout << "\n\n";
    }
  }

  // Print numbers to indicate time
  std::cout << "\t";
  for (int i = 0; i < currTime; i++) {
    if (i % 5 == 0) {
      std::cout << i % 10;
    }
    else {
      std::cout << ' ';
    }
  }

  // always print last history
  std::cout << currTime;
  std::cout << std::endl;
}

void Circuit::printSummary() const {
  std::cout << "Circuit name: " << name << std::endl;
  for (Wire* wire : wireArray) {
    if (wire != nullptr) {
      std::cout << "Wire name: " << wire->getName();
      int numGates = wire->getNumGates();
      std::cout << " Feeds " << numGates << " gates, ";

      // Loop through each gate on the wire, printing its type
      for (int i = 0; i < numGates; i++) {
        Gate* gate = wire->getGate(i);
        std::cout << gateTypeToStr(gate->getType()) << " (" << 
          gate->getDelay() << "ms)";
      }

      std::cout << std::endl;
    }
  }
}<file_sep>/*******************************************************************************
* File:       Wire.cpp
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    Represents a logic wire with a hisory of past states and pointers
*             to connected Gates
*******************************************************************************/
#pragma once

#include "Wire.h"
#include "Gate.h"

Wire::Wire(std::string name) {
  // Set passed in name to name prop
  this->name = name;
  
  // To begin, the wire's value will always be X
  history.push_back(WireValue::X);
}

WireValue Wire::getState() const
{
  // If no history, return unknown as we don't know state yet
  if (history.size() > 0) {
    return history.back();
  }
  else {
    return WireValue::X;
  }
}

WireValue Wire::getState(int time) const
{
  // check if index is valid. If not, call getState();
  if (time < history.size()) {
    return history.at(time);
  }
  else {
    return getState();
  }
}

void Wire::setState(WireValue state, int time) {
  //WireValue prevState = getState();

  // If time == -1, push to end of history
  if (time < 0) {
    history.push_back(state);
  }

  // If time == last index in history, change that
  else if (time == history.size() - 1) {
    history.back() = state;
  }

  // If time >= history.size, push to history
  else if (time >= history.size()) {
    // push back with existing state
    for (int i = history.size(); i < time; i++) {
      history.push_back(history.back());
    }
    // history.size should now == time
    history.push_back(state);
  }
}

void Wire::printHistory(int length) const {
  WireValue val;
  for (int i = 0; i < history.size(); i++) {
    val = history.at(i);
    std::cout << wireValToChar(val);
  }
  // If the desired length is greater than length of history,
  // print the last character enough times to fill the diff
  int historySize = history.size();
  if (historySize < length) {
    for (int i = 0; i < length - historySize; i++) {
      std::cout << wireValToChar(history.back());
    }
  }
}
<file_sep># circuit-simulator
A Digital Logic Circuit simulator

Hey look, I made a change<file_sep>/*******************************************************************************
* File:       Gate.cpp
* Name:       <NAME>, <NAME>
* Date:       4 December 2019
* Assignment: HW6 - Circuit Simulator
* Purpose:    Represents a logic gate with a type and Wire inputs and output
*******************************************************************************/
#pragma once

#include "Gate.h"
#include "Circuit.h"
#include "Wire.h"

Gate::Gate(GateType t, int d, Wire* i1, Wire* i2, Wire* o)
  : type(t), delay(d), in1(i1), in2(i2), out(o) 
{}

WireValue Gate::eval()
{
  // Handle special case of NOT gate
  if (type == GateType::NOT) {
    return doLogic(in1->getState(), WireValue::X);
  }
  return doLogic(in1->getState(), in2->getState());
}

WireValue Gate::eval(WireValue state, Wire *input)
{
  // Handle special case of NOT gate
  if (type == GateType::NOT) {
    return doLogic(state, WireValue::X);
  }
  // Determine which wire is changing, and evaluate what the change would be
  if (input == in1) {
    return doLogic(state, in2->getState());
  }
  else if (input == in2) {
    return doLogic(state, in1->getState());
  }
}

WireValue Gate::doLogic(WireValue in1State, WireValue in2State)
{
  switch (type) {
  case GateType::AND:
    if (in1State == 0 || in2State == 0) {
      return WireValue::OFF;
      break;
    }
    else if (in1State == WireValue::X || in2State == WireValue::X) {
      return WireValue::X;
      break;
    }
    else {
      return WireValue::ON;
      break;
    }
  case GateType::OR:
    if (in1State == 1 || in2State == 1) {
      return WireValue::ON;
      break;
    }
    else if (in1State == -1 || in2State == -1) {
      return WireValue::X;
      break;
    }
    else {
      return WireValue::OFF;
      break;
    }
  case GateType::XOR:
    if (in1State == -1 || in2State == -1) {
      return WireValue::X;
      break;
    }
    else if (in1State == in2State) {
      return WireValue::OFF;
      break;
    }
    else {
      return WireValue::ON;
      break;
    }
  case GateType::NAND:
    if (in1State == 0 || in2State == 0) {
      return WireValue::ON;
      break;
    }
    else if (in1State == WireValue::X || in2State == WireValue::X) {
      return WireValue::X;
      break;
    }
    else {
      return WireValue::OFF;
      break;
    }
  case GateType::NOR:
    if (in1State == 1 || in2State == 1) {
      return WireValue::OFF;
      break;
    }
    else if (in1State == -1 || in2State == -1) {
      return WireValue::X;
      break;
    }
    else {
      return WireValue::ON;
      break;
    }
  case GateType::XNOR:
    if (in1State == -1 || in2State == -1) {
      return WireValue::X;
      break;
    }
    else if (in1State == in2State) {
      return WireValue::ON;
      break;
    }
    else {
      return WireValue::OFF;
      break;
    }
  case GateType::NOT:
    if (in1State == -1) {
      return WireValue::X;
      break;
    }
    else if (in1State == 1) {
      return WireValue::OFF;
      break;
    }
    else {
      return WireValue::ON;
      break;
    }
  }
}
