func (m *Mario) mutateStep(c int) { if m.figures[c].dead { m.stats.dead++ m.figures[c].dead = false m.figures[c].cache = make(map[BoolMap]MarioOutput) m.figures[c].fig.pos = *m.lvl.NewFigurePos() m.figures[c].fig.vel = *util.NewVector(0, 0) needsMutation := true mutateChance := (float64(c) / float64(len(m.figures))) * 2.0 forceCross := c >= len(m.figures)/2 if forceCross || neural.Chance(mutateChance) { *m.figures[c].brain = *neural.Cross2(m.randNet(), m.randNet()) m.stats.crossed++ needsMutation = false } if m.figures[c].idleFrames >= idleThreshold { m.stats.culled++ if needsMutation { needsMutation = false m.figures[c].brain.Mutate(0.75) m.figures[c].bestX *= 0.25 } } if needsMutation || neural.Chance(0.01) { m.figures[c].brain.MutateWithMagnitude(0.01, 0.01) m.figures[c].bestX *= 0.975 } m.figures[c].idleFrames = 0 m.figures[c].idleX = 0 } else { if m.figures[c].fig.pos.X > m.figures[c].bestX { m.figures[c].bestX = m.figures[c].fig.pos.X } if int(m.figures[c].fig.pos.X) > m.figures[c].idleX { m.figures[c].idleX = int(m.figures[c].fig.pos.X) m.figures[c].idleFrames = 0 } else { m.figures[c].idleFrames++ if m.figures[c].idleFrames >= idleThreshold { m.figures[c].dead = true } } } }
func (f *Flappy) mutateFlock() { sort.Sort(f.birds) randNet := func() *neural.Net { return f.birds[int(neural.RandMax(float64(len(f.birds))))].brain } best := f.birds[0].brain for c := range f.birds { if f.birds[c].dead { f.birds[c].dead = false f.birds[c].bird.pos = *f.lvl.NewBirdPos() f.birds[c].bird.vel = *util.NewVector(SCROLL_SPEED, 0) f.birds[c].brain = neural.Cross(best, randNet()) if neural.Chance(0.1) { // penalize best achievement due to mutation f.birds[c].bestX *= 0.99 f.birds[c].brain.Mutate(0.33) } } else { f.birds[c].bird.pos = f.birds[c].bird.nextPos f.birds[c].bestX = math.Max(f.birds[c].bird.pos.X, f.birds[c].bestX) } } }
func (l *Level) makeHole(c *int) { size := int(3 + neural.RandMax(2)) height := int(l.size.Y/float64(BLOCK_SIZE)) - 1 - 3 skip := OBSTACLE_SPACING * 2 if neural.Chance(0.75) { size = skip for iter := 0; iter < skip; iter++ { if iter+*c >= len(l.blocks) { break } if iter%5 == 0 { x := float64((iter + *c) * BLOCK_SIZE) y := float64((height + 3) * BLOCK_SIZE) l.blocks[iter+*c][height+3] = util.NewVector(x, y) } } } if neural.Chance(0.3) { for iter := -2; iter < size+3; iter++ { xIdx := iter + *c if xIdx < 0 || xIdx >= len(l.blocks) { continue } x := float64(xIdx * BLOCK_SIZE) y := float64(height * BLOCK_SIZE) l.blocks[xIdx][height] = util.NewVector(x, y) } } *c += size }
func NewLevel(w, h int) *Level { blockH := h / BLOCK_SIZE blockW := w / BLOCK_SIZE lvl := &Level{ size: *util.NewVector(float64(w), float64(h)), blocks: make([][]*util.Vector, blockW, blockW), bmap: make([][]BoolMap, blockW, blockW), figures: make([]*Figure, 0), } fmt.Println("Mario: generating level...") for c := 0; c < blockW; c++ { lvl.blocks[c] = make([]*util.Vector, blockH, blockH) for r := 0; r < blockH; r++ { lvl.blocks[c][r] = nil } } for c, obs := 0, 1; c < blockW; c, obs = c+1, obs+1 { pr := c if obs%OBSTACLE_SPACING == 0 { if neural.Chance(0.7) { lvl.makeHole(&c) } else { lvl.makeObstacle(&c) } } else { lvl.makeGround(&c) } obs += c - pr } fmt.Println("Mario: generating bool map...") for c := 0; c < blockW; c++ { lvl.bmap[c] = make([]BoolMap, blockH, blockH) for r := 0; r < blockH; r++ { lvl.bmap[c][r] = lvl.boolMapAtIdx(c, r) } } return lvl }