package main import ( "bufio" "errors" "fmt" "log" "os" "strconv" "strings" ) var currState string var diagAfterSteps, currStep, currPos int var allStates map[string]State var tape map[int]bool func main() { inp := StdinToStrings() tape = make(map[int]bool) allStates = make(map[string]State) // Parse 'Begin' line pts := strings.Split(inp[0], " ") st := pts[len(pts)-1] currState = st[:len(st)-1] pts = strings.Split(inp[1], " ") // Parse 'Diagnostic' line diagAfterSteps = Atoi(pts[5]) // Parse all of the 'state' lines for i := 3; i < len(inp); i += 10 { if state, err := NewState(inp[i:]); err == nil { allStates[state.Name] = state } } fmt.Println("Beginning in State", currState) fmt.Println("Diagnostic After", diagAfterSteps) for i := 0; i < diagAfterSteps; i++ { //fmt.Printf("Steps: %d; State %s; Diag: %d; Tape: %s\n", i, currState, RunDiagnostic(), GetTapeString()) currState = allStates[currState].Process() } fmt.Println("Diagnostic Checksum:", RunDiagnostic()) } func GetTapeString() string { ret := "[ " min, max := 0, 0 for k := range tape { if k < min { min = k } if k > max { max = k } } for i := min; i < max; i++ { ret += fmt.Sprint("(", i, tape[i], ") ") } return ret + "]" } func RunDiagnostic() int { var chk int for _, v := range tape { if v { chk++ } } return chk } type State struct { Name string State1Ins Instruction State0Ins Instruction } // NewState takes a slice of strings and returns a state built from the _next_ description found func NewState(inp []string) (State, error) { if len(inp) < 9 { return State{}, errors.New("Invalid state instructions") } ret := State{} // The first line should have the state name ln := inp[0] ret.Name = ln[len(ln)-2 : len(ln)-1] ret.State0Ins = NewInstruction(inp[2:5]) ret.State1Ins = NewInstruction(inp[6:9]) return ret, nil } // Process makes the needed changes to the tape and returns the // next state func (s State) Process() string { ins := s.State0Ins if tape[currPos] { ins = s.State1Ins } tape[currPos] = ins.WriteValue currPos += ins.Move return ins.NextState } type Instruction struct { WriteValue bool Move int NextState string } func NewInstruction(inp []string) Instruction { ret := Instruction{} tmp := strings.Split(strings.TrimSpace(inp[0]), " ") ret.WriteValue = (tmp[4][len(tmp[4])-2] == '1') tmp = strings.Split(strings.TrimSpace(inp[1]), " ") ret.Move = 1 if tmp[6] == "left." { ret.Move = -1 } tmp = strings.Split(strings.TrimSpace(inp[2]), " ") state := tmp[len(tmp)-1] ret.NextState = state[len(state)-2 : len(state)-1] return ret } func Atoi(i string) int { var ret int var err error if ret, err = strconv.Atoi(i); err != nil { log.Fatal("Invalid Atoi") } return ret } func StdinToStrings() []string { var input []string scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { input = append(input, scanner.Text()) } return input }