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
}
