我想用Pymunk产生一种遗传算法,其目的是向目标投掷一个球。
我知道大多数遗传算法的知识,但是Pymunk对我来说是新手。这个想法是,球将从一个固定的位置开始,例如距地面1.5m,距篮筐水平20m。假设球重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()
答案 0 :(得分:1)
我认为这个问题有几个部分。我的第一建议是从最小的东西开始,然后从那里开始扩展。当有多个部分令人困惑或您不知道如何解决时,这对于各种问题都非常有效。
以下是一些指针:
您需要弄清楚要如何测量健身度。一些示例:
在一定时间后测量球到目标的距离。这应该非常容易实现,因为当仿真结束时,您只需要测量一次即可。但是,可能很难决定应该几点。
在一次“掷”中测量球到目标的最小距离。我想这要好于1,但要取决于您要培训的内容。在这种情况下,您可以在每次调用step函数时测量距离,并跟踪其最小值。我认为我会从这种适合度的测量方法开始,因为它相当容易,但仍然感觉还可以。
您可能希望将模拟与显示分开。因此,您应该尝试编写执行一圈/“掷”的功能并将其模拟到最后。
例如,这是一个简单的示例,我将其与方法do_one_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
一旦具备这些基本知识,就可以添加更多精美功能