begin boolean Debugging = false; real Pi = 3.14159265; procedure Debug(T); text T; begin if Debugging then begin OutText("Debug> " & T); OutImage; end if; end Debug; real procedure Degrees(Rad); real Rad; begin Degrees := Rad/Pi * 180; end Degrees; real procedure Solve(NHooks, RopeLength); integer NHooks; real RopeLength; begin ref(Hook) array H(0:NHooks+1); class Hook(X, Y); real X, Y; begin real procedure Dir(H2); ref(Hook) H2; begin real dX, dY, D; dX := H2.X-X; dY := H2.Y-Y; D := if dX=0 then 90 else Degrees(ArcTan(dY/dX)); if dX < 0 then D := D+180; Dir := D; end Dir; procedure Dump; begin OutText("("); OutFix(X, 2, 0); OutText(","); OutFix(Y, 2, 0); OutText(")"); end Dump; real procedure FindNext(CurDir, CurLen); real CurDir, CurLen; begin ref(Hook) BestHook; real BestDir, BestDist, BestAngle; integer I; if Y >= -CurLen then begin H(NHooks+1) :- new Hook(X+Sqrt(CurLen**2-Y**2),0); end else begin H(NHooks+1) :- none; end if; for I := 0 step 1 until NHooks+1 do begin if H(I)=/=none and then H(I)=/=this Hook then begin boolean procedure BetterHook; begin if L <= CurLen*1.0001 then begin if BestHook =/= none then begin if A < BestAngle then BetterHook := true else if A=BestAngle and L>BestDist then BetterHook := true; end else BetterHook := true; end if; end BetterHook; real A, D, L; D := Dir(H(I)); L := Length(H(I)); A := D-CurDir; if A < 0 then A := A+360; if Debugging then begin OutText("Debug: "); Dump; OutText(" and "); H(I).Dump; OutText(": Dir="); OutFix(D, 2, 0); OutText(", Angle="); OutFix(A, 2, 0); OutText(", Distance="); OutFix(L, 2, 0); OutImage; end if; if BetterHook then begin BestHook :- H(I); BestAngle := A; BestDir := D; BestDist := L; end if; end if; end for; if BestHook == none then begin if Debugging then begin Debug("Pendulum has started circling around a hook."); OutText(" Circumference is 2*Pi*"); OutFix(CurLen,2,0); OutText(" = "); OutFix(2*Pi*CurLen,2,0); OutImage; end if; FindNext := -2*Pi*CurLen; end else if BestHook == H(NHooks+1) then begin if Debugging then begin Debug("Pendulum has reached its highest point."); OutText(" Length of last arc is 2*Pi*"); OutFix(CurLen,2,0); OutText("*"); OutFix(BestAngle,2,0); OutText("/360 = "); OutFix(2*Pi*CurLen*BestAngle/360,2,0); OutImage; end if; FindNext := 2*2*Pi*CurLen*BestAngle/360; end else begin real NextD; if Debugging then begin Debug("Pendulum bends around a hook and continues."); OutText(" Free rope is now "); OutFix(CurLen-BestDist,2,0); OutImage; end if; NextD := BestHook.FindNext(BestDir,CurLen-BestDist); if Debugging and NextD>=0 then begin OutText(" Length of previous arc is 2*Pi*"); OutFix(CurLen,2,0); OutText("*"); OutFix(BestAngle,2,0); OutText("/360 = "); OutFix(2*Pi*CurLen*BestAngle/360,2,0); OutImage; end if; FindNext := if NextD<0 then NextD else NextD + 2*2*Pi*CurLen*BestAngle/360; end if; end FindNext; real procedure Length(Hx); ref(Hook) Hx; begin Length := Sqrt((Hx.X-X)**2 + (Hx.Y-Y)**2); end Length; end Hook; integer I; H(0) :- new Hook(0,0); for I := 1 step 1 until NHooks do H(I) :- new Hook(InF.InInt,InF.InInt); Solve := Abs(H(0).FindNext(180,RopeLength)); end Solve; ref(InFile) InF; ref(OutFile) OutF; integer NHooks, Cnt; real Res; InF :- new InFile ("pendulum.in"); InF.Open(Blanks(80)); OutF :- new OutFile("pendulum.out"); OutF.Open(Blanks(80)); for NHooks := InF.InInt while NHooks > 0 do begin Debug("New pendulum:"); Res := Solve(NHooks, InF.InReal); Cnt := Cnt+1; inspect OutF do begin OutText("Pendulum #"); OutInt(Cnt, 0); OutImage; OutText("Length of periodic orbit = "); OutFix(Res, 2, 0); OutImage; OutImage; end inspect; end for; InF.Close; OutF.Close; end