Генетический алгоритм броска мяча в цель - PullRequest
1 голос
/ 23 октября 2019

Я хотел бы использовать Pymunk для создания генетического алгоритма, в котором цель состоит в том, чтобы бросить мяч в цель.

Я знаю, как выполнять большую часть генетического алгоритма, но Pymunk новичок вменя. Идея состоит в том, что мяч будет начинаться с фиксированной позиции, скажем, 1,5 м над землей и 20 м горизонтально от обруча. Скажем, мяч весит 1 кг. Затем мяч будет запущен с определенной силой под определенным углом. Пригодность будет ближайшей к центру цели во время полета.

Так, например, индивидуум в популяции может выглядеть как [10.0, 5.0], где 10,0 означает 10N, примененный горизонтально, и 5,0 означает 5Nприменяется вертикально.

Я не хочу, чтобы он запускал каждую симуляцию в окне, которое я вижу, но я хотел бы иметь возможность включить его, чтобы я мог запустить его для самого подходящего человека после определенного числапоколений или как только он достигает определенного уровня пригодности. Вот наглядное представление о том, что я имею в виду https://prnt.sc/pn1hoc.

Я старался изо всех сил, чтобы решить это самостоятельно, используя документацию по pymunk, но я не нашел это очень полезным, и поэтому я скореезастрял.

Что я знаю, так это то, что мне нужно начать пробел

space = pymunk.Space()
space.gravity = (0.0, -900.0)  # not sure what this means?

Затем создать шар в этом пространстве

def add_ball(space):
    mass = 1
    radius = 14
    moment = pymunk.moment_for_circle(mass, 0, radius)
    body = pymunk.Body(mass, moment)
    body.position = 100, 150
    shape = pymunk.Circle(body, radius)
    space.add(body, shape)
    return shape

Хотя этот шар начнет падать, не уверен, как заставить его запускаться статически.

Затем, чтобы сгенерировать цель, я должен сделать что-то вроде

def add_target(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC)
    body.position = (500, 300)
    target = pymunk.Segment(body, (-150, 0), (-150, 50), 5)
    space.add(target)
    return target

Я был бы очень признателен за помощь в совмещении этого с таким, что я могузапустить симуляции из моего генетического алгоритма, но также переключить их для запуска в окне.

Спасибо.

РЕДАКТИРОВАТЬ:

Я разработал, как положить вслово, вот весь мой код до сих пор

import sys, random
import pygame
from pygame.locals import *
import pymunk
import pymunk.pygame_util


def add_ball(space):
    mass = 1
    radius = 14
    moment = pymunk.moment_for_circle(mass, 0, radius)
    body = pymunk.Body(mass, moment)
    body.position = (50, 150)
    shape = pymunk.Circle(body, radius)
    space.add(body, shape)
    return shape


def add_floor(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC)
    body.position = (0, 0)
    target = pymunk.Segment(body, (0, 5), (600, 5), 5)
    space.add(target)
    return target


def add_target(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC)
    body.position = (700, 300)
    target = pymunk.Segment(body, (-150, 0), (-150, 50), 5)
    space.add(target)
    return target


def main():
    pygame.init()
    screen = pygame.display.set_mode((600, 600))
    clock = pygame.time.Clock()

    space = pymunk.Space()
    space.gravity = (0.0, -900.0)

    target = add_target(space)
    floor = add_floor(space)
    balls = []
    draw_options = pymunk.pygame_util.DrawOptions(screen)

    ball_count = 0
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit(0)
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                sys.exit(0)

        if ball_count < 1:
            ball_shape = add_ball(space)
            balls.append(ball_shape)
            ball_count += 1

        space.step(1/50.0)

        screen.fill((255,255,255))
        space.debug_draw(draw_options)

        pygame.display.flip()
        clock.tick(50)

if __name__ == '__main__':
    main()

1 Ответ

1 голос
/ 25 октября 2019

Я думаю, что этот вопрос состоит из нескольких частей. Мой совет номер один - начинать с самой маленькой вещи, а затем расширяться оттуда. Это очень хорошо работает для всех видов проблем, когда есть несколько частей, которые сбивают с толку, или вы не знаете, как решить.

Вот несколько указателей:

Вы должны выяснить,как именно вы хотите измерить физическую форму. Некоторые примеры:

  1. Измерьте расстояние мяча до цели через определенное время. Это должно быть очень легко реализовать, так как вам просто нужно измерить расстояние один раз, когда симуляция достигнет конца. Однако, может быть трудно решить, какое время должно быть.

  2. Измерьте минимальное расстояние мяча до цели во время одного «броска». Я думаю, что это лучше, чем 1, но зависит от того, для чего вы хотите тренироваться. В этом случае вы можете измерять расстояние каждый раз, когда вызываете пошаговую функцию, и отслеживать ее минимальное значение. Я думаю, что я бы начал с этого метода измерения пригодности, так как он довольно прост, но все еще чувствует себя хорошо.

Вы, вероятно, хотите отделить симуляцию от ее отображения. Поэтому вы должны попытаться написать функцию, которая выполняет один раунд / «бросок», и имитировать ее до конца.

Например, вот небольшой пример, который я собрал вместе с методом do_one_throw, который принимает импульс throw каквведите и верните минимальное расстояние до цели с помощью 1000 шагов моделирования:

def add_ball(space):
    mass = 1
    radius = 14
    moment = pymunk.moment_for_circle(mass, 0, radius)
    body = pymunk.Body(mass, moment)
    body.position = (50, 150)
    shape = pymunk.Circle(body, radius)
    space.add(body, shape)
    return shape


def add_floor(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC)
    body.position = (0, 0)
    target = pymunk.Segment(body, (0, 5), (600, 5), 5)
    space.add(target)
    return target


def add_target(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC)
    body.position = (700, 300)
    target = pymunk.Segment(body, (-150, 0), (-150, 50), 5)
    space.add(target)
    return target

def do_one_throw(impulse):
    space = pymunk.Space()
    space.gravity = (0.0, -900.0)

    ball_shape = add_ball(space)
    add_floor(space)
    target_shape = add_target(space)

    ball_shape.body.apply_impulse_at_local_point(impulse)

    min_distance_to_target = 1000000
    steps = 1000
    for _ in range(steps):
        space.step(1/50.0)
        distance_to_target = target_shape.body.position.get_distance(ball_shape.body.position)
        if distance_to_target < min_distance_to_target:
            min_distance_to_target = distance_to_target
    return min_distance_to_target

Как только вы освоите эти основы, вы можете добавить больше необычных функций

  • ДляНапример, вы можете легко начать, просто используя распечатки, чтобы распечатать то, что происходит в симуляции, чтобы начать с нее.
  • Гравитация, которую вы устанавливаете в пространстве, является вектором гравитации. Обратите внимание, что pymunk не зависит от модуля, поэтому до тех пор, пока все, что вы передаете, является последовательным, оно должно работать правильно: http://www.pymunk.org/en/latest/overview.html#mass-weight-and-units
  • Вы можете оптимизировать мой быстрый и грязный код, приведенный выше, например, имея несколько умнеелогика, чтобы решить, когда закончить симуляцию, чтобы вам не нужно было выполнять все 1000 шагов, если мяч уже вышел из игры без шансов вернуться.
  • Вы можете добавить код рисования пигмейка, похоже, что вы уже пришлидлинный путь здесь
  • Улучшение измерения расстояния до цели, теперь я принял самое простое решение, измерив расстояние между телами, но вы, вероятно, хотите, чтобы расстояние между фигурами было таким, чтобы при столкновении фигур расстояние составляло 0.
...