예제 #1
0
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),
		})
	}
}
예제 #2
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,
		})
	}
}
예제 #3
0
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]
	}
}
예제 #4
0
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)
		}
	}

}
예제 #5
0
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
}
예제 #6
0
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)
}
예제 #7
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
			}
		}

	}
}
예제 #8
0
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)
	}

}
예제 #9
0
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
}
예제 #10
0
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
}
예제 #11
0
func (l *Level) NewFigurePos() *util.Vector {
	return util.NewVector(float64(BLOCK_SIZE)/2, l.size.Y-float64(BLOCK_SIZE)*2)
}
예제 #12
0
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))
}
예제 #13
0
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))
	}
}
예제 #14
0
func (l *Level) NewBirdPos() *util.Vector {
	return util.NewVector(1, l.size.Y/2)
}