Как рассчитать пи в tkinter, используя иглы Буффона? - PullRequest
0 голосов
/ 31 мая 2019

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

Я новичок, извините за грязный код, но я скоро проведу вас через него.

После отрисовки установки она генерирует случайные координаты x1 и y1 для начальной точки линии.Обратите внимание, что я хочу, чтобы длина строк составляла 50 единиц.Поэтому я генерирую x_rel, который может находиться в диапазоне от -50 до 50. После этого, используя теорему Пифагора, я вычисляю y_rel.Случайно это может быть сделано отрицательным, или это может остаться положительным.Чтобы получить конечные координаты линии, вы просто складываете x_rel и x1, то же самое для y.

Чтобы обнаружить столкновение с одной из начальных линий на доске, я сравниваю первые числа y1 и y2.Если они одинаковы, то столкновения не происходит (это работает, потому что разрыв между каждой стартовой линией на доске равен 100).После подсчёта столкновений я просто вычисляю число пи и печатаю его.Но обычно возвращается ~ 2,6.Но другие программы, подобные этой, которые я нашел в Интернете, могут довольно точно рассчитать число пи.Где моя ошибка?

import tkinter as tk
import random
import math


count = 0
class App:

    def __init__(self, root):

        self.root = root
        root.title("PI calculator")

        c = tk.Canvas(root, height=700, width=700)
        c.pack()
        c.create_line(100, 100, 600, 100)
        c.create_line(100, 200, 600, 200)
        c.create_line(100, 300, 600, 300)
        c.create_line(100, 400, 600, 400)
        c.create_line(100, 500, 600, 500)
        c.create_line(100, 600, 600, 600)
        for x in range(100000):
            c.create_line(self.generate_coords(), fill="red", width=1.5)

    def generate_coords(self):
        choices = [1, 0]
        x1 = random.randint(100, 600)
        y1 = random.randint(100, 600)
        x_rel = random.randint(-50, 50)
        y_rel = math.sqrt(50**2 - x_rel**2)
        if random.choice(choices) == 1:
            y_rel = -abs(y_rel)
        if random.choice(choices) == 0:
            y_rel = abs(y_rel)
        x2 = x1 + x_rel
        y2 = y1 + y_rel
        col = self.detect_collision(y1, y2)
        if col == True:
            global count
            count += 1
        return x1, y1, x2, y2

    def detect_collision(self, y1, y2):
        first_num_1 = math.floor(y1/100)
        first_num_2 = math.floor(y2 / 100)
        if first_num_1 != first_num_2:
            return True
        else:
            return False


root = tk.Tk()
window = App(root)
pi = (2*50*100000)/(100*count)
print(count)
print(pi)
root.mainloop()

38243
2.6148576210025363

1 Ответ

0 голосов
/ 31 мая 2019

Я поэкспериментировал с вашим кодом и сравнил его с аналогичными программами, и пришел к выводу, что ваши пин-коды не были такими случайными, как следовало бы, и это искажало ваши результаты.Ниже я переработал логику сбрасывания булавки, и результаты, кажется, улучшились:

import tkinter as tk
import random
import math

NUMBER_STICKS = 250
LINE_DISTANCE = 100
STICK_LENGTH = 83

class App:

    def __init__(self, root):

        self.root = root
        root.title("PI calculator")

        self.collisions = 0

        c = tk.Canvas(root, height=700, width=700)
        c.pack()

        for y in range(1, 7):
            c.create_line(100, y * LINE_DISTANCE, 600, y * LINE_DISTANCE)

        for _ in range(NUMBER_STICKS):
            collision, *coords = self.generate_coords()
            c.create_line(coords, fill="red" if collision else "green", width=1.5)

    def generate_coords(self):

        x1 = random.randint(100, 600)
        y1 = random.randint(100, 600)

        angle = random.randrange(360)
        x2 = x1 + STICK_LENGTH * math.cos(math.radians(angle))
        y2 = y1 + STICK_LENGTH * math.sin(math.radians(angle))

        collision = self.detect_collision(y1, y2)

        if collision:
            self.collisions += 1

        return collision, x1, y1, x2, y2

    def detect_collision(self, y1, y2):
        num_1 = y1 // LINE_DISTANCE
        num_2 = y2 // LINE_DISTANCE

        return num_1 != num_2

    def get_collisions(self):
        return self.collisions


root = tk.Tk()
application = App(root)

collisions = application.get_collisions()
print((2 * STICK_LENGTH * NUMBER_STICKS) / (LINE_DISTANCE * collisions))

root.mainloop()

ВЫХОД

% python3 test.py
3.516949152542373
%

Я также изменил программу для цветного кодаштифты как пересекающие или не пересекающие линии:

enter image description here

...