Rešitev

Ciljanje

Rešitev, ki uporablja, kar smo se učili na predavanjih v tednu po roku za oddajo naloge, je takšna.

from math import *
from random import *

cilj = randint(10, 50)
print("Cilj je", cilj, "daleč. Uspešno streljajte.")

razdalja = 0
while abs(cilj - razdalja) > 1:
    hitrost = float(input("Hitrost: "))
    kot = radians(float(input("Kot: ")))
    razdalja = (hitrost ** 2) * sin(2 * kot) / 9.81
    if abs(cilj - razdalja) > 1:
        print("Mimo: kroglo je neslo", razdalja, "daleč.")
print("Bum.")

V pogoju zanke preverjamo, ali je razdalja, ki jo preleti krogla, za manj kot 1 različna od razdalje do cilja. Z uporabo abs smo se izognili temu, da bi morali pisati pogoje v slogu

while razdalja > cilj - 1 and razdalja < cilj + 1:

ali kaj podobnega.

Ker uporabnika sprašujemo šele v zanki in torej tudi razdalja računamo šele v njej, pred zanko nastavimo razdalja na neko vrednost, ki je gotovo napačna, v našem primeru 0.

Malo moteče je, da dvakrat računamo abs(cilj - razdalja) > 1. Rešimo se, recimo, z nečim, česar na drugih predavanjih še nisem hotel omeniti, da se ne bi prehitro razvadili: zanko lahko prekinemo z break.

from math import *
from random import *

cilj = randint(10, 50)
print("Cilj je", cilj, "daleč. Uspešno streljajte.")

while True:
    hitrost = float(input("Hitrost: "))
    kot = radians(float(input("Kot: ")))
    razdalja = (hitrost ** 2) * sin(2 * kot) / 9.81
    if abs(cilj - razdalja) <= 1:
        break
    print("Mimo: kroglo je neslo", razdalja, "daleč.")
print("Bum.")

Pogoj v zanki je zdaj kar while True: zanka naj se vrti v nedogled. No, skoraj: če je cilj zadet, jo prekinemo z break.

V študentskih izdelkihh sem pogosto videval "zastavice". Takole

from math import *
from random import *

cilj = randint(10, 50)
print("Cilj je", cilj, "daleč. Uspešno streljajte.")

zadet = False
while not zadet:
    hitrost = float(input("Hitrost: "))
    kot = radians(float(input("Kot: ")))
    razdalja = (hitrost ** 2) * sin(2 * kot) / 9.81
    if abs(cilj - razdalja) <= 1:
        zadet = True
    else:
        print("Mimo: kroglo je neslo", razdalja, "daleč.")
print("Bum.")

Tudi prav. Z break-om se jim sicer lahko navadno izognemo.

Nekateri ste pisali while zadet == False. To je manj lepo. Pravzaprav ni lepo. :)

Prašič in cilj: rocket science. :)

Najprej vprašamo uporabnika, kje sta prašič in cilj.

pras_x = float(input("Razdalja do prašiča: "))
pras_y = float(input("Višina prašiča: "))
cilj = float(input("Razdalja do cilja: "))

Potem si premislimo in ne sprašujemo uporabnika, da ne bo potrebno stalno vpisovati številk, ko bomo popravljali program. Številke kar vprogramiramo; ko bomo popravljali program, jih bomo malo spreminjali, na koncu pa spet vrnemo input-e.

Rešitev z malo poskušanja

from math import *
g = 9.81

pras_x = 2
pras_y = 8
cilj = 10

kot = 0
while kot < 90:
    kot += 0.1
    radkot = radians(kot)
    v = sqrt(cilj * g / sin(2 * radkot))
    vx = v * cos(radkot)
    vy = v * sin(radkot)
    t = pras_x / vx
    visina = vy * t - g * t ** 2 / 2
    if abs(pras_y - visina < 0.1:
        print(kot, v)

Program preskusi različne kote, s korakom 0.1 stopinje. Izpisal bo vse kombinacije (kot, hitrost), ki zadanejo cilj in prašiča.

V zanko počnemo tole. Ko si izberemo kot, lahko iz tega izračunamo potrebno hitrost. Le formulo iz obvezne domače naloge moramo preobrniti: tam smo iz kota in hitrosti računali razdaljo, tu pa iz kota in razdalje računamo hitrost.

Ko imamo hitrost (v), jo razstavimo na vodoravno in navpično komponento. Krogla se bo v začetku pomikala s hitrostjo vx v vodoravni smeri in vy navzgor. Vodoravno hitrost bo obdržala, torej lahko izračunamo, koliko časa bo potrebovala do prašiča -- v vodoravni smeri: t = pras_x / vx. V času t bo torej nad, pod ali v prašiču. Izračunati moramo le še, kako visoko bo v tem trenutku. Iz fizike vemo, da je pot pri pospešenem gibanju enaka $$s = v t + a t^2 / 2$$, kjer je $v$ začetna hitrost, $a$ pa pospešek. Pri nas kažeta začetna hitrost in pospešek v različni smeri, poleg tega pa opazujemo le navpično komponento, zato vy * t - g * t ** 2 / 2.

To je to.

Računska rešitev

Gornja simulacija je pokazala pot do računske rešitve. Recimo, da bomo izstrelili kroglo pod kotom $phi$. Da bodo formule krajše, recimo, da je do cilja $s$, prašič pa je na koordinatah $(p_x, p_y)$. Vemo (tako kot zgoraj, samo $\sin 2\phi$ razpišem v $2 \sin\phi \cos\phi$)

$$v = \sqrt{\frac{s g}{2 \sin\phi \cos\phi}}$$

Če vem, da je $v_x = v\cos\phi$ in $v_x = v\cos\phi$ ter nisem pozabil, da je $\sin\phi / \cos\phi = \tan\phi$, imam

$$ v_x = \sqrt{\frac{sg}{2 \tan\phi}},\;\;\;\;\;\;v_y = \sqrt{\frac{sg\tan\phi}{2}}$$

In, mimogrede, $v_y / v_x = \tan\phi$.

Tako kot prej vemo

$$t = \frac{p_x}{v_x} = p_x\sqrt{\frac{2 \tan\phi}{sg}}$$

Zdaj pa poskušamo zadeti prašiča: krogla mora biti v času $t$ na višini $p_y$:

$$p_y = v_y t - \frac{1}{2}g t^2$$

V to vstavimo gornji $t$, vendar enkrat kot $\frac{p_x}{v_x}$, drugič kot $p_x\sqrt{\frac{2 \tan\phi}{sg}}$.

$$p_y = v_y \frac{p_x}{v_x} - \frac{1}{2}g p_x^2 \frac{2 \tan\phi}{sg} = p_x \tan\phi - \frac{p_x^2}{s}\tan\phi = (p_x - \frac{p_x^2}{s})\tan\phi$$

Torej

$$\tan\phi = \frac{p_y}{p_x - p_x^2/s}$$

oziroma

$$\phi = \arctan\frac{p_y}{p_x - p_x^2/s}$$

Ko imamo kot, pa poznamo hitrost,

$$v = \sqrt{\frac{2 g}{\sin 2\phi}}$$

pras_x = float(input("Razdalja do prašiča: "))
pras_y = float(input("Višina prašiča: "))
cilj = float(input("Razdalja do cilja: "))

phi = atan(pras_y / (pras_x - pras_x ** 2 / cilj))
v = sqrt(cilj * g / sin(2 * phi))
print(degrees(phi), v)
Last modified: Saturday, 15 October 2016, 6:13 PM