Skip to content

Commit

Permalink
Remove joystick input hack and use channels instead
Browse files Browse the repository at this point in the history
  • Loading branch information
nlowe committed Dec 14, 2019
1 parent 8e39fce commit 5616828
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 44 deletions.
67 changes: 38 additions & 29 deletions challenge/day13/b.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ package day13

import (
"fmt"
"math"

"github.com/gdamore/tcell"

"github.com/nlowe/aoc2019/intcode"

"github.com/nlowe/aoc2019/challenge"
"github.com/nlowe/aoc2019/intcode"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

const (
Expand All @@ -26,29 +24,41 @@ var B = &cobra.Command{
},
}

func init() {
flags := B.Flags()

flags.Bool("headless", false, "Run without rendering the game")

if err := viper.BindPFlags(flags); err != nil {
panic(err)
}
}

func b(challenge *challenge.Input) int {
joystick := positionNeutral
cpu, out := intcode.NewCPUForProgram(<-challenge.Lines(), nil)
// This needs to be buffered because the game doesn't read the paddle state
// immediately after rendering the ball (it still wants to render more tiles).
// If we were to block, the render loop wouldn't be able to read more tile data
// and the CPU would deadlock.
joystick := make(chan int, 1)
cpu, out := intcode.NewCPUForProgram(<-challenge.Lines(), joystick)
cpu.Memory[0] = 2

// TODO: Is there a way to keep input and output channels in sync without this hack?
cpu.UseFloatingInput(func() int {
return joystick
})

headless := viper.GetBool("headless")
term, err := tcell.NewScreen()
if err != nil {
panic(err)
}

if err := term.Init(); err != nil {
panic(err)
if !headless {
if err := term.Init(); err != nil {
panic(err)
}
term.DisableMouse()
defer term.Fini()
}
term.DisableMouse()
defer term.Fini()

bx := 0
px := math.MaxInt64
px := 0

term.Clear()
score := 0
Expand All @@ -57,17 +67,17 @@ func b(challenge *challenge.Input) int {
for {
x, ok := <-out
if !ok {
return score
break
}

y, ok := <-out
if !ok {
return score
break
}

tile, ok := <-out
if !ok {
return score
break
}

if x == -1 && y == 0 {
Expand All @@ -78,15 +88,12 @@ func b(challenge *challenge.Input) int {
term.SetContent(x, y, tcell.RuneBlock, nil, tcell.StyleDefault)
case tileBall:
bx = x

if px != math.MaxInt64 {
if bx < px {
joystick = positionLeft
} else if bx > px {
joystick = positionRight
} else {
joystick = positionNeutral
}
if bx < px {
joystick <- positionLeft
} else if bx > px {
joystick <- positionRight
} else {
joystick <- positionNeutral
}

term.SetContent(x, y, '0', nil, tcell.StyleDefault)
Expand All @@ -99,7 +106,9 @@ func b(challenge *challenge.Input) int {
term.SetContent(x, y, ' ', nil, tcell.StyleDefault)
}

term.Show()
if !headless {
term.Show()
}
}
}

Expand Down
11 changes: 2 additions & 9 deletions intcode/cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,11 @@ const (
RAMSize = 8192
)

type floatingInputProvider func() int

type CPU struct {
Memory []int

input <-chan int
output chan<- int
floatingInput floatingInputProvider
input <-chan int
output chan<- int

pc int
relativeOffset int
Expand All @@ -41,10 +38,6 @@ func NewCPUForProgram(program string, inputs <-chan int) (*CPU, <-chan int) {
return &CPU{Memory: memory, input: inputs, output: output}, output
}

func (c *CPU) UseFloatingInput(p floatingInputProvider) {
c.floatingInput = p
}

func (c *CPU) Run() {
for !c.IsHalted() {
c.Step()
Expand Down
11 changes: 5 additions & 6 deletions intcode/microcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ var microcode = map[int]opFunc{
return 1 + instruction.ArgCount(instruction.Mul)
},
instruction.In: func(m3, m2, m1 int, c *CPU) int {
if c.floatingInput != nil {
c.write(m1, 1, c.floatingInput())
return 1 + instruction.ArgCount(instruction.In)
}

select {
case v := <-c.input:
c.write(m1, 1, v)
Expand All @@ -33,7 +28,11 @@ var microcode = map[int]opFunc{
}
},
instruction.Out: func(m3, m2, m1 int, c *CPU) int {
c.output <- c.read(m1, 1)
select {
case c.output <- c.read(m1, 1):
case <-time.After(5 * time.Second):
panic(fmt.Sprintf("blocked on write for 5 seconds %s", c.debugState()))
}
return 1 + instruction.ArgCount(instruction.Out)
},
instruction.JT: func(m3, m2, m1 int, c *CPU) int {
Expand Down

0 comments on commit 5616828

Please sign in to comment.