package main

import (
	"AoC2020/helper"
	"fmt"
	"os"
	"strconv"
	"strings"
)

var band []string
var pointer int
var accumulator int
var result int
var terminated bool


func main() {
	args := os.Args[1:]
	input, err := helper.GetInput(args[0])
	if err != nil {
		fmt.Println(err)
	}
	runMachine(input)
	fmt.Println(result)
	part2(input)
}

func part2(input []string) {
	for i,_ := range input {
		if strings.Fields(input[i])[0] == "nop" {
			changedInput := make([]string, len(input))
			copy(changedInput,input)
			changedInput[i] = strings.Replace(band[i],"nop","jmp",-1)
			runMachine(changedInput)
		}
		if strings.Fields(input[i])[0] == "jmp" {
			changedInput := make([]string, len(input))
			copy(changedInput,input)
			changedInput[i] = strings.Replace(band[i],"jmp","nop",-1)
			runMachine(changedInput)
		}
		if terminated == true {
			fmt.Printf("Change value at: %d \n", i)
			fmt.Printf("Accumulator: %d", result)
		}
	}
}

func runMachine(input []string) {
	pointer = 0
	result = 0
	accumulator = 0
	band = input
	var visitedPointer []bool = make([]bool, len(band))
	for i := 0; i < len(band); i++ {
		visitedPointer[i] = false
	}
	for result == 0 {
		terminated = run(visitedPointer)
	}
}

func run(visitedPointer []bool) bool {
	if pointer == len(band) {
		result = accumulator
		return true
	}
	if visitedPointer[pointer]  {
		result = accumulator
		return false
	} else {
		visitedPointer[pointer] = true
	}
	command := strings.Fields(band[pointer])
	number, _ := strconv.Atoi(command[1])
	if command[0] == "acc"{
		acc(number)
	}
	if command[0] == "jmp"{
		jmp(number)
	}
	if command[0] == "nop"{
		nop()
	}
	return false
}

func nop() {
	pointer++
}

func acc(number int) {
	accumulator += number
	pointer++
}

func jmp(number int) {
	pointer += number
}


