summaryrefslogtreecommitdiff
path: root/day2.go
diff options
context:
space:
mode:
Diffstat (limited to 'day2.go')
-rw-r--r--day2.go163
1 files changed, 163 insertions, 0 deletions
diff --git a/day2.go b/day2.go
new file mode 100644
index 0000000..3eb3a43
--- /dev/null
+++ b/day2.go
@@ -0,0 +1,163 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "os"
+)
+
+type round struct {
+ opponent shape
+ player shape
+}
+
+type roundOutcome struct {
+ lost int
+ draw int
+ won int
+}
+
+var outcome roundOutcome = roundOutcome{
+ lost: 0,
+ draw: 3,
+ won: 6,
+}
+
+type shape rune
+
+const (
+ opponentRock, playerRock shape = iota + 'A', iota + 'X'
+ opponentPaper, playerPaper
+ opponentScissors, playerScissors
+)
+
+func shapePoints(p shape) int {
+ return int((p - playerRock + 1) * 1)
+}
+
+func loseDrawWin(o shape) (shape, shape, shape) {
+ switch o {
+ case opponentRock:
+ return playerScissors, playerRock, playerPaper
+ case opponentPaper:
+ return playerRock, playerPaper, playerScissors
+ case opponentScissors:
+ return playerPaper, playerScissors, playerRock
+ default:
+ return 0, 0, 0
+ }
+}
+
+func outcomePoints(r round) int {
+ player := int(r.player - playerPaper)
+ opponent := int(r.opponent - opponentPaper)
+ if player == opponent {
+ return 3
+ }
+ if player+opponent == 0 && player < opponent {
+ return 6
+ } else if player+opponent == 0 && player > opponent {
+ return 0
+ }
+ if player < opponent {
+ return 0
+ } else {
+ return 6
+ }
+}
+
+func outcomePointsCheating(p shape) int {
+ switch p {
+ case playerRock:
+ return 0
+ case playerPaper:
+ return 3
+ case playerScissors:
+ return 6
+ default:
+ return 0
+ }
+}
+
+func shapePointsCheating(r round) int {
+ lose, draw, win := loseDrawWin(r.opponent)
+ switch outcomePointsCheating(r.player) {
+ case 0:
+ return shapePoints(lose)
+ case 3:
+ return shapePoints(draw)
+ case 6:
+ return shapePoints(win)
+ default:
+ return 0
+ }
+}
+
+func countRounds(f io.Reader, buf []byte) (int, error) {
+ count := 0
+ for {
+ i, err := f.Read(buf)
+ count += bytes.Count(buf[:i], []byte{'\n'})
+ switch {
+ case err == io.EOF:
+ return count, nil
+ case err != nil:
+ log.Fatal("Error reading input file")
+ return count, err
+ }
+ }
+}
+
+// A very verbose way to read lines into rounds without the bufio package
+func getRounds(f io.Reader, buf []byte, rounds []round) []round {
+ r := 0
+ for {
+ n, err := f.Read(buf)
+ for i := 0; i < n; i += 4 {
+ o := shape(buf[i])
+ p := shape(buf[i+2])
+ if playerRock <= p && p <= playerScissors {
+ rounds[r].player = p
+ }
+ if opponentRock <= o && o <= opponentScissors {
+ rounds[r].opponent = o
+ }
+ if rounds[r].player == 0 || rounds[r].opponent == 0 {
+ rounds[r] = rounds[len(rounds)-1]
+ rounds = rounds[:len(rounds)-1]
+ }
+ r++
+ }
+ if err == io.EOF {
+ return rounds
+ }
+ }
+}
+
+func main() {
+ f, err := os.Open("day2.txt")
+ if err != nil {
+ log.Fatal("could not open input file")
+ }
+ var buf []byte = make([]byte, 32*1024)
+ count, err := countRounds(f, buf)
+ f.Seek(0, 0)
+ var rounds []round = make([]round, count)
+ rounds = getRounds(f, buf, rounds)
+
+ points := 0
+ for _, r := range rounds {
+ points += shapePoints(r.player)
+ points += outcomePoints(r)
+ }
+ fmt.Println("first part: ", points)
+
+ points = 0
+ for _, r := range rounds {
+ points += shapePointsCheating(r)
+ points += outcomePointsCheating(r.player)
+ }
+ fmt.Println("second part: ", points)
+}