package main
import (
"bufio"
"fmt"
"log"
"os"
"strconv"
"strings"
)
func main() {
if err := myMain(); err != nil {
log.Println(err)
}
}
func myMain() error {
data, err := parseInput()
if err != nil {
return err
}
first, err := solveFirst(data)
if err != nil {
return err
}
log.Println("Part1:", first)
second, err := solveSecond(data)
if err != nil {
return err
}
log.Println("Part2:", second)
return nil
}
func solveFirst(data []string) (int64, error) {
g, e, err := getGE(data)
if err != nil {
return 0, err
}
gint, err := strconv.ParseInt(g, 2, 64)
if err != nil {
return 0, err
}
eint, err := strconv.ParseInt(e, 2, 64)
if err != nil {
return 0, err
}
return gint * eint, nil
}
func getGE(data []string) (string, string, error) {
gamma := strings.Builder{}
epsilon := strings.Builder{}
var zero, one int
gammaLen := len(data[0])
for j := 0; j < gammaLen; j++ {
for _, line := range data {
switch line[j] {
case '0':
zero++
case '1':
one++
default:
return "", "", fmt.Errorf("invalid binary")
}
}
if one > zero {
gamma.WriteByte('1')
epsilon.WriteByte('0')
} else {
gamma.WriteByte('0')
epsilon.WriteByte('1')
}
zero, one = 0, 0
}
return gamma.String(), epsilon.String(), nil
}
func solveSecond(data []string) (int64, error) {
ogr, err := strconv.ParseInt(OGR(data), 2, 64)
if err != nil {
return 0, err
}
cgr, err := strconv.ParseInt(CGR(data), 2, 64)
if err != nil {
return 0, err
}
return ogr * cgr, nil
}
func getCommon(data []string, col int) (int, int) {
zero, one := 0, 0
for _, line := range data {
switch line[col] {
case '0':
zero++
case '1':
one++
}
}
return zero, one
}
func bitCriteria(zero, one int, t string) byte {
switch t {
case "oxigen":
if zero > one {
return '0'
} else {
return '1'
}
case "CO2":
if zero > one {
return '1'
} else {
return '0'
}
default:
panic("unreachable")
}
}
func OGR(data []string) string {
for k := 0; k < len(data[0]); k++ {
next := getOxCO2(data, k, "oxigen")
if len(next) == 1 {
return next[0]
}
data = next
}
return "OGR SZOPÓ"
}
func CGR(data []string) string {
for k := 0; k < len(data[0]); k++ {
next := getOxCO2(data, k, "CO2")
if len(next) == 1 {
return next[0]
}
data = next
}
return "CGR SZOPÓ"
}
func getOxCO2(data []string, k int, kind string) []string {
var nextData []string
zero, one := getCommon(data, k)
for _, line := range data {
if line[k] == bitCriteria(zero, one, kind) {
nextData = append(nextData, line)
}
}
return nextData
}
func parseInput() ([]string, error) {
fd, err := os.Open("input.txt")
if err != nil {
return nil, err
}
defer fd.Close()
buf := bufio.NewScanner(fd)
var ret []string
for buf.Scan() {
ret = append(ret, buf.Text())
}
return ret, nil
}