Interlos, losotoč

Jen jsem plácnu svoje řešení jedné úlohy, kterou jsem dělal v rámci Interlosu. InterLoS je pětihodinová internetová týmová soutěž. Týmy řeší zadané, různě obtížné úlohy, které jsou šifrovacího, logického nebo programovacího charakteru.

Poprvé v životě jsem v Pythonu musel použít

sys.setrecursionlimit()

Zadání

Daleko na severu je nuda – dlouhé noci, všude sníh a polární záře se brzy omrzí. Losi proto nepohrdnou žádnou zábavou. Nu a proto si postavili kolotoč. Jednoduché kolotoče jsou ale nuda. Daleko zajímavější jsou ty, kde se otáčí rameno a na jeho konci se otáčí další rameno a teprve tam je sedačka. To losy ale také brzo omrzelo, a proto se rozhodli postavit kolotoč s otáčejícím se ramenem, na jehož konci je otáčející se rameno a na něm je otáčející se rameno a na něm je otáčející se rameno… Asi chápete, že na Losotoči nešetřili s rameny. Jejich sebesložitější kolotoč můžeme snadno popsat jako seznam ramen, kde u každého ramene uvedeme jeho rychlost otáčení, jeho délku a případně počáteční úhel, ze kterého se začalo otáčet. Na konci posledního ramene je sedačka.

Otázka pro vás – po jaké křivce se pohybuje uživatel Losotoče? Je nám jedno, jestli Losotoč postavíte nebo odsimulujete. V souboru zadání P1-input.txt každý řádek reprezentuje jedno rameno a každé rameno je trojice čísel oddělená čárkou – rychlost ramene v radiánech za sekundu, délka ramene v milimetrech a jeho počáteční úhel v radiánech. A abyste neřekli, že jsme na vás zlí, jelikož po vás chceme simulaci spojitého systému (v případě, že Losotoč skutečně nechcete stavět), stačí, když budete sledovat polohu kolotoče každých 20 milisekund. Pro získání hesla úlohy stačí popsat trajektorii Losotoče podstatným jménem v prvním pádě.

Řešení

example

Kód

import csv
from PIL import Image, ImageDraw
import sys
sys.setrecursionlimit(1200)
pi = 3.14154804
from math import sin, cos

width, height = 3000, 3000

bg = (255, 255, 255)

xx = []
yy = []

im = Image.new("RGBA", (width, height), bg)
draw = ImageDraw.Draw(im)

class Kolotoc:
  def __init__(self, x,y, speed, radius, startAngle):
    self.x = x
    self.y = y
    self.speed = float(speed) / 200  # rad per second
    self.radius = float(radius) / 2000
    self.angle = float(startAngle)
    self.child = None

  def doTick(self):
    self.angle += self.speed
    okraj = self.drawPoint()
    if self.child:
      self.child.x, self.child.y = okraj
      self.child.doTick()

  def drawPoint(self):
    okraj = self.x + self.radius * cos(self.angle), self.y + self.radius * sin(self.angle)
    if not self.child:
      bold = 7
      draw.ellipse((okraj[0] - bold, okraj[1] - bold, okraj[0]+bold, okraj[1]+bold), fill="Blue", outline="Blue")
      xx.append(okraj[0])
      yy.append(okraj[1])
    else:
      draw.point(okraj, fill="Green")
    return okraj

  def setChild(self, speed, radius, startRadius):
    center = self.drawPoint()
    self.child = Kolotoc(center[0], center[1], speed, radius, startRadius)
    return self.child

with open('input.txt', 'rb') as csvfile:
  r = csv.reader(csvfile, delimiter=',')
  k = None
  for row in r:
    (speed, radius, start) = row
    if not k:
      k = Kolotoc(0, 2600, speed, radius, start)
      rootK = k
    else:
        k = k.setChild(speed, radius, start)

for t in range(0, 3600):
  rootK.doTick()

im.save("example.png")

print("""
Xmin  {}   xMax {}
Ymin  {}   yMax {}
""".format(
  int(min(xx)), int(max(xx)),
  int(min(yy)), int(max(yy))
))

Comments are disabled