Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package main
- import (
- "bufio"
- "fmt"
- "os"
- "regexp"
- "strconv"
- "strings"
- )
- var mostOps = regexp.MustCompile(`(AND|OR|RSHIFT|LSHIFT)`)
- var isInt = regexp.MustCompile(`^[0-9]+$`)
- type Wire struct {
- sig uint16
- op string
- args []string
- }
- type Circuit struct {
- plan map[string]*Wire
- }
- func main() {
- // Declare a new circuit
- c := NewCircuit()
- // Open the input for reading
- f, _ := os.Open(os.Args[1])
- defer f.Close()
- // read and parse the input
- c.ReadInput(f)
- // Evaluate wire "a"
- fmt.Printf("a: %v\n", c.GetSignal("a"))
- }
- func NewCircuit() *Circuit {
- c := new(Circuit)
- c.plan = make(map[string]*Wire)
- return c
- }
- func (c *Circuit) ReadInput(file *os.File) {
- s := bufio.NewScanner(file)
- for s.Scan() {
- w := new(Wire) // Declare a new wire to be added to circuit plan
- // Get wire id and operation
- l := strings.Split(s.Text(), "->")
- op, id := strings.TrimSpace(l[0]), strings.TrimSpace(l[1])
- // break down operation into components
- l = strings.Split(op, " ")
- if mostOps.MatchString(op) { // see mostOps regex at the to to see what matches
- w.op = l[1]
- w.args = append(w.args, l[0], l[2])
- } else if len(l) == 1 { // direct assign, if it's a number then assign to the wire's signal
- if isInt.MatchString(l[0]) {
- v, _ := strconv.ParseInt(l[0], 10, 16) // Convert value to 16bit int
- w.sig = uint16(v)
- } else { // Other wise assign to the arguments so it can be evaluated later
- w.args = append(w.args, l[0])
- }
- } else { // Last possible option is that it's a NOT operation
- w.op = l[0]
- w.args = append(w.args, l[1])
- }
- // Assign the parsed wire to the circuit plan
- c.plan[id] = w
- }
- }
- // Recursively evaluate the signal for a given wire
- func (c *Circuit) GetSignal(wire string) uint16 {
- if !c.HasSignal(wire) { // if a wire has no arguments then it has a signal
- args := c.plan[wire].args
- fmt.Printf("\n-->%v [%v, %v]\n", wire, args, c.plan[wire].op)
- // Let's cut to the chase with operation arguments and make them uints that we can pass
- // stright to the operation
- opArgs := make([]uint16, len(args), len(args))
- // evaluate each argument and see if it has a signal
- for i := 0; i < len(args); i++ {
- arg := args[i] // let's make this easier to read
- fmt.Printf("?%v\n", arg)
- if !isInt.MatchString(arg) { // if the arg is not a number it's a wire
- if !c.HasSignal(arg) { // if it has no signal we should get one
- c.plan[arg].sig = c.GetSignal(arg)
- opArgs[i] = c.plan[arg].sig
- fmt.Printf("%v = %v\n", arg, c.plan[arg].sig)
- } else if c.HasSignal(arg) { // if it has a signal we should give it to the args
- opArgs[i] = c.plan[arg].sig
- }
- } else { // otherwise it's just a number so give it to the args
- v, _ := strconv.ParseInt(arg, 10, 16)
- opArgs[i] = uint16(v)
- }
- }
- // Perform the operation now that all requirements are satisfied and clear the args
- // to indicate that this wire is complete.
- c.plan[wire].sig = c.PerformOperation(wire, opArgs)
- c.plan[wire].args = nil
- }
- return c.plan[wire].sig
- }
- func (c *Circuit) PerformOperation(wire string, args []uint16) uint16 {
- var result uint16
- switch c.plan[wire].op {
- case "AND":
- result = args[0] & args[1]
- case "OR":
- result = args[0] | args[1]
- case "LSHIFT":
- result = args[0] << args[1]
- case "RSHIFT":
- result = args[0] >> args[1]
- case "NOT":
- result = ^args[0]
- default:
- result = args[0]
- }
- return result
- }
- func (c *Circuit) HasSignal(w string) bool {
- if len(c.plan[w].args) == 0 {
- return true
- }
- return false
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement