From f6a598a55924b507d2ad41ecfe7c657d1a0ef2c5 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sat, 20 Nov 2021 19:17:35 -1000 Subject: [PATCH] Start exercising grow code, breaking the VM --- grow/definition.go | 7 +---- grow/grow.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++ grow/main.go | 4 +-- grow/sample.go | 24 +++++++++++++++++ vm/ophandler.go | 16 ++++++++++-- vm/state.go | 4 +-- 6 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 grow/grow.go create mode 100644 grow/sample.go diff --git a/grow/definition.go b/grow/definition.go index 8d59906..0f048e3 100644 --- a/grow/definition.go +++ b/grow/definition.go @@ -10,12 +10,7 @@ type Definition struct { Samples []*Sample `yaml:"samples"` } -type Sample struct { - GlobalMemoryInputs map[uint64]uint64 `yaml:"global_memory_inputs"` - GlobalMemoryOutputs map[uint64]uint64 `yaml:"global_memory_outputs"` -} - -func loadDefinition(r io.Reader) (*Definition, error) { +func NewDefinition(r io.Reader) (*Definition, error) { dec := yaml.NewDecoder(r) dec.SetStrict(true) diff --git a/grow/grow.go b/grow/grow.go new file mode 100644 index 0000000..2c64435 --- /dev/null +++ b/grow/grow.go @@ -0,0 +1,64 @@ +package main + +import "log" + +import "github.com/firestuff/subcoding/asm" +import "github.com/firestuff/subcoding/gen" +import "github.com/firestuff/subcoding/vm" + +func (def *Definition) Grow() { + high_score := 0 + + log.Print("Starting grow run...") + + // TODO: Score should be number of output criteria, not number of Samples + for high_score < len(def.Samples) { + prog := gen.RandProgram(def.GlobalMemorySize, def.FunctionMemorySize) + + { + src, err := asm.Disassemble(prog) + if err != nil { + log.Fatal(err) + } + + log.Print("Prog:\n%s", src) + } + + score, err := def.Score(prog) + if err != nil { + log.Fatal(err) + } + + if score > high_score { + high_score = score + + src, err := asm.Disassemble(prog) + if err != nil { + log.Fatal(err) + } + + log.Print("New high score %d / %d:\n%s", high_score, len(def.Samples), src) + } + } +} + +func (def *Definition) Score(prog *vm.Program) (int, error) { + score := 0 + + for _, sample := range def.Samples { + state, err := vm.NewState(prog) + if err != nil { + return 0, err + } + + sample.SetInputs(state) + + state.Execute() // ignore error + + if sample.OutputsMatch(state) { + score += 1 + } + } + + return score, nil +} diff --git a/grow/main.go b/grow/main.go index f9c9865..e624faa 100644 --- a/grow/main.go +++ b/grow/main.go @@ -17,10 +17,10 @@ func main() { log.Fatal(err) } - def, err := loadDefinition(defFile) + def, err := NewDefinition(defFile) if err != nil { log.Fatal(err) } - log.Printf("%+v", def) + def.Grow() } diff --git a/grow/sample.go b/grow/sample.go new file mode 100644 index 0000000..a059760 --- /dev/null +++ b/grow/sample.go @@ -0,0 +1,24 @@ +package main + +import "github.com/firestuff/subcoding/vm" + +type Sample struct { + GlobalMemoryInputs map[uint64]uint64 `yaml:"global_memory_inputs"` + GlobalMemoryOutputs map[uint64]uint64 `yaml:"global_memory_outputs"` +} + +func (s *Sample) SetInputs(state *vm.State) { + for i, val := range s.GlobalMemoryInputs { + state.GlobalMemory().WriteUnsigned(i, val) + } +} + +func (s *Sample) OutputsMatch(state *vm.State) bool { + for i, val := range s.GlobalMemoryOutputs { + if state.GlobalMemory().MustReadUnsigned(i) != val { + return false + } + } + + return true +} diff --git a/vm/ophandler.go b/vm/ophandler.go index fe78d12..0d0be00 100644 --- a/vm/ophandler.go +++ b/vm/ophandler.go @@ -73,13 +73,25 @@ func (state *State) handleMultiply(instr *Instruction) { func (state *State) handleDivideUnsigned(instr *Instruction) { in1 := state.readUnsigned(instr.Operands[0]) in2 := state.readUnsigned(instr.Operands[1]) - state.writeUnsigned(instr.Operands[0], in1/in2) + + if in2 == 0 { + // Divide by zero just returns zero + state.writeUnsigned(instr.Operands[0], 0) + } else { + state.writeUnsigned(instr.Operands[0], in1/in2) + } } func (state *State) handleDivideSigned(instr *Instruction) { in1 := state.readSigned(instr.Operands[0]) in2 := state.readSigned(instr.Operands[1]) - state.writeSigned(instr.Operands[0], in1/in2) + + if in2 == 0 { + // Divide by zero just returns zero + state.writeSigned(instr.Operands[0], 0) + } else { + state.writeSigned(instr.Operands[0], in1/in2) + } } func (state *State) handleNot(instr *Instruction) { diff --git a/vm/state.go b/vm/state.go index b6772c6..ee7ec18 100644 --- a/vm/state.go +++ b/vm/state.go @@ -71,11 +71,11 @@ func (state *State) processInstruction() { state.instructionIndex += 1 instr.opHandler(state, instr) - if state.functionIndex >= int64(len(state.program.Functions)) { + if state.functionIndex < 0 || state.functionIndex >= int64(len(state.program.Functions)) { state.ret() } - if state.instructionIndex >= int64(len(fnc.Instructions)) { + if state.instructionIndex < 0 || state.instructionIndex >= int64(len(fnc.Instructions)) { state.ret() } }