package main

import (
	"fmt"
	"strings"
	"strconv"
	"bufio"
	"os"
)

var sendCount [2]int
var chanCount [2]int
func main() {
	inp := StdinToStrings()
	// Part 2
	progAChan := make(chan int, 100000)
	progBChan := make(chan int, 100000)
	go run(inp, 0, progAChan, progBChan)
	run(inp, 1, progBChan, progAChan)
	// Part 1
	//runPart1(inp)
}

var reg [2]map[string]int

func run(inp []string, pId int, input, output chan int) {
	reg[pId] = make(map[string]int)
	// Default register p to the process id
	reg[pId]["p"] = pId

	for i := 0; i >= 0 && i < len(inp); i++ {
		fmt.Println(pId, ":", inp[i])
		pts := strings.Split(inp[i], " ")
		switch(pts[0]) {
		case "snd": send(pId, pts[1], output)
		case "set": setReg(pId, pts[1], pts[2])
		case "add": addReg(pId, pts[1], pts[2])
		case "mul": mulReg(pId, pts[1], pts[2])
		case "mod": modReg(pId, pts[1], pts[2])
		case "rcv": receive(pId, pts[1], input)
		case "jgz": i += jumpIfPos(pId, pts[1], pts[2])
		}
	}
	close(output)
}

func send(pId int, key string, out chan int) {
	sendCount[pId]++
	if pId == 0 {
		chanCount[1]++
	} else {
		chanCount[0]++
	}
	out <- getValue(pId, key)
}

func receive(pId int, key string, in chan int) {
	fmt.Println("SENDS:",sendCount)
	reg[pId][key] = <-in
	chanCount[pId]--
}

/* Part 1 Specifics */
var lastSound int
func runPart1(inp []string) {
	reg[0] = make(map[string]int)
	printRegisters(0)
	for i := 0; i >= 0 && i < len(inp); i++ {
		pts := strings.Split(inp[i], " ")
		switch(pts[0]) {
		case "snd": playSound(0, pts[1])
		case "set": setReg(0, pts[1], pts[2])
		case "add": addReg(0, pts[1], pts[2])
		case "mul": mulReg(0, pts[1], pts[2])
		case "mod": modReg(0, pts[1], pts[2])
		case "rcv": recoverSound(0, pts[1])
		case "jgz": i += jumpIfPos(0, pts[1], pts[2])
		}
	}
}

func playSound(pId int, freq string) {
	lastSound = getValue(pId, freq)
	fmt.Println("*BEEP* (",lastSound,")")
}

func recoverSound(pId int, test string) {
	if getValue(pId, test) != 0 {
		playSound(pId, fmt.Sprint(lastSound))
		os.Exit(0)
	}
}

func setReg(pId int, key string, val string) {
	reg[pId][key] = getValue(pId, val)
}

func addReg(pId int, key string, val string) {
	reg[pId][key] = getValue(pId, key) + getValue(pId, val)
}

func mulReg(pId int, key string, val string) {
	reg[pId][key] = getValue(pId, key) * getValue(pId, val)
}

func modReg(pId int, key string, val string) {
	reg[pId][key] = getValue(pId, key) % getValue(pId, val)
}

func jumpIfPos(pId int, test string, jump string) int {
	var ret int
	if getValue(pId, test) > 0 {
		ret = getValue(pId, jump) - 1
	}
	return ret
}

func getValue(pId int, key string) int {
	var ret int
	var ok bool
	var err error
	if ret, err = strconv.Atoi(key); err != nil {
		// It's not a number
		if ret, ok = reg[pId][key]; !ok {
			// The register is empty
			reg[pId][key] = 0
			ret = 0
		}
	}
	return ret
}

func printRegisters(pId int) {
	fmt.Print(pId,": [ ")
	for i := 0; i < 26; i++ {
		getReg := string('a'+i)
		fmt.Printf("%s:%d ", getReg, getValue(pId, getReg))
	}
	fmt.Print("]\n")
}

func StdinToStrings() []string {
	var input []string
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		input = append(input, scanner.Text())
	}
	return input
}
