diff --git a/grow/definition.go b/grow/definition.go index 543c1de..93f8d53 100644 --- a/grow/definition.go +++ b/grow/definition.go @@ -48,7 +48,7 @@ func (def *Definition) Grow(statusChan chan<- Status) (*vm.Program, error) { for { status.Attempts++ - Mutate(prog) + Mutate(def, prog) score, err := def.score(prog) if err != nil { @@ -58,7 +58,7 @@ func (def *Definition) Grow(statusChan chan<- Status) (*vm.Program, error) { if score > status.BestScore { status.BestScore = score - status.BestProgram = prog + status.BestProgram = prog.Copy() if statusChan != nil { statusChan <- status @@ -73,6 +73,7 @@ func (def *Definition) Grow(statusChan chan<- Status) (*vm.Program, error) { return nil, err } + status.BestProgram = prog.Copy() if statusChan != nil { statusChan <- status @@ -142,6 +143,7 @@ func (def *Definition) minifyFunction(prog *vm.Program, f int) error { for i := 0; i < len(prog.Functions[f].Instructions); i++ { origInstructions := prog.Functions[f].Instructions + tmp := make([]*vm.Instruction, len(prog.Functions[f].Instructions)) copy(tmp, prog.Functions[f].Instructions) prog.Functions[f].Instructions = append(tmp[:i], tmp[i+1:]...) diff --git a/grow/mutate.go b/grow/mutate.go index 0111383..da713e7 100644 --- a/grow/mutate.go +++ b/grow/mutate.go @@ -8,8 +8,14 @@ import "github.com/firestuff/subcoding/vm" const instructionsPerFunctionMean = 15 const instrucitonsPerFunctionStdDev = 10 -func Mutate(prog *vm.Program) { - target := int(rand.NormFloat64()*instrucitonsPerFunctionStdDev+instructionsPerFunctionMean) +const minifyPeriodMean = 10000 + +func Mutate(def *Definition, prog *vm.Program) { + if rand.Intn(minifyPeriodMean) == 0 { + def.minifyProgram(prog) // ignore error + } + + target := int(rand.NormFloat64()*instrucitonsPerFunctionStdDev + instructionsPerFunctionMean) if len(prog.Functions[0].Instructions) < target { addInstruction(prog, prog.Functions[0]) diff --git a/vm/function.go b/vm/function.go index 74b1dd2..f10c48f 100644 --- a/vm/function.go +++ b/vm/function.go @@ -3,3 +3,13 @@ package vm type Function struct { Instructions []*Instruction } + +func (fnc *Function) Copy() *Function { + ret := &Function{} + + for _, instr := range fnc.Instructions { + ret.Instructions = append(ret.Instructions, instr.Copy()) + } + + return ret +} diff --git a/vm/instruction.go b/vm/instruction.go index 3d6129f..e1e1ecb 100644 --- a/vm/instruction.go +++ b/vm/instruction.go @@ -7,3 +7,15 @@ type Instruction struct { opHandler opHandler `struc:"skip"` } + +func (instr *Instruction) Copy() *Instruction { + ret := &Instruction{ + OpCode: instr.OpCode, + } + + for i, opr := range instr.Operands { + ret.Operands[i] = opr.Copy() + } + + return ret +} diff --git a/vm/operand.go b/vm/operand.go index fa6546d..64e2b76 100644 --- a/vm/operand.go +++ b/vm/operand.go @@ -13,3 +13,14 @@ type Operand struct { Reserved [3]byte Value uint64 } + +func (opr *Operand) Copy() *Operand { + if opr == nil { + return nil + } + + return &Operand{ + Type: opr.Type, + Value: opr.Value, + } +} diff --git a/vm/program.go b/vm/program.go index f06eb47..a355c15 100644 --- a/vm/program.go +++ b/vm/program.go @@ -6,3 +6,17 @@ type Program struct { InstructionLimit uint64 Functions []*Function } + +func (prog *Program) Copy() *Program { + ret := &Program{ + GlobalMemorySize: prog.GlobalMemorySize, + FunctionMemorySize: prog.FunctionMemorySize, + InstructionLimit: prog.InstructionLimit, + } + + for _, fnc := range prog.Functions { + ret.Functions = append(ret.Functions, fnc.Copy()) + } + + return ret +}