Создание "разбросанных" предметов, которые не перекрываются - PullRequest
1 голос
/ 23 февраля 2020

Это вопрос, который мне пришлось решить, но я бился головой о стену последние 5 дней. Должно быть что-то действительно простое, что я упускаю или неправильно понимаю, так как логика c кажется мне на 100% правильной, но она просто не сработает.

Мне нужно нарисовать «разбросанные» дома, которые не за коленями, 100 из них. Я должен использовать черепаху, чтобы нарисовать их, поэтому у меня есть координаты X и Y. И X и Y перечисляют в целях проверки, чтобы видеть, находится ли дом в этом месте.

То, что я делаю, рисует "дом" (квадрат с треугольником на вершине) на рандомизированных координатах, я l oop, в то время как число домов меньше 100. На каждом l oop я рандомизирую координаты x и y, откуда я начинаю рисовать каждый дом с черепахой. Я проверяю, есть ли значение уже в проверочных списках X и Y, а также, если мои новые X и Y имеют +/- размер дома (рассматривая его как квадрат)

import turtle
import time
import random
t = turtle.Turtle()
turtle.screensize(1920,1000)
x_verif = []
y_verif = []
t.speed(0)
collision = None


def square():
    for s in range(0, 4):
        t.forward(90)
        t.left(90)

def triangle():
    for s in range(0, 2):
        t.left(-60)
        t.forward(52)

def house():
    square()
    t.left(90)
    t.forward(90)
    triangle()

def scatter():
    print("a")
    house()
    x1 = random.randint(-850, 850)
    y1 = random.randint(-380, 380)
    count = 0
    while count < 100:
        print("a2")
        i = 0
        u = 0
        collision = False
        for  tries in range (0, 2):
            print("a3")
            x_verif.append(x1)
            y_verif.append(y1)
        while u < 100:
            print("a4")

            print(x_verif, y_verif, x1, y1)
            while i < len(x_verif):
                x1 = random.randint(-850, 850)
                y1 = random.randint(-380, 380)
                print(x1, y1)
                if x1 not in x_verif and (x1 > x_verif[i]+91 or x1 < x_verif[i]-91):
                    if y1 not in y_verif and (y1 > y_verif[i]+142 or y1 < y_verif[i]-142):
                        collision = False
                else:
                    collision = True
            if collision == False:
                            t.penup()
                            t.hideturtle()
                            t.setx(x1)
                            t.sety(y1)
                            t.pendown()
                            house()
                            x_verif.append(x1)
                            y_verif.append(y1)
                            count += 1
                i+= 1
        u += 1


scatter()

Извините за уродливый код и простота. Я хотел бы использовать списочные определения для этого, но я не знаю, где мой лог c терпит неудачу в данный момент. Это похоже на мою сотую попытку, так как в этой версии это только dr aws начальный дом, и я думаю, что он где-то бесконечно зацикливается ....

Моя проблема заключается в циклическом прохождении целых списков для каждого нового значения , Нужно ли мне проходить через них oop каждый раз, или есть какое-то условие ЕСЛИ, которое я могу использовать? Редактировать: он продолжает циклически перебирать случайные значения, но ни одно из них не принимается двумя операторами IF, которые я использую.

Примечание: с моим текущим кодом они также каждый раз меняют направление рисования ... Не знаю, почему это происходит ....

Редактировать: Я очень благодарен за все решения! Я борюсь с запиской в ​​начале вопроса. Это говорит о том, что для выполнения последней нужно всего несколько строк, по сравнению с первой ..... Они шутят? questions

Ответы [ 2 ]

1 голос
/ 24 февраля 2020

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

Точка в процедуре треугольника основана на одном из GeeksForGeeks.org

У меня есть один небольшой фактор помадки в моем коде, который все еще нужно исправить. Но в целом кажется, что цель достигнута:

from turtle import Screen, Turtle
from random import randint

HOUSES = 100
HOUSE_SIZE = 90

WINDOW_WIDTH, WINDOW_HEIGHT = 1920, 1000

# assumes roof is an isosceles triangle
ROOF_SIDE = HOUSE_SIZE * 3**0.5 / 3
ROOF_HEIGHT = ROOF_SIDE // 2

FONT_SIZE = HOUSE_SIZE // 3
FONT = ('Arial', FONT_SIZE, 'normal')

def square(turtle, identity=None):
    turtle.begin_poly()

    for _ in range(3):
        turtle.forward(HOUSE_SIZE)
        turtle.right(90)

    turtle.end_poly()

    turtle.forward(HOUSE_SIZE/2 - FONT_SIZE/2)  # visually finish square

    if identity:  # label each house with a number
        turtle.penup()
        turtle.right(90)
        turtle.forward(HOUSE_SIZE/2)
        turtle.write(identity, align='center', font=FONT)
        turtle.backward(HOUSE_SIZE/2)
        turtle.left(90)
        turtle.pendown()

    turtle.forward(HOUSE_SIZE/2 + FONT_SIZE/2)  # visually finish square
    turtle.right(90)  # return to original orientation

    return turtle.get_poly()

def triangle(turtle):
    turtle.begin_poly()

    turtle.forward(HOUSE_SIZE)
    turtle.left(150)
    turtle.forward(ROOF_SIDE)

    turtle.end_poly()

    turtle.left(60)
    turtle.forward(ROOF_SIDE)  # visually finish triangle
    turtle.right(210)  # return to original orientation

    return turtle.get_poly()

def house(turtle, identity=None):
    return (square(turtle, identity), triangle(turtle))

def area_of_triangle(p1, p2, p3):

    x1, y1 = p1
    x2, y2 = p2
    x3, y3 = p3

    return abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2))) // 2

def is_inside_triangle(point, triangle):

    p1, p2, p3 = triangle

    a = area_of_triangle(p1, p2, p3)

    b = area_of_triangle(point, p2, p3)
    c = area_of_triangle(p1, point, p3)
    d = area_of_triangle(p1, p2, point)

    return abs(a - (b + c + d)) < 5  # 5 == fudge factor, sigh

def is_inside_square(point, square):

    x, y = point

    p1, p2, p3, p4 = square

    _, y1 = p1
    x2, _ = p2
    _, y3 = p3
    x4, _ = p4

    return x4 <= x <= x2 and y3 <= y <= y1

def scatter(turtle):
    houses = []
    count = 0

    while count < HOUSES:

        x = randint(-WINDOW_WIDTH/2, WINDOW_WIDTH/2 - HOUSE_SIZE)
        y = randint(HOUSE_SIZE - WINDOW_HEIGHT/2, WINDOW_HEIGHT/2 - ROOF_HEIGHT)

        turtle.penup()
        turtle.goto(x, y)
        proposed_square, proposed_triangle = house(turtle)  # test draw invisible house
        turtle.pendown()

        collision = False

        for point in proposed_square + proposed_triangle:  # does proposed house collide with houses?
            for square, triangle in houses:
                if is_inside_square(point, square) or is_inside_triangle(point, triangle):
                    collision = True
                    break

            if collision:
                break

        for square, triangle in houses:  # do houses collide with proposed house?
            for point in square + triangle:
                if is_inside_square(point, proposed_square) or is_inside_triangle(point, proposed_triangle):
                    collision = True
                    break

            if collision:
                break

        if not collision:
            count += 1
            houses.append(house(turtle, identity=count))  # actually draw new house
            print(count)

screen = Screen()
screen.screensize(WINDOW_WIDTH, WINDOW_HEIGHT)
screen.tracer(False)

turtle = Turtle()
turtle.hideturtle()

scatter(turtle)

screen.tracer(True)
screen.exitonclick()

Эта проблема несколько упрощена последовательной ориентацией домов. Если бы дома были ориентированы случайным образом по компасу, расчеты квадратного перекрытия были бы более сложными.

Решение можно было бы сделать более эффективным, если бы треугольник перекрывался с треугольником, квадрат перекрывался с треугольником и т. Д. c. тесты вместо просто "указать внутрь". Мы могли бы также записать sh логи столкновений c в подпрограммы square() и triangle(), чтобы выдать ошибку, как только возникнет коллизия, вместо того, чтобы завершить строительство дома и затем провести тестирование.

Учитывая размер области экрана, размер дома, количество домов и случайное рассеяние, я полагаю, что для отдельного прогона программы может быть остановлено попытка разместить дом там, где может не быть свободного места :

enter image description here

1 голос
/ 23 февраля 2020

Дефо не лучший способ сделать это, но

import turtle
import time
import random
t = turtle.Turtle()
turtle.screensize(1920,1000)
x_verif = []
y_verif = []
t.speed(0)
collision = None


def square():
    for s in range(0, 4):
        t.forward(90)
        t.left(90)

def triangle():
    for s in range(0, 2):
        t.left(-60)
        t.forward(52)

def house():
    square()
    t.left(90)
    t.forward(90)
    triangle()
    t.left(30) #returning to 90 degrres
def scatter():
    beenAt = [] #this will hold every place that there is a house
    for i in range(100): 
        t.penup()
        loop = True
        while loop == True:
            area = random.randint(-850, 850) 
            for i in range(91): #looping for the size of the house
                if area+i in beenAt: #if the number chosen plus i is in beenAt stop because we cant use that place
                    break
                if i == 90: #if at the finial part of our loop then draw house
                    t.goto(area, 0)
                    t.pendown()
                    for i in range(area, area + 91): 
                        beenAt.append(i) #add to been at list every place we have drawn
                    house()
                    loop = False
scatter()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...