func (l *Level) AddBirds(count int) { for c := 0; c < count; c++ { l.birds = append(l.birds, &Bird{ pos: *l.NewBirdPos(), vel: *util.NewVector(0, 0).Add(&X_ACCELERATION), nextPos: *util.NewVector(0, 0), }) } }
func (l *Level) AddFigures(count int) { for c := 0; c < count; c++ { l.figures = append(l.figures, &Figure{ pos: *l.NewFigurePos(), vel: *util.NewVector(0, 0), nextPos: *util.NewVector(0, 0), jumps: 1, }) } }
func (l *Level) ClosestPylon(pos *util.Vector) util.Vector { idx := l.FirstPylonAfterIdx(pos) if idx == -1 { return *util.NewVector(0, 0) } nextX := l.pylons[idx].X - pos.X // TODO srsly? //prevX := idx > 0 ? pos.X - l.pylons[idx - 1] : pylonSpacing * 2 var prevX float64 = 0 if idx > 0 { prevX = pos.X - l.pylons[idx-1].X } else { // will be bigger than any spacing to next pylon prevX = float64(pylonSpacing) * 2 } if prevX < nextX { return l.pylons[idx-1] } else { return l.pylons[idx] } }
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 NewLevel(w, h int) *Level { lvl := &Level{ size: *util.NewVector(float64(w), float64(h)), pylons: make([]util.Vector, 0), birds: make([]*Bird, 0), } // min offset from top && bottom yOffset := float64(PylonHole) for off := pylonSpacing; off < w; off += pylonSpacing { hole := neural.RandMax(float64(h)-yOffset*2.0) + yOffset lvl.pylons = append(lvl.pylons, *util.NewVector(float64(off), hole)) } return lvl }
func (l *Level) FirstPylonAfter(pos *util.Vector) util.Vector { idx := l.FirstPylonAfterIdx(pos) if idx >= 0 { return l.pylons[idx] } return *util.NewVector(0, 0) // TODO srsly? // idx >= 0 ? l.pylons[idx] : *util.NewVector(0, 0) }
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 (m *Mario) DrawTick() { var ( red = uint32(0xffff0000) green = uint32(0xff00ff00) blue = uint32(0xff0000ff) ) blSize := util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE)) blSizeSmall := blSize.Scale(0.5) translate := util.NewVector(6, 6) size := util.NewVector(float64(m.drawSize), float64(m.drawSize)) for c := range m.lvl.blocks { for r := range m.lvl.blocks[c] { if m.lvl.blocks[c][r] != nil { m.drawCb(m.lvl.blocks[c][r], blSize, red) m.drawCb(m.lvl.blocks[c][r].Add(translate), blSizeSmall, green) } } } for c := range m.figures { m.drawCb(m.figures[c].fig.pos.Add(size.Scale(0.5).Neg()), size, blue) } m.drawCb( m.dbg.figure.fig.pos.Add(util.NewVector(-3., -20.)), util.NewVector(2, 20), 0xff000000) if m.dbg.output.move > 0 { m.drawCb( m.dbg.figure.fig.pos.Add(util.NewVector(0, -3)), util.NewVector(20, 2), 0xff000000) } else { m.drawCb( m.dbg.figure.fig.pos.Add(util.NewVector(-20, -3)), util.NewVector(20, 2), 0xff000000) } }
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 }
func (l *Level) NewFigurePos() *util.Vector { return util.NewVector(float64(BLOCK_SIZE)/2, l.size.Y-float64(BLOCK_SIZE)*2) }
func (l *Level) makeGround(c *int) { r := int(l.size.Y/float64(BLOCK_SIZE)) - 1 l.blocks[*c][r] = util.NewVector(float64(*c*BLOCK_SIZE), float64(r*BLOCK_SIZE)) }
func (l *Level) makeObstacle(c *int) { r := int(l.size.Y/float64(BLOCK_SIZE)) - 1 for q := 0; q < 4; q++ { l.blocks[*c][r-q] = util.NewVector(float64(*c*BLOCK_SIZE), float64((r-q)*BLOCK_SIZE)) } }
func (l *Level) NewBirdPos() *util.Vector { return util.NewVector(1, l.size.Y/2) }