From 3d5235ad6e292f76f3533456128f7e5c2385615c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Fri, 16 Feb 2024 21:22:31 +0100 Subject: [PATCH] Added another WIP solution attempt --- AdventOfCode.lpi | 8 + UVector.pas | 111 +++++ solvers/UNeverTellMeTheOdds.pas | 646 +++++++++++++++++++++++-- tests/UNeverTellMeTheOddsTestCases.pas | 12 + 4 files changed, 747 insertions(+), 30 deletions(-) create mode 100644 UVector.pas diff --git a/AdventOfCode.lpi b/AdventOfCode.lpi index 9255b8b..8795c81 100644 --- a/AdventOfCode.lpi +++ b/AdventOfCode.lpi @@ -137,6 +137,14 @@ + + + + + + + + diff --git a/UVector.pas b/UVector.pas new file mode 100644 index 0000000..785aef8 --- /dev/null +++ b/UVector.pas @@ -0,0 +1,111 @@ +{ + Solutions to the Advent Of Code. + Copyright (C) 2024 Stefan Müller + + This program is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + this program. If not, see . +} + +unit UVector; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, SysUtils; + +type + TVector3DataRange = 0..2; + TVector3Int64Data = array[TVector3DataRange] of Int64; + + { TVector3Int64 } + + TVector3Int64 = object + private + function GetX: Int64; + function GetY: Int64; + function GetZ: Int64; + procedure SetX(AValue: Int64); + procedure SetY(AValue: Int64); + procedure SetZ(AValue: Int64); + public + Data: TVector3Int64Data; + property X: Int64 read GetX write SetX; + property Y: Int64 read GetY write SetY; + property Z: Int64 read GetZ write SetZ; + constructor Init(const AX, AY, AZ: Int64); + end; + + //// Component-wise binary operators. + //operator - (const A, B: TVector3Int64): TVector3Int64; + //operator / (const A, B: TVector3Int64): TVector3Int64; + +implementation + +//operator - (const A, B: TVector3Int64): TVector3Int64; +//var +// i: TVector3DataRange; +//begin +// for i in TVector3DataRange do +// Result.Data[i] := A.Data[i] - B.Data[i]; +//end; +// +//operator / (const A, B: TVector3Int64): TVector3Int64; +//var +// i: TVector3DataRange; +//begin +//for i in TVector3DataRange do +// Result.Data[i] := A.Data[i] / B.Data[i]; +//end; + +{ TVector3Int64 } + +function TVector3Int64.GetX: Int64; +begin + Result := Data[0]; +end; + +function TVector3Int64.GetY: Int64; +begin + Result := Data[1]; +end; + +function TVector3Int64.GetZ: Int64; +begin + Result := Data[2]; +end; + +procedure TVector3Int64.SetX(AValue: Int64); +begin + Data[0] := AValue; +end; + +procedure TVector3Int64.SetY(AValue: Int64); +begin + Data[1] := AValue; +end; + +procedure TVector3Int64.SetZ(AValue: Int64); +begin + Data[2] := AValue; +end; + +constructor TVector3Int64.Init(const AX, AY, AZ: Int64); +begin + X := AX; + Y := AY; + Z := AZ; +end; + +end. + diff --git a/solvers/UNeverTellMeTheOdds.pas b/solvers/UNeverTellMeTheOdds.pas index 6f5c98d..1e91b97 100644 --- a/solvers/UNeverTellMeTheOdds.pas +++ b/solvers/UNeverTellMeTheOdds.pas @@ -1,6 +1,6 @@ { Solutions to the Advent Of Code. - Copyright (C) 2023 Stefan Müller + Copyright (C) 2023-2024 Stefan Müller This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -22,26 +22,45 @@ unit UNeverTellMeTheOdds; interface uses - Classes, SysUtils, Generics.Collections, Math, USolver; + Classes, SysUtils, Generics.Collections, Math, USolver, UVector; type { THailstone } - THailstone = record - X, Y, Z: Int64; - VX, VY, VZ: Integer; + THailstone = class + public + Position, Velocity: TVector3Int64; + constructor Create(const ALine: string); + constructor Create(const APosition, AVelocity: TVector3Int64); + function GetParameterMinimum(const AMin, AMax: Int64): Int64; + function GetParameterMaximum(const AMin, AMax: Int64): Int64; end; - THailstones = specialize TList; + THailstones = specialize TObjectList; + + //{ TFirstCollisionPolynomial } + // + //TFirstCollisionPolynomial = class + //private + // FA: array[0..10] of TBigInt; + // FH: array[0..6] of TBigInt; + // procedure NormalizeCoefficients; + //public + // procedure Init(constref AHailstone1, AHailstone2, AHailstone3: THailstone; const t_0, t_1, t_2: Int64); + // function EvaluateAt(const AT0: Int64): TBigInt; + // function CalcPositiveIntegerRoot: Int64; + // function CalcT1(const AT0: Int64): Int64; + //end; { TNeverTellMeTheOdds } TNeverTellMeTheOdds = class(TSolver) private FMin, FMax: Int64; - FHailStones: THailstones; + FHailstones: THailstones; function AreIntersecting(constref AHailstone1, AHailstone2: THailstone): Boolean; + procedure FindRockThrow(const AIndex1, AIndex2, AIndex3: Integer); public constructor Create(const AMin: Int64 = 200000000000000; const AMax: Int64 = 400000000000000); destructor Destroy; override; @@ -51,8 +70,492 @@ type function GetPuzzleName: string; override; end; +const + CIterationThreshold = 0.00001; + CEpsilon = 0.0000000001; + implementation +{ THailstone } + +constructor THailstone.Create(const ALine: string); +var + split: TStringArray; +begin + split := ALine.Split([',', '@']); + Position.Init( + StrToInt64(Trim(split[0])), + StrToInt64(Trim(split[1])), + StrToInt64(Trim(split[2]))); + Velocity.Init( + StrToInt64(Trim(split[3])), + StrToInt64(Trim(split[4])), + StrToInt64(Trim(split[5]))); + //Position.init( + // StrToFloat(Trim(split[0])), + // StrToFloat(Trim(split[1])), + // StrToFloat(Trim(split[2]))); + //Velocity.init( + // StrToFloat(Trim(split[3])), + // StrToFloat(Trim(split[4])), + // StrToFloat(Trim(split[5]))); +end; + +constructor THailstone.Create(const APosition, AVelocity: TVector3Int64); +begin + Position := APosition; + Velocity := AVelocity; +end; + +function THailstone.GetParameterMinimum(const AMin, AMax: Int64): Int64; +var + i: TVector3DataRange; + boundary: Int64; +begin + Result := 0; + for i in TVector3DataRange do + begin + if Velocity.Data[i] > 0 then + boundary := AMin + else + boundary := AMax; + Result := Max(Result, Ceil64((boundary - Position.Data[i]) / Velocity.Data[i])); + end; +end; + +function THailstone.GetParameterMaximum(const AMin, AMax: Int64): Int64; +var + i: TVector3DataRange; + boundary: Int64; +begin + Result := Int64.MaxValue; + for i in TVector3DataRange do + begin + if Velocity.Data[i] > 0 then + boundary := AMax + else + boundary := AMin; + Result := Min(Result, Floor64((boundary - Position.Data[i]) / Velocity.Data[i])); + end; +end; + +//{ TFirstCollisionPolynomial } +// +//procedure TFirstCollisionPolynomial.NormalizeCoefficients; +//var +// shift: Integer; +// i: Low(FA)..High(FA); +// //gcd: TBigInt; +//begin +// // Eliminates zero constant term. +// shift := 0; +// while (shift <= High(FA)) and (FA[shift] = 0) do +// Inc(shift); +// +// if shift <= High(FA) then +// begin +// if shift > 0 then +// begin +// for i := Low(FA) to High(FA) - shift do +// FA[i] := FA[i + shift]; +// for i := High(FA) - shift + 1 to High(FA) do +// FA[i] := 0; +// end; +// +// //// Finds GCD of all coefficients. +// //gcd := FA[Low(FA)]; +// //for i := Low(FA) + 1 to High(FA) do +// // if FA[i] <> 0 then +// // gcd := TNumberTheory.GreatestCommonDivisor(gcd, FA[i]); +// //WriteLn('GCD: ', gcd); +// // +// //for i := Low(FA) to High(FA) do +// // FA[i] := FA[i] div gcd; +// end; +// +// //WriteLn('(', FA[10], ') * x^10 + (', FA[9], ') * x^9 + (', FA[8], ') * x^8 + (', FA[7], ') * x^7 + (', +// // FA[6], ') * x^6 + (', FA[5], ') * x^5 + (', FA[4], ') * x^4 + (', FA[3], ') * x^3 + (', FA[2], ') * x^2 + (', +// // FA[1], ') * x + (', FA[0], ')'); +//end; +// +//procedure TFirstCollisionPolynomial.Init(constref AHailstone1, AHailstone2, AHailstone3: THailstone; const t_0, t_1, +// t_2: Int64); +//var +// P_00, P_01, P_02, P_10, P_11, P_12, P_20, P_21, P_22, +// V_00, V_01, V_02, V_10, V_11, V_12, V_20, V_21, V_22: Int64; +// k: array[0..139] of TBigInt; +// // For debug calculations +// act, a_1, a_2, b_0, b_1, c_0, c_1, d_0, d_1, e_0, e_1, f_0, f_1, f_2: Int64; +//begin +// // Solving this non-linear equation system, with velocities V_i and start positions P_i: +// // V_0 * t_0 + P_0 = V_x * t_0 + P_x +// // V_1 * t_1 + P_1 = V_x * t_1 + P_x +// // V_2 * t_2 + P_2 = V_x * t_2 + P_x +// // Which gives: +// // P_x = (V_0 - V_x) * t_0 + P_0 +// // V_x = (V_0 * t_0 - V_1 * t_1 + P_0 - P_1) / (t_0 - t_1) +// // And with vertex components: +// // 1: 0 = (t_1 - t_0) * (V_00 * t_0 - V_20 * t_2 + P_00 - P_20) - (t_2 - t_0) * (V_00 * t_0 - V_10 * t_1 + P_00 - P_10) +// // 2: t_1 = (((V_01 - V_21) * t_2 + P_11 - P_21) * t_0 + (P_01 - P_11) * t_2) +// // / ((V_01 - V_11) * t_0 + (V_11 - V_21) * t_2 + P_01 - P_21) +// // 3: t_2 = (((V_02 - V_12) * t_1 + P_22 - P_12) * t_0 + (P_02 - P_22) * t_1) +// // / ((V_02 - V_22) * t_0 + (V_22 - V_12) * t_1 + P_02 - P_12) +// // for t_0, t_1, t_2 not pairwise equal. +// // With some substitutions depending only on t_0 this gives +// // 1: 0 = (t_1 - t_0) * (f_2 - V_20 * t_2) - (t_2 - t_0) * (f_1 - V_10 * t_1) +// // 2: t_1 = (b_0 + b_1 * t_2) / (c_0 + c_1 * t_2) +// // 3: t_2 = (d_0 + d_1 * t_1) / (e_0 + e_1 * t_1) +// // And 3 in 2 gives: +// // 4: g_2 * t_1^2 - g_1 * t_1 - g_0 = 0 +// // Then, with 4 and 3 in 1 and lengthy calculations with many substitutions (see constants k below, now independent of +// // t_0), the following polynomial can be constructed, with t_0 being a positive integer root of this polynomial. +// // y = a_10 * x^10 + a_9 * x^9 + ... + a_0 +// +// P_00 := Round(AHailstone1.Position.data[0]); +// P_01 := Round(AHailstone1.Position.data[1]); +// P_02 := Round(AHailstone1.Position.data[2]); +// P_10 := Round(AHailstone2.Position.data[0]); +// P_11 := Round(AHailstone2.Position.data[1]); +// P_12 := Round(AHailstone2.Position.data[2]); +// P_20 := Round(AHailstone3.Position.data[0]); +// P_21 := Round(AHailstone3.Position.data[1]); +// P_22 := Round(AHailstone3.Position.data[2]); +// V_00 := Round(AHailstone1.Velocity.data[0]); +// V_01 := Round(AHailstone1.Velocity.data[1]); +// V_02 := Round(AHailstone1.Velocity.data[2]); +// V_10 := Round(AHailstone2.Velocity.data[0]); +// V_11 := Round(AHailstone2.Velocity.data[1]); +// V_12 := Round(AHailstone2.Velocity.data[2]); +// V_20 := Round(AHailstone3.Velocity.data[0]); +// V_21 := Round(AHailstone3.Velocity.data[1]); +// V_22 := Round(AHailstone3.Velocity.data[2]); +// +// k[0] := P_00 - P_20; +// k[1] := P_00 - P_10; +// k[2] := P_11 - P_21; +// k[3] := P_01 - P_11; +// k[4] := P_01 - P_21; +// k[5] := P_22 - P_12; +// k[6] := P_02 - P_22; +// k[7] := P_02 - P_12; +// k[8] := V_11 - V_21; +// k[9] := V_22 - V_12; +// k[10] := V_01 - V_21; +// k[11] := V_01 - V_11; +// k[12] := V_02 - V_12; +// k[13] := V_02 - V_22; +// +// FH[0] := k[11] * k[9] + k[8] * k[12]; +// FH[1] := k[4] * k[9] + k[8] * k[6]; +// FH[2] := k[11] * k[13] - k[10] * k[12]; +// FH[3] := k[11] * k[7] + k[4] * k[13] + k[8] * k[5] - k[2] * k[9] - k[10] * k[6] - k[3] * k[12]; +// FH[4] := k[4] * k[7] - k[3] * k[6]; +// FH[5] := k[10] * k[5] + k[2] * k[13]; +// FH[6] := k[3] * k[5] + k[2] * k[7]; +// +// k[14] := V_00 * k[9] - V_20 * k[12]; +// k[15] := k[0] * k[9] - V_20 * k[6]; +// k[16] := V_00 * k[13]; +// k[17] := V_00 * k[7] + k[0] * k[13] - V_20 * k[5]; +// k[18] := k[0] * k[7]; +// k[19] := k[5] - k[7]; +// k[20] := 2 * FH[2] * FH[3]; +// k[21] := FH[3] * FH[3]; +// k[22] := k[21] + 2 * FH[2] * FH[4]; +// k[23] := 2 * FH[3] * FH[4]; +// k[24] := 2 * FH[0] * FH[1]; +// k[25] := FH[0] * FH[0]; // KILL? +// k[26] := FH[5] * k[25]; // KILL? +// k[126] := FH[5] * FH[0]; +// k[127] := FH[5] * FH[1] + FH[6] * FH[0]; +// k[128] := FH[6] * FH[1]; +// k[27] := FH[5] * k[24] + FH[6] * k[25]; // KILL? +// k[28] := FH[1] * FH[1]; // KILL? +// k[29] := FH[5] * k[28] + FH[6] * k[24]; // KILL? +// k[30] := FH[6] * k[28]; // KILL? +// k[31] := FH[2] * FH[2]; +// k[132] := k[20] + 4 * k[126]; +// k[133] := k[22] + 4 * k[127]; +// k[134] := k[23] + 4 * k[128]; +// k[32] := k[31] + 4 * k[26]; // KILL? +// k[33] := k[20] + 4 * k[27]; // KILL? +// k[34] := k[22] + 4 * k[29]; // KILL? +// k[35] := k[23] + 4 * k[30]; // KILL? +// k[36] := k[31] + 2 * k[26]; // KILL? +// k[37] := k[20] + 2 * k[27]; // KILL? +// k[38] := k[22] + 2 * k[29]; // KILL? +// k[39] := k[23] + 2 * k[30]; // KILL? +// k[137] := k[20] + 2 * k[126]; +// k[138] := k[22] + 2 * k[127]; +// k[139] := k[23] + 2 * k[128]; +// k[40] := k[14] + V_10 * (k[12] - k[9]); +// k[41] := k[15] + V_10 * k[6]; +// k[42] := k[16] - k[14] - V_10 * k[13] - (k[12] - k[9]) * V_00; +// k[43] := k[17] - k[15] + V_10 * k[19] - (k[12] - k[9]) * k[1] - k[6] * V_00; +// k[44] := k[18] - k[6] * k[1]; +// k[45] := k[42] * FH[0] - k[40] * FH[2]; +// k[46] := k[42] * FH[1] + k[43] * FH[0] - k[41] * FH[2] - k[40] * FH[3]; +// k[47] := k[43] * FH[1] + k[44] * FH[0] - k[41] * FH[3] - k[40] * FH[4]; +// k[48] := k[44] * FH[1] - k[41] * FH[4]; +// k[49] := k[42] * FH[2]; +// k[50] := k[40] * k[31] - k[49] * FH[0]; +// k[51] := k[42] * FH[3] + k[43] * FH[2]; +// k[52] := k[40] * k[137] + k[41] * k[31] - k[51] * FH[0] - k[49] * FH[1]; +// k[53] := k[42] * FH[4] + k[43] * FH[3] + k[44] * FH[2]; +// k[54] := k[40] * k[138] + k[41] * k[137] - k[53] * FH[0] - k[51] * FH[1]; +// k[55] := k[43] * FH[4] + k[44] * FH[3]; +// k[56] := k[40] * k[139] + k[41] * k[138] - k[55] * FH[0] - k[53] * FH[1]; +// k[57] := k[44] * FH[4]; +// k[58] := FH[4] * FH[4]; +// k[59] := k[40] * k[58] + k[41] * k[139] - k[57] * FH[0] - k[55] * FH[1]; +// k[60] := k[41] * k[58] - k[57] * FH[1]; +// k[61] := k[13] * V_00 - k[16]; +// k[62] := 2 * k[25] * k[61]; +// k[63] := k[13] * k[1] - k[19] * V_00 - k[17]; +// k[64] := 2 * (k[24] * k[61] + k[25] * k[63]); +// k[65] := - k[19] * k[1] - k[18]; +// k[66] := 2 * (k[28] * k[61] + k[24] * k[63] + k[25] * k[65]); +// k[67] := 2 * (k[28] * k[63] + k[24] * k[65]); +// k[68] := 2 * k[28] * k[65]; +// k[69] := k[50] + k[62]; +// k[70] := k[52] + k[64]; +// k[71] := k[54] + k[66]; +// k[72] := k[56] + k[67]; +// k[73] := k[59] + k[68]; +// k[74] := k[45] * k[45]; +// k[75] := 2 * k[45] * k[46]; +// k[76] := k[46] * k[46] + 2 * k[45] * k[47]; +// k[77] := 2 * (k[45] * k[48] + k[46] * k[47]); +// k[78] := k[47] * k[47] + 2 * k[46] * k[48]; +// k[79] := 2 * k[47] * k[48]; +// k[80] := k[48] * k[48]; +// +// FA[0] := k[58] * k[80] - k[60] * k[60]; +// FA[1] := k[134] * k[80] + k[58] * k[79] - 2 * k[73] * k[60]; +// FA[2] := k[133] * k[80] + k[134] * k[79] + k[58] * k[78] - k[73] * k[73] - 2 * k[72] * k[60]; +// FA[3] := k[133] * k[79] + k[134] * k[78] + k[58] * k[77] + k[132] * k[80] +// - 2 * (k[71] * k[60] + k[72] * k[73]); +// FA[4] := k[31] * k[80] + k[133] * k[78] + k[134] * k[77] + k[58] * k[76] + k[132] * k[79] - k[72] * k[72] +// - 2 * (k[70] * k[60] + k[71] * k[73]); +// FA[5] := k[31] * k[79] + k[133] * k[77] + k[134] * k[76] + k[58] * k[75] + k[132] * k[78] +// - 2 * (k[69] * k[60] + k[70] * k[73] + k[71] * k[72]); +// FA[6] := k[31] * k[78] + k[133] * k[76] + k[134] * k[75] + k[58] * k[74] + k[132] * k[77] - k[71] * k[71] +// - 2 * (k[69] * k[73] + k[70] * k[72]); +// FA[7] := k[31] * k[77] + k[133] * k[75] + k[134] * k[74] + k[132] * k[76] - 2 * (k[69] * k[72] + k[70] * k[71]); +// FA[8] := k[31] * k[76] + k[132] * k[75] + k[133] * k[74] - k[70] * k[70] - 2 * k[69] * k[71]; +// FA[9] := k[31] * k[75] + k[132] * k[74] - 2 * k[69] * k[70]; +// FA[10] := k[31] * k[74] - k[69] * k[69]; +// +// // Debug calculations +// //a_1 := V_00 * t_0 + P_00 - P_20; +// //a_2 := V_00 * t_0 + P_00 - P_10; +// //b_0 := (P_11 - P_21) * t_0; +// //b_1 := (V_01 - V_21) * t_0 + P_01 - P_11; +// //c_0 := (V_01 - V_11) * t_0 + P_01 - P_21; +// //c_1 := V_11 - V_21; +// //d_0 := (P_22 - P_12) * t_0; +// //d_1 := (V_02 - V_12) * t_0 + P_02 - P_22; +// //e_0 := (V_02 - V_22) * t_0 + P_02 - P_12; +// //e_1 := V_22 - V_12; +// //f_2 := c_0 * e_1 + c_1 * d_1; +// //f_1 := c_0 * e_0 + c_1 * d_0 - b_0 * e_1 - b_1 * d_1; +// //f_0 := b_1 * d_0 + b_0 * e_0; +// // +// //act := f_2 * t_1 * t_1 + f_1 * t_1 - f_0; +// //Write('debug10: ', 0 = act, ' '); +// // +// //if f_2 <> 0 then +// //begin +// // act := Round(- f_1 / (2 * f_2) + Sqrt((f_1 / (2 * f_2)) * (f_1 / (2 * f_2)) + f_0 / f_2)); +// // Write('debug15: ', t_1 = act); +// // act := Round(- f_1 / (2 * f_2) - Sqrt((f_1 / (2 * f_2)) * (f_1 / (2 * f_2)) + f_0 / f_2)); +// // Write(' OR ', t_1 = act, ' '); +// //end; +// // +// //act := (e_0 + e_1 * t_1) * t_2 - (d_0 + d_1 * t_1); +// //Write('debug20: ', 0 = act, ' '); +// // +// //act := (a_1 * e_1 - V_20 * d_1 + V_10 * (d_1 - e_1 * t_0)) * t_1 * t_1 +// // + (a_1 * e_0 - V_20 * d_0 - t_0 * (a_1 * e_1 - V_20 * d_1) - (d_1 - e_1 * t_0) * a_2 + V_10 * (d_0 - e_0 * t_0)) * t_1 +// // + t_0 * (V_20 * d_0 - a_1 * e_0) + (e_0 * t_0 - d_0) * a_2; +// //Write('debug30: ', 0 = act, ' '); +// // +// //act := Round((a_1 * e_1 - V_20 * d_1 + V_10 * (d_1 - e_1 * t_0)) * (f_1 * f_1 + 2 * f_0 * f_2 - f_1 * Sqrt(f_1 * f_1 + 4 * f_0 * f_2)) +// // + (a_1 * e_0 - V_20 * d_0 - t_0 * (a_1 * e_1 - V_20 * d_1) - (d_1 - e_1 * t_0) * a_2 + V_10 * (d_0 - e_0 * t_0)) * (- f_1 * f_2 + f_2 * Sqrt(f_1 * f_1 + 4 * f_0 * f_2)) +// // + t_0 * (V_20 * d_0 - a_1 * e_0) * 2 * f_2 * f_2 + (e_0 * t_0 - d_0) * a_2 * 2 * f_2 * f_2); +// //Write('debug40: ', 0 = act, ' '); +// // +// //Write('debug41: ', +// // a_1 * k[9] - V_20 * d_1 +// // = k[14] * t_0 + k[15], ' '); +// //Write('debug42: ', +// // d_1 - k[9] * t_0 +// // = (k[12] - k[9]) * t_0 + k[6], ' '); +// //Write('debug43: ', +// // a_1 * e_0 - V_20 * d_0 +// // = k[16] * t_0 * t_0 + k[17] * t_0 + k[18], ' '); +// //Write('debug44: ', +// // d_0 - e_0 * t_0 +// // = - k[13] * t_0 * t_0 + k[19] * t_0, ' '); +// //Write('debug45: ', +// // f_1 * f_1 +// // = FH[2] * FH[2] * t_0 * t_0 * t_0 * t_0 + k[20] * t_0 * t_0 * t_0 + k[22] * t_0 * t_0 + k[23] * t_0 + FH[4] * FH[4], ' '); +// //Write('debug46: ', +// // f_2 * f_2 +// // = FH[0] * FH[0] * t_0 * t_0 + k[24] * t_0 + FH[1] * FH[1], ' '); +// //Write('debug47: ', +// // f_0 * f_2 +// // = k[126] * t_0 * t_0 * t_0 + k[127] * t_0 * t_0 + k[128] * t_0, ' '); +// //Write('debug48: ', +// // f_1 * f_1 + 4 * f_0 * f_2 +// // = k[31] * t_0 * t_0 * t_0 * t_0 + k[132] * t_0 * t_0 * t_0 + k[133] * t_0 * t_0 + k[134] * t_0 + k[58], ' '); +// //Write('debug49: ', +// // f_1 * f_1 + 2 * f_0 * f_2 +// // = k[31] * t_0 * t_0 * t_0 * t_0 + k[137] * t_0 * t_0 * t_0 + k[138] * t_0 * t_0 + k[139] * t_0 + k[58], ' '); +// // +// //act := Round((k[14] * t_0 + k[15] + V_10 * ((k[12] - k[9]) * t_0 + k[6])) * (k[31] * t_0 * t_0 * t_0 * t_0 + k[137] * t_0 * t_0 * t_0 + k[138] * t_0 * t_0 + k[139] * t_0 + k[58] - f_1 * sqrt(f_1 * f_1 + 4 * f_0 * f_2)) +// // + (k[16] * t_0 * t_0 + k[17] * t_0 + k[18] - t_0 * (k[14] * t_0 + k[15]) - ((k[12] - k[9]) * t_0 + k[6]) * a_2 - V_10 * (k[13] * t_0 * t_0 - k[19] * t_0)) * (- f_1 * f_2 + f_2 * sqrt(f_1 * f_1 + 4 * f_0 * f_2)) +// // - 2 * t_0 * (k[16] * t_0 * t_0 + k[17] * t_0 + k[18]) * (FH[0] * FH[0] * t_0 * t_0 + k[24] * t_0 + FH[1] * FH[1]) + 2 * (k[13] * t_0 * t_0 - k[19] * t_0) * a_2 * (FH[0] * FH[0] * t_0 * t_0 + k[24] * t_0 + FH[1] * FH[1])); +// //Write('debug50: ', 0 = act, ' '); +// // +// //Write('debug53: ', +// // 0 = Round((k[40] * t_0 + k[41]) * (k[31] * t_0 * t_0 * t_0 * t_0 + k[137] * t_0 * t_0 * t_0 + k[138] * t_0 * t_0 + k[139] * t_0 + k[58] - f_1 * sqrt(f_1 * f_1 + 4 * f_0 * f_2)) +// // + ((k[16] - k[14] - V_10 * k[13] - (k[12] - k[9]) * V_00) * t_0 * t_0 + (k[17] - k[15] + V_10 * k[19] - (k[12] - k[9]) * k[1] - k[6] * V_00) * t_0 + k[18] - k[6] * k[1]) * (- f_1 * f_2 + f_2 * sqrt(f_1 * f_1 + 4 * f_0 * f_2)) +// // - 2 * t_0 * (k[16] * t_0 * t_0 + k[17] * t_0 + k[18]) * (FH[0] * FH[0] * t_0 * t_0 + k[24] * t_0 + FH[1] * FH[1]) + 2 * (k[13] * t_0 * t_0 - k[19] * t_0) * a_2 * (FH[0] * FH[0] * t_0 * t_0 + k[24] * t_0 + FH[1] * FH[1])), +// // ' '); +// // +// //Write('debug55: ', +// // 0 = Round((k[40] * t_0 + k[41]) * (k[31] * t_0 * t_0 * t_0 * t_0 + k[137] * t_0 * t_0 * t_0 + k[138] * t_0 * t_0 + k[139] * t_0 + k[58]) +// // - (k[40] * t_0 + k[41]) * f_1 * sqrt(f_1 * f_1 + 4 * f_0 * f_2) +// // + (k[42] * t_0 * t_0 + k[43] * t_0 + k[44]) * (- f_1 * f_2 + f_2 * sqrt(f_1 * f_1 + 4 * f_0 * f_2)) +// // - 2 * t_0 * (k[16] * t_0 * t_0 + k[17] * t_0 + k[18]) * (FH[0] * FH[0] * t_0 * t_0 + k[24] * t_0 + FH[1] * FH[1]) + 2 * (k[13] * t_0 * t_0 - k[19] * t_0) * a_2 * (FH[0] * FH[0] * t_0 * t_0 + k[24] * t_0 + FH[1] * FH[1])), +// // ' '); +// // +// //Write('debug70: ', +// // 0 = Round(((k[42] * t_0 * t_0 + k[43] * t_0 + k[44]) * (FH[0] * t_0 + FH[1]) - (k[40] * t_0 + k[41]) * (FH[2] * t_0 * t_0 + FH[3] * t_0 + FH[4])) * sqrt(f_1 * f_1 + 4 * f_0 * f_2)) +// // + (k[40] * t_0 + k[41]) * (k[31] * t_0 * t_0 * t_0 * t_0 + k[137] * t_0 * t_0 * t_0 + k[138] * t_0 * t_0 + k[139] * t_0 + k[58]) +// // - (k[42] * t_0 * t_0 + k[43] * t_0 + k[44]) * (FH[2] * t_0 * t_0 + FH[3] * t_0 + FH[4]) * (FH[0] * t_0 + FH[1]) +// // - 2 * t_0 * (k[16] * t_0 * t_0 + k[17] * t_0 + k[18]) * (FH[0] * FH[0] * t_0 * t_0 + k[24] * t_0 + FH[1] * FH[1]) + 2 * (k[13] * t_0 * t_0 - k[19] * t_0) * (V_00 * t_0 + k[1]) * (FH[0] * FH[0] * t_0 * t_0 + k[24] * t_0 + FH[1] * FH[1]), +// // ' '); +//// +//// Write('debug73: ', +//// 0 = Round(( +//// (k[42] * FH[0] - k[40] * FH[2]) * t_0 * t_0 * t_0 +//// + (k[42] * FH[1] + k[43] * FH[0] - k[41] * FH[2] - k[40] * FH[3]) * t_0 * t_0 +//// + (k[43] * FH[1] + k[44] * FH[0] - k[41] * FH[3] - k[40] * FH[4]) * t_0 +//// + k[44] * FH[1] - k[41] * FH[4] +//// ) * sqrt(f_1 * f_1 + 4 * f_0 * f_2)) +//// + (k[40] * k[31] - k[42] * FH[2] * FH[0]) * t_0 * t_0 * t_0 * t_0 * t_0 +//// + (k[40] * k[137] + k[41] * k[31] - k[42] * FH[3] * FH[0] - k[43] * FH[2] * FH[0] - k[42] * FH[2] * FH[1]) * t_0 * t_0 * t_0 * t_0 +//// + (k[40] * k[138] + k[41] * k[137] - k[42] * FH[4] * FH[0] - k[43] * FH[3] * FH[0] - k[44] * FH[2] * FH[0] - k[42] * FH[3] * FH[1] - k[43] * FH[2] * FH[1]) * t_0 * t_0 * t_0 +//// + (k[40] * k[139] + k[41] * k[138] - k[43] * FH[4] * FH[0] - k[44] * FH[3] * FH[0] - k[42] * FH[4] * FH[1] - k[43] * FH[3] * FH[1] - k[44] * FH[2] * FH[1]) * t_0 * t_0 +//// + (k[40] * k[58] + k[41] * k[139] - k[44] * FH[4] * FH[0] - k[43] * FH[4] * FH[1] - k[44] * FH[3] * FH[1]) * t_0 +//// + k[41] * k[58] - k[44] * FH[4] * FH[1] +//// + 2 * (k[13] * V_00 * FH[0] * FH[0] - k[16] * FH[0] * FH[0]) * t_0 * t_0 * t_0 * t_0 * t_0 +//// + 2 * (k[13] * V_00 * k[24] + k[13] * k[1] * FH[0] * FH[0] - k[19] * V_00 * FH[0] * FH[0] - k[16] * k[24] - k[17] * FH[0] * FH[0]) * t_0 * t_0 * t_0 * t_0 +//// + 2 * (k[13] * V_00 * FH[1] * FH[1] + k[13] * k[1] * k[24] - k[19] * V_00 * k[24] - k[19] * k[1] * FH[0] * FH[0] - k[16] * FH[1] * FH[1] - k[17] * k[24] - k[18] * FH[0] * FH[0]) * t_0 * t_0 * t_0 +//// + 2 * (k[13] * k[1] * FH[1] * FH[1] - k[19] * V_00 * FH[1] * FH[1] - k[19] * k[1] * k[24] - k[17] * FH[1] * FH[1] - k[18] * k[24]) * t_0 * t_0 +//// + 2 * (- k[19] * k[1] * FH[1] * FH[1] - k[18] * FH[1] * FH[1]) * t_0, +//// ' '); +//// +//// Write('debug78: ', +//// 0 = Round((k[45] * t_0 * t_0 * t_0 + k[46] * t_0 * t_0 + k[47] * t_0 + k[48]) * sqrt(f_1 * f_1 + 4 * f_0 * f_2)) +//// + (k[50] + k[62]) * t_0 * t_0 * t_0 * t_0 * t_0 + (k[52] + k[64]) * t_0 * t_0 * t_0 * t_0 + (k[54] + k[66]) * t_0 * t_0 * t_0 + (k[56] + k[67]) * t_0 * t_0 + (k[59] + k[68]) * t_0 + k[60], +//// ' '); +//// +//// Write('debug80: ', +//// 0 = Round((k[45] * t_0 * t_0 * t_0 + k[46] * t_0 * t_0 + k[47] * t_0 + k[48]) * sqrt(k[31] * t_0 * t_0 * t_0 * t_0 + k[132] * t_0 * t_0 * t_0 + k[133] * t_0 * t_0 + k[134] * t_0 + k[58]) +//// + k[69] * t_0 * t_0 * t_0 * t_0 * t_0 + k[70] * t_0 * t_0 * t_0 * t_0 + k[71] * t_0 * t_0 * t_0 + k[72] * t_0 * t_0 + k[73] * t_0 + k[60]), +//// ' '); +//// WriteLn; +//// WriteLn(' 0 = ((', k[45], ') * x^3 + (', k[46], ') * x^2 + (', k[47], ') * x + (', k[48], ')) * sqrt((', k[31], ') * x^4 + (', k[132], ') * x^3 + (', k[133], ') * x^2 + (', k[134], ') * x + (', k[58], ')) + (', +//// k[69], ') * x^5 + (', k[70], ') * x^4 + (', k[71], ') * x^3 + (', k[72], ') * x^2 + (', k[73], ') * x + (', k[60], ')'); +// +// Write('debug83: ', +// (k[45] * t_0 * t_0 * t_0 + k[46] * t_0 * t_0 + k[47] * t_0 + k[48]) * (k[45] * t_0 * t_0 * t_0 + k[46] * t_0 * t_0 + k[47] * t_0 + k[48]) * (k[31] * t_0 * t_0 * t_0 * t_0 + k[132] * t_0 * t_0 * t_0 + k[133] * t_0 * t_0 + k[134] * t_0 + k[58]) = +// (k[69] * t_0 * t_0 * t_0 * t_0 * t_0 + k[70] * t_0 * t_0 * t_0 * t_0 + k[71] * t_0 * t_0 * t_0 + k[72] * t_0 * t_0 + k[73] * t_0 + k[60]) * (k[69] * t_0 * t_0 * t_0 * t_0 * t_0 + k[70] * t_0 * t_0 * t_0 * t_0 + k[71] * t_0 * t_0 * t_0 + k[72] * t_0 * t_0 + k[73] * t_0 + k[60]), +// ' '); +// Write('debug85: ', +// 0 = +// ( +// k[45] * k[45] * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 +// + 2 * k[45] * k[46] * t_0 * t_0 * t_0 * t_0 * t_0 +// + k[46] * k[46] * t_0 * t_0 * t_0 * t_0 +// + 2 * k[45] * k[47] * t_0 * t_0 * t_0 * t_0 +// + 2 * k[45] * k[48] * t_0 * t_0 * t_0 +// + 2 * k[46] * k[47] * t_0 * t_0 * t_0 +// + k[47] * k[47] * t_0 * t_0 +// + 2 * k[46] * k[48] * t_0 * t_0 +// + 2 * k[47] * k[48] * t_0 +// + k[48] * k[48] +// ) * (k[31] * t_0 * t_0 * t_0 * t_0 + k[132] * t_0 * t_0 * t_0 + k[133] * t_0 * t_0 + k[134] * t_0 + k[58]) +// - k[69] * k[69] * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 +// - 2 * k[69] * k[70] * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 +// - (k[70] * k[70] + 2 * k[69] * k[71]) * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 +// - 2 * (k[69] * k[72] + k[70] * k[71]) * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 +// - (k[71] * k[71] + 2 * k[69] * k[73] + 2 * k[70] * k[72]) * t_0 * t_0 * t_0 * t_0 * t_0 * t_0 +// - 2 * (k[69] * k[60] + k[70] * k[73] + k[71] * k[72]) * t_0 * t_0 * t_0 * t_0 * t_0 +// - (k[72] * k[72] + 2 * k[70] * k[60] + 2 * k[71] * k[73]) * t_0 * t_0 * t_0 * t_0 +// - 2 * (k[71] * k[60] + k[72] * k[73]) * t_0 * t_0 * t_0 +// - (k[73] * k[73] + 2 * k[72] * k[60]) * t_0 * t_0 +// - 2 * k[73] * k[60] * t_0 +// - k[60] * k[60], +// ' '); +// +// WriteLn('debug96: ', EvaluateAt(t_0) = 0); +// +// NormalizeCoefficients; +// +// WriteLn('debug99: ', EvaluateAt(t_0) = 0, ' '); +//end; +// +//function TFirstCollisionPolynomial.EvaluateAt(const AT0: Int64): TBigInt; +//var +// i: Low(FA)..High(FA); +//begin +// Result := TBigInt.Zero; +// for i := High(FA) downto Low(FA) do +// Result := Result * AT0 + FA[i]; +//end; +// +//function TFirstCollisionPolynomial.CalcPositiveIntegerRoot: Int64; +//var +// dividers: TDividers; +// factors: TInt64Array; +// divider: Int64; +//begin +// Result := 0; +// //factors := TIntegerFactorization.PollardsRhoAlgorithm(FA[0]); +// //dividers := TDividers.Create(factors); +// // +// //try +// //for divider in dividers do +// //begin +// // //WriteLn('Check if ', divider, ' is a root...'); +// // if EvaluateAt(divider) = 0 then +// // begin +// // Result := divider; +// // Break; +// // end; +// //end; +// // +// //finally +// // dividers.Free; +// //end; +//end; +// +//function TFirstCollisionPolynomial.CalcT1(const AT0: Int64): Int64; +//var +// g_0, g_1, g_2: Int64; +// g: Extended; +//begin +// //g_2 := FH[0] * AT0 + FH[1]; +// //g_1 := FH[2] * AT0 * AT0 + FH[3] * AT0 + FH[4]; +// //g_0 := FH[5] * AT0 * AT0 + FH[6] * AT0; +// //g := - g_1 / (2 * g_2); +// //Result := Round(g + sqrt(g * g + g_0)); +//end; + { TNeverTellMeTheOdds } function TNeverTellMeTheOdds.AreIntersecting(constref AHailstone1, AHailstone2: THailstone): Boolean; @@ -60,58 +563,141 @@ var m1, m2, x, y: Double; begin Result := False; - m1 := AHailstone1.VY / AHailstone1.VX; - m2 := AHailstone2.VY / AHailstone2.VX; + m1 := AHailstone1.Velocity.Y / AHailstone1.Velocity.X; + //m1 := AHailstone1.Velocity.data[1] / AHailstone1.Velocity.data[0]; + m2 := AHailstone2.Velocity.Y / AHailstone2.Velocity.X; + //m2 := AHailstone2.Velocity.data[1] / AHailstone2.Velocity.data[0]; if m1 <> m2 then begin - x := (AHailstone2.Y - m2 * AHailstone2.X - AHailstone1.Y + m1 * AHailstone1.X) / (m1 - m2); + x := (AHailstone2.Position.Y - m2 * AHailstone2.Position.X + - AHailstone1.Position.Y + m1 * AHailstone1.Position.X) + / (m1 - m2); + //x := (AHailstone2.Position.data[1] - m2 * AHailstone2.Position.data[0] + // - AHailstone1.Position.data[1] + m1 * AHailstone1.Position.data[0]) + // / (m1 - m2); if (FMin <= x) and (x <= FMax) - and (x * Sign(AHailstone1.VX) >= AHailstone1.X * Sign(AHailstone1.VX)) - and (x * Sign(AHailstone2.VX) >= AHailstone2.X * Sign(AHailstone2.VX)) then + and (x * Sign(AHailstone1.Velocity.X) >= AHailstone1.Position.X * Sign(AHailstone1.Velocity.X)) + //and (x * Sign(AHailstone1.Velocity.data[0]) >= AHailstone1.Position.data[0] * Sign(AHailstone1.Velocity.data[0])) + and (x * Sign(AHailstone2.Velocity.X) >= AHailstone2.Position.X * Sign(AHailstone2.Velocity.X)) + //and (x * Sign(AHailstone2.Velocity.data[0]) >= AHailstone2.Position.data[0] * Sign(AHailstone2.Velocity.data[0])) + then begin - y := m1 * (x - AHailstone1.X) + AHailstone1.Y; + y := m1 * (x - AHailstone1.Position.X) + AHailstone1.Position.Y; + y := m1 * (x - AHailstone1.Position.X) + AHailstone1.Position.Y; if (FMin <= y) and (y <= FMax) then Result := True end; end; end; +// For debug calculations: +Const + T : array[0..4] of Byte = (5, 3, 4, 6, 1); + +procedure TNeverTellMeTheOdds.FindRockThrow(const AIndex1, AIndex2, AIndex3: Integer); +var + i: TVector3DataRange; + //i, j, k: Integer; + //x0, x1, x2: Extended; + //f: TFirstCollisionPolynomial; + t0, t1, t2, t0Min, t0Max, t1Min, t1Max, t2Min, t2Max: Int64; + boundary: Int64; + //p, v: Tvector3_extended; + //test: TBigInt; +begin + //WriteLn; + WriteLn(AIndex1, ' ', AIndex2, ' ', AIndex3, ' '); + + t0Min := FHailstones[AIndex1].GetParameterMinimum(FMin, FMax); + t0Max := FHailstones[AIndex1].GetParameterMaximum(FMin, FMax); + WriteLn('t0 bounds: ', t0Min, ' ', t0Max); + t1Min := FHailstones[AIndex2].GetParameterMinimum(FMin, FMax); + t1Max := FHailstones[AIndex2].GetParameterMaximum(FMin, FMax); + WriteLn('t1 bounds: ', t1Min, ' ', t1Max); + t2Min := FHailstones[AIndex3].GetParameterMinimum(FMin, FMax); + t2Max := FHailstones[AIndex3].GetParameterMaximum(FMin, FMax); + WriteLn('t2 bounds: ', t2Min, ' ', t2Max); + + //t0 := t0Min >> 1 + t0Max >> 1; + //WriteLn('t0: ', t0); + //t1 := t1Min >> 1 + t1Max >> 1; + //WriteLn('t1: ', t1); + //t2 := t2Min >> 1 + t2Max >> 1; + //WriteLn('t2: ', t2); + + //f := TFirstCollisionPolynomial.Create; + //f.Init(FHailstones[AIndex1], FHailstones[AIndex2], FHailstones[AIndex3], T[AIndex1], T[AIndex2], T[AIndex3]); + ////t0 := f.CalcPositiveIntegerRoot; + ////WriteLn('t0: ', t0, ' ', t0 = T[AIndex1]); + ////t1 := f.CalcT1(t0); + ////WriteLn(', t1: ', t1); + //f.Free; + + //// V_x = (V_0 * t_0 - V_1 * t_1 + P_0 - P_1) / (t_0 - t_1) + //v := (FHailstones[AIndex1].Velocity * t0 - FHailstones[AIndex2].Velocity * t1 + // + FHailstones[AIndex1].Position - FHailstones[AIndex2].Position) / (t0 - t1); + //// P_x = (V_0 - V_x) * t_0 + P_0 + //p := (FHailstones[AIndex1].Velocity - v) * t0 + FHailstones[AIndex1].Position; + //FPart2 := Round(p.data[0]) + Round(p.data[1]) + Round(p.data[2]); + + //for i := 0 to FHailstones.Count - 3 do + // for j := i + 1 to FHailstones.Count - 2 do + // for k:= j + 1 to FHailstones.Count - 1 do + // begin + // WriteLn(i, j, k); + // solver := TRockThrowSolver.Create(FHailstones[i], FHailstones[j], FHailstones[k], 0); + // case i of + // 0: x0 := 5; + // 1: x0 := 3; + // 2: x0 := 4; + // end; + // f := solver.CalcValue(x0); + // solver.Free; + // end; + + //for i := 80 to 120 do + //begin + // solver := TRockThrowSolver.Create(FHailstones[0], FHailstones[1], FHailstones[2], 0); + // x0 := i / 20; + // f := solver.CalcValue(x0); + // WriteLn(x0, ' ', f.Valid, ' ', f.Value); + // solver.Free; + //end; +end; + constructor TNeverTellMeTheOdds.Create(const AMin: Int64; const AMax: Int64); begin FMin := AMin; FMax := AMax; - FHailStones := THailstones.Create; + FHailstones := THailstones.Create; end; destructor TNeverTellMeTheOdds.Destroy; begin - FHailStones.Free; + FHailstones.Free; inherited Destroy; end; procedure TNeverTellMeTheOdds.ProcessDataLine(const ALine: string); -var - split: TStringArray; - hailstone: THailstone; begin - split := ALine.Split([',', '@']); - hailstone.X := StrToInt64(Trim(split[0])); - hailstone.Y := StrToInt64(Trim(split[1])); - hailstone.Z := StrToInt64(Trim(split[2])); - hailstone.VX := StrToInt(Trim(split[3])); - hailstone.VY := StrToInt(Trim(split[4])); - hailstone.VZ := StrToInt(Trim(split[5])); - FHailStones.Add(hailstone); + FHailstones.Add(THailstone.Create(ALine)); end; procedure TNeverTellMeTheOdds.Finish; var - i, j: Integer; + i, j, k: Integer; begin - for i := 0 to FHailStones.Count - 2 do - for j := i + 1 to FHailStones.Count - 1 do - if AreIntersecting(FHailStones[i], FHailStones[j]) then + for i := 0 to FHailstones.Count - 2 do + for j := i + 1 to FHailstones.Count - 1 do + if AreIntersecting(FHailstones[i], FHailstones[j]) then Inc(FPart1); + + //for i := 0 to FHailstones.Count - 1 do + // for j := 0 to FHailstones.Count - 1 do + // for k := 0 to FHailstones.Count - 1 do + // if (i <> j) and (i <> k) and (j <> k) then + // FindRockThrow(i, j, k); + FindRockThrow(0, 1, 2); end; function TNeverTellMeTheOdds.GetDataFileName: string; diff --git a/tests/UNeverTellMeTheOddsTestCases.pas b/tests/UNeverTellMeTheOddsTestCases.pas index 8b5c282..a2f1235 100644 --- a/tests/UNeverTellMeTheOddsTestCases.pas +++ b/tests/UNeverTellMeTheOddsTestCases.pas @@ -33,6 +33,7 @@ type function CreateSolver: ISolver; override; published procedure TestPart1; + procedure TestPart2; end; { TNeverTellMeTheOddsExampleTestCase } @@ -42,6 +43,7 @@ type function CreateSolver: ISolver; override; published procedure TestPart1; + procedure TestPart2; end; { TNeverTellMeTheOddsTestCase } @@ -77,6 +79,11 @@ begin AssertEquals(15107, FSolver.GetResultPart1); end; +procedure TNeverTellMeTheOddsFullDataTestCase.TestPart2; +begin + AssertEquals(-1, FSolver.GetResultPart2); +end; + { TNeverTellMeTheOddsExampleTestCase } function TNeverTellMeTheOddsExampleTestCase.CreateSolver: ISolver; @@ -89,6 +96,11 @@ begin AssertEquals(2, FSolver.GetResultPart1); end; +procedure TNeverTellMeTheOddsExampleTestCase.TestPart2; +begin + AssertEquals(47, FSolver.GetResultPart2); +end; + { TNeverTellMeTheOddsTestCase } function TNeverTellMeTheOddsTestCase.CreateSolver: ISolver;