Updated day 12 WIP solver
This commit is contained in:
parent
fb2f813701
commit
1d399cc5b6
|
@ -22,7 +22,7 @@ unit UHotSprings;
|
|||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Math, Generics.Collections, USolver, UCommon;
|
||||
Classes, SysUtils, Math, Generics.Collections, USolver, UCommon, UMultiIndexEnumerator;
|
||||
|
||||
const
|
||||
COperationalChar = '.';
|
||||
|
@ -30,7 +30,7 @@ const
|
|||
CWildcardChar = '?';
|
||||
//COperationalPatternChars = [COperationalChar, CWildcardChar];
|
||||
//CDamagedPatternChars = [CDamagedChar, CWildcardChar];
|
||||
CPart2Repetition = 2;
|
||||
CPart2Repetition = 1;
|
||||
|
||||
type
|
||||
|
||||
|
@ -52,6 +52,7 @@ type
|
|||
|
||||
TValidationLengths = array of array of Integer;
|
||||
//TPatternLengths = array of Integer;
|
||||
// TODO: TIntegerArray probably not needed.
|
||||
TIntegerArray = array of Integer;
|
||||
|
||||
{ TDamage }
|
||||
|
@ -61,16 +62,62 @@ type
|
|||
end;
|
||||
|
||||
TDamages = specialize TList<TDamage>;
|
||||
// TODO: Instead of using TDamagesBlocks, "block" should be a record of a string and its associated list TDamages.
|
||||
TDamagesBlocks = specialize TObjectList<TDamages>;
|
||||
|
||||
{ TValidationToDamageAssignments }
|
||||
|
||||
TValidationToDamageAssignments = class(TEnumerableMultiIndexStrategy)
|
||||
private
|
||||
FValidation: TIntegerList;
|
||||
FValidationLengths: TValidationLengths;
|
||||
FDamages: TDamages;
|
||||
FValidationStartIndex, FValidationStopIndex: Integer;
|
||||
// Calculates "span", the length of all damages for this validation number combined.
|
||||
function CalcValidationSpan(constref ACurrentIndexArray: TIndexArray; const ALastDamageIndex, AValidationNumber:
|
||||
Integer): Integer;
|
||||
public
|
||||
constructor Create(constref AValidation: TIntegerList; constref AValidationLengths: TValidationLengths;
|
||||
constref ADamages: TDamages; const AStartIndex, AStopIndex: Integer);
|
||||
function GetCardinality: Integer; override;
|
||||
function TryGetStartIndexValue(constref ACurrentIndexArray: TIndexArray; const ACurrentIndex: Integer;
|
||||
out AStartIndexValue: Integer): Boolean; override;
|
||||
function ValidateIndexValue(constref ACurrentIndexArray: TIndexArray; const ACurrentIndex: Integer):
|
||||
TIndexValidationResult; override;
|
||||
end;
|
||||
|
||||
{ TValidationPositionInfo }
|
||||
|
||||
TValidationPositionInfo = record
|
||||
ValidationIndex: Integer;
|
||||
MinStart, MaxStart: Byte;
|
||||
end;
|
||||
|
||||
TValidationPositionInfos = specialize TList<TValidationPositionInfo>;
|
||||
|
||||
{ TValidationPositionOffsets }
|
||||
|
||||
TValidationPositionOffsets = class(TEnumerableMultiIndexStrategy)
|
||||
private
|
||||
FValidation: TIntegerList;
|
||||
FPositionInfos: TValidationPositionInfos;
|
||||
public
|
||||
constructor Create(constref AValidation: TIntegerList; constref APositionInfos: TValidationPositionInfos);
|
||||
function GetCardinality: Integer; override;
|
||||
function TryGetStartIndexValue(constref ACurrentIndexArray: TIndexArray; const ACurrentIndex: Integer;
|
||||
out AStartIndexValue: Integer): Boolean; override;
|
||||
function ValidateIndexValue(constref ACurrentIndexArray: TIndexArray; const ACurrentIndex: Integer):
|
||||
TIndexValidationResult; override;
|
||||
end;
|
||||
|
||||
{ TConditionRecord }
|
||||
|
||||
TConditionRecord = class
|
||||
private
|
||||
FValidation: TIntegerList;
|
||||
// List of non-empty, maximum-length parts of the pattern without operational springs.
|
||||
FBlockPatterns: TStringList;
|
||||
// Array 'a' of accumulated validation block lengths. 'a[i, j]' denotes the combined length of consecutive
|
||||
// List of non-empty, maximum-length parts of the pattern without operational springs ("blocks").
|
||||
FBlocks: TStringList;
|
||||
// Array 'a' of accumulated validation series lengths. 'a[i, j]' denotes the combined length of consecutive
|
||||
// validation numbers from 'FValidation[i]' to 'FValidation[j - 1]' with a single space in between each pair of
|
||||
// them.
|
||||
FValidationLengths: TValidationLengths;
|
||||
|
@ -78,34 +125,39 @@ type
|
|||
//FPatternLengths: TPatternLengths;
|
||||
|
||||
// Array 'a' of minimum indices 'a[i]', such that all remaining validation numbers starting at index 'a[i] - 1'
|
||||
// cannot fit into the remaining block patterns starting at 'FBlockPatterns[i]'.
|
||||
// cannot fit into the remaining blocks starting at 'FBlocks[i]'.
|
||||
FMinIndices: TIntegerArray;
|
||||
// List 'a' of lists of damages in a block pattern. Each list of damages 'a[i]' contains exactly one entry for each
|
||||
// block of consecutive damages characters in the i-th block pattern.
|
||||
// List 'a' of lists of damages in a block. Each list of damages 'a[i]' contains exactly one entry for each block of
|
||||
// consecutive damages characters in the i-th block.
|
||||
// For example, if the pattern is '?#.??##?#?..??', then 'FDamagesBlocks' would have 3 entries, which are lists of
|
||||
// 1, 2, and 0 damages, respectively.
|
||||
FDamagesBlocks: TDamagesBlocks;
|
||||
procedure InitValidationLengths;
|
||||
|
||||
//// Returns an array 'a' of accumulated pattern block lengths. 'a[i]' denotes the combined length of consecutive
|
||||
//// pattern blocks starting with 'FBlockPatterns[i]' and all following with a single space in between each pair of
|
||||
//// Returns an array 'a' of accumulated block lengths. 'a[i]' denotes the combined length of consecutive
|
||||
//// blocks starting with 'FBlocks[i]' and all following with a single space in between each pair of
|
||||
//// them.
|
||||
//// Should be "function CalcBlockLengths: TBlockLengths;
|
||||
//function CalcPatternLengths: TPatternLengths;
|
||||
|
||||
procedure InitMinIndices;
|
||||
function CalcCombinations(constref AIndices: TIntegerArray): Int64;
|
||||
function CalcCombinationsSingleBlock(const APattern: string; constref ADamages: TDamages; const AStartIndex,
|
||||
AStopIndex: Integer): Int64;
|
||||
function CalcCombinationsSingleBlockSingleValidation(const APattern: string; constref ADamages: TDamages;
|
||||
function CalcCombinationsBlock(const ABlock: string; constref ADamages: TDamages; const AStartIndex, AStopIndex:
|
||||
Integer): Int64;
|
||||
function CalcCombinationsBlockSingleValidation(const ABlockLength: Integer; constref ADamages: TDamages;
|
||||
const AIndex: Integer): Int64;
|
||||
function ParseDamages(const APattern: string): TDamages;
|
||||
function CalcCombinationsBlockMultiValidations(const ABlockLength: Integer; constref ADamages: TDamages;
|
||||
constref AIndices: TIndexArray; const AStartIndex, AStopIndex: Integer): Int64;
|
||||
function CalcCombinationsBlockAssignedValidations(const ABlockLength: Integer; constref APositionInfos:
|
||||
TValidationPositionInfos; constref AOffsets: TIndexArray; const AStartIndex, AStopIndex: Integer): Int64;
|
||||
function ParseDamages(const ABlock: string): TDamages;
|
||||
public
|
||||
property BlockPatterns: TStringList read FBlockPatterns;
|
||||
property Blocks: TStringList read FBlocks;
|
||||
property Validation: TIntegerList read FValidation;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
// Adds all non-empty, maximum-length parts of the pattern without operational springs.
|
||||
procedure AddBlockPatterns(const APattern: string);
|
||||
// Adds all non-empty, maximum-length parts of the pattern without operational springs ("blocks").
|
||||
procedure AddBlocks(const APattern: string);
|
||||
function GenerateBlockAssignments: Int64;
|
||||
end;
|
||||
|
||||
|
@ -146,6 +198,137 @@ implementation
|
|||
// Write(' |');
|
||||
//end;
|
||||
|
||||
{ TValidationToDamageAssignments }
|
||||
|
||||
function TValidationToDamageAssignments.CalcValidationSpan(constref ACurrentIndexArray: TIndexArray;
|
||||
const ALastDamageIndex, AValidationNumber: Integer): Integer;
|
||||
var
|
||||
spanStart: Integer;
|
||||
begin
|
||||
spanStart := ALastDamageIndex;
|
||||
while (spanStart > 0) and (ACurrentIndexArray[spanStart - 1] = AValidationNumber) do
|
||||
Dec(spanStart);
|
||||
Result := FDamages[ALastDamageIndex].Length;
|
||||
if spanStart < ALastDamageIndex then
|
||||
Inc(Result, FDamages[ALastDamageIndex].Start - FDamages[spanStart].Start);
|
||||
end;
|
||||
|
||||
constructor TValidationToDamageAssignments.Create(constref AValidation: TIntegerList; constref AValidationLengths:
|
||||
TValidationLengths; constref ADamages: TDamages; const AStartIndex, AStopIndex: Integer);
|
||||
begin
|
||||
FValidation := AValidation;
|
||||
FValidationLengths := AValidationLengths;
|
||||
FDamages := ADamages;
|
||||
FValidationStartIndex := AStartIndex;
|
||||
FValidationStopIndex := AStopIndex;
|
||||
end;
|
||||
|
||||
function TValidationToDamageAssignments.GetCardinality: Integer;
|
||||
begin
|
||||
Result := FDamages.Count;
|
||||
end;
|
||||
|
||||
function TValidationToDamageAssignments.TryGetStartIndexValue(constref ACurrentIndexArray: TIndexArray;
|
||||
const ACurrentIndex: Integer; out AStartIndexValue: Integer): Boolean;
|
||||
begin
|
||||
Result := True;
|
||||
if ACurrentIndex > 0 then
|
||||
AStartIndexValue := ACurrentIndexArray[ACurrentIndex - 1]
|
||||
else
|
||||
AStartIndexValue := FValidationStartIndex;
|
||||
end;
|
||||
|
||||
function TValidationToDamageAssignments.ValidateIndexValue(constref ACurrentIndexArray: TIndexArray;
|
||||
const ACurrentIndex: Integer): TIndexValidationResult;
|
||||
var
|
||||
i, prev, firstSkip: Integer;
|
||||
begin
|
||||
i := ACurrentIndexArray[ACurrentIndex];
|
||||
if i > FValidationStopIndex then
|
||||
begin
|
||||
Result := ivrBacktrack;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// Checks if there is enough space after this damage for remaining validation numbers.
|
||||
if FValidationLengths[i + 1, FValidationStopIndex + 1] + 1 > FDamages[ACurrentIndex].CharsRemaining then
|
||||
begin
|
||||
Result := ivrSkip;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// Checks if there is enough space before this damage for previous validation numbers.
|
||||
if (FValidationStartIndex < i) and (FValidationLengths[FValidationStartIndex, i] + 1 >= FDamages[ACurrentIndex].Start) then
|
||||
begin
|
||||
Result := ivrBacktrack;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// Checks if there is enough space between previous and this damage for skipped validation numbers.
|
||||
if ACurrentIndex > 0 then
|
||||
begin
|
||||
prev := ACurrentIndex - 1;
|
||||
firstSkip := ACurrentIndexArray[prev] + 1;
|
||||
if (firstSkip < i) and (FValidationLengths[firstSkip, i] + 2 > FDamages[ACurrentIndex].Start - FDamages[prev].Start - FDamages[prev].Length) then
|
||||
begin
|
||||
Result := ivrBacktrack;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
// Checks if span is small enough to fit within this validation number.
|
||||
if FValidation[i] < CalcValidationSpan(ACurrentIndexArray, ACurrentIndex, i) then
|
||||
begin
|
||||
Result := ivrSkip;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
Result := ivrValid;
|
||||
end;
|
||||
|
||||
{ TValidationPositionOffsets }
|
||||
|
||||
constructor TValidationPositionOffsets.Create(constref AValidation: TIntegerList; constref APositionInfos:
|
||||
TValidationPositionInfos);
|
||||
begin
|
||||
FValidation := AValidation;
|
||||
FPositionInfos := APositionInfos;
|
||||
end;
|
||||
|
||||
function TValidationPositionOffsets.GetCardinality: Integer;
|
||||
begin
|
||||
Result := FPositionInfos.Count;
|
||||
end;
|
||||
|
||||
function TValidationPositionOffsets.TryGetStartIndexValue(constref ACurrentIndexArray: TIndexArray;
|
||||
const ACurrentIndex: Integer; out AStartIndexValue: Integer): Boolean;
|
||||
var
|
||||
info: TValidationPositionInfo;
|
||||
begin
|
||||
info := FPositionInfos[ACurrentIndex];
|
||||
// Calculates start value such that the validation number just includes MinEnd.
|
||||
//AStartIndexValue := info.MinEnd - FValidation[info.ValidationIndex] + 1;
|
||||
AStartIndexValue := info.MinStart;
|
||||
////////////////////////////////////////////
|
||||
Assert(AStartIndexValue > 0, 'start value ');
|
||||
////////////////////////////////////////////
|
||||
// Adjusts start value to avoid overlap of this validation number with the previous one (the one from previous
|
||||
// position info).
|
||||
if ACurrentIndex > 0 then
|
||||
AStartIndexValue := Max(AStartIndexValue,
|
||||
ACurrentIndexArray[ACurrentIndex - 1] + FValidation[FPositionInfos[ACurrentIndex - 1].ValidationIndex] + 1);
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TValidationPositionOffsets.ValidateIndexValue(constref ACurrentIndexArray: TIndexArray; const ACurrentIndex:
|
||||
Integer): TIndexValidationResult;
|
||||
begin
|
||||
if ACurrentIndexArray[ACurrentIndex] <= FPositionInfos[ACurrentIndex].MaxStart then
|
||||
Result := ivrValid
|
||||
else
|
||||
Result := ivrBacktrack;
|
||||
end;
|
||||
|
||||
{ TConditionRecord }
|
||||
|
||||
procedure TConditionRecord.InitValidationLengths;
|
||||
|
@ -179,15 +362,15 @@ procedure TConditionRecord.InitMinIndices;
|
|||
var
|
||||
i, j, patternsLength: Integer;
|
||||
begin
|
||||
SetLength(FMinIndices, FBlockPatterns.Count - 1);
|
||||
patternsLength := Length(FBlockPatterns[FBlockPatterns.Count - 1]);
|
||||
SetLength(FMinIndices, FBlocks.Count - 1);
|
||||
patternsLength := Length(FBlocks[FBlocks.Count - 1]);
|
||||
j := FValidation.Count;
|
||||
for i := FBlockPatterns.Count - 2 downto 0 do
|
||||
for i := FBlocks.Count - 2 downto 0 do
|
||||
begin
|
||||
while (j >= 0) and (FValidationLengths[j, FValidation.Count] <= patternsLength) do
|
||||
Dec(j);
|
||||
FMinIndices[i] := j + 1;
|
||||
patternsLength := patternsLength + 1 + Length(FBlockPatterns[i]);
|
||||
patternsLength := patternsLength + 1 + Length(FBlocks[i]);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -201,20 +384,21 @@ begin
|
|||
|
||||
Result := 1;
|
||||
i := 0;
|
||||
while (Result > 0) and (i < FBlockPatterns.Count) do
|
||||
while (Result > 0) and (i < FBlocks.Count) do
|
||||
begin
|
||||
Result := Result * CalcCombinationsSingleBlock(FBlockPatterns[i], FDamagesBlocks[i], AIndices[i], AIndices[i + 1] - 1);
|
||||
Result := Result * CalcCombinationsBlock(FBlocks[i], FDamagesBlocks[i], AIndices[i], AIndices[i + 1] - 1);
|
||||
Inc(i);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TConditionRecord.CalcCombinationsSingleBlock(const APattern: string; constref ADamages: TDamages;
|
||||
const AStartIndex, AStopIndex: Integer): Int64;
|
||||
function TConditionRecord.CalcCombinationsBlock(const ABlock: string; constref ADamages: TDamages; const AStartIndex,
|
||||
AStopIndex: Integer): Int64;
|
||||
var
|
||||
i, j, k: Integer;
|
||||
indices: TIntegerArray;
|
||||
indices: TIndexArray;
|
||||
validationToDamageAssignments: TValidationToDamageAssignments;
|
||||
begin
|
||||
Write(' ', APattern, ' ');
|
||||
Write(' ', ABlock, ' ');
|
||||
for i := AStartIndex to AStopIndex do
|
||||
Write(FValidation[i], ' ');
|
||||
WriteLn;
|
||||
|
@ -229,11 +413,10 @@ begin
|
|||
end
|
||||
// One validation number assigned to this block.
|
||||
else if AStartIndex = AStopIndex then
|
||||
Result := CalcCombinationsSingleBlockSingleValidation(APattern, ADamages, AStartIndex)
|
||||
Result := CalcCombinationsBlockSingleValidation(Length(ABlock), ADamages, AStartIndex)
|
||||
// Multiple validation numbers assigned to this block.
|
||||
else begin
|
||||
SetLength(indices, ADamages.Count);
|
||||
|
||||
///////////////////////////////
|
||||
Write(' min before: ');
|
||||
for i := AStartIndex to AStopIndex do
|
||||
Write(FValidationLengths[AStartIndex, i + 1] - FValidation[i], ' ');
|
||||
|
@ -243,7 +426,6 @@ begin
|
|||
Write(FValidationLengths[i, AStopIndex + 1] - FValidation[i], ' ');
|
||||
WriteLn;
|
||||
|
||||
///////////////////////////////
|
||||
for i := 0 to ADamages.Count - 1 do
|
||||
begin
|
||||
WriteLn(' damage: start ',ADamages[i].Start, ', length ', ADamages[i].Length, ', remain ', ADamages[i].CharsRemaining);
|
||||
|
@ -263,51 +445,34 @@ begin
|
|||
Result := 9999;
|
||||
|
||||
// Assigns validation numbers to specific damages.
|
||||
j := AStartIndex;
|
||||
for i := 0 to ADamages.Count - 1 do
|
||||
validationToDamageAssignments := TValidationToDamageAssignments.Create(FValidation, FValidationLengths, ADamages,
|
||||
AStartIndex, AStopIndex);
|
||||
WriteLn(' validation numbers (indices) per damages:');
|
||||
for indices in validationToDamageAssignments do
|
||||
begin
|
||||
while (j <= AStopIndex)
|
||||
// Enough space before damage for the other validation numbers?
|
||||
and ((FValidationLengths[AStartIndex, j + 1] - FValidation[j] >= ADamages[i].Start)
|
||||
// Enough space after damage for the other validation numbers?
|
||||
// TODO: Is this true? Once the following check is true for given j, increasing j will not make it false, so set Result := 0 and break.
|
||||
or (FValidationLengths[j, AStopIndex + 1] - FValidation[j] > ADamages[i].CharsRemaining)
|
||||
// Damage itself small enough for this validation number?
|
||||
or (FValidation[j] < ADamages[i].Length)) do
|
||||
Inc(j);
|
||||
|
||||
if (j > AStopIndex) then
|
||||
begin
|
||||
Result := 0;
|
||||
Break;
|
||||
end;
|
||||
|
||||
indices[i] := j;
|
||||
Write(' ');
|
||||
for i := 0 to ADamages.Count - 1 do
|
||||
Write(FValidation[indices[i]], ' ');
|
||||
Write('( ');
|
||||
for i := 0 to ADamages.Count - 1 do
|
||||
Write(indices[i] - AStartIndex, ' ');
|
||||
WriteLn(')');
|
||||
CalcCombinationsBlockMultiValidations(Length(ABlock), ADamages, indices, AStartIndex, AStopIndex);
|
||||
end;
|
||||
|
||||
WriteLn(' validation number indices per damages:');
|
||||
Write(' ');
|
||||
for i := 0 to ADamages.Count - 1 do
|
||||
Write(indices[i], ' ');
|
||||
Write('( ');
|
||||
for i := 0 to ADamages.Count - 1 do
|
||||
Write(indices[i] - AStartIndex, ' ');
|
||||
WriteLn(')');
|
||||
|
||||
// TODO: Iterate over all possible assignments of validation numbers to specific damages.
|
||||
validationToDamageAssignments.Free;
|
||||
end;
|
||||
WriteLn(' Result: ', Result);
|
||||
end;
|
||||
|
||||
function TConditionRecord.CalcCombinationsSingleBlockSingleValidation(const APattern: string; constref ADamages:
|
||||
function TConditionRecord.CalcCombinationsBlockSingleValidation(const ABlockLength: Integer; constref ADamages:
|
||||
TDamages; const AIndex: Integer): Int64;
|
||||
var
|
||||
combinedDamagesLength: Integer;
|
||||
begin
|
||||
if Length(APattern) < FValidation[AIndex] then
|
||||
if ABlockLength < FValidation[AIndex] then
|
||||
Result := 0
|
||||
else if ADamages.Count = 0 then
|
||||
Result := Length(APattern) - FValidation[AIndex] + 1
|
||||
Result := ABlockLength - FValidation[AIndex] + 1
|
||||
else begin
|
||||
combinedDamagesLength := ADamages.Last.Start + ADamages.Last.Length - ADamages.First.Start;
|
||||
if FValidation[AIndex] < combinedDamagesLength then
|
||||
|
@ -316,23 +481,113 @@ begin
|
|||
Result := Min(Min(Min(
|
||||
ADamages.First.Start,
|
||||
FValidation[AIndex] - combinedDamagesLength + 1),
|
||||
Length(APattern) - FValidation[AIndex] + 1),
|
||||
ABlockLength - FValidation[AIndex] + 1),
|
||||
ADamages.Last.CharsRemaining + 1);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TConditionRecord.ParseDamages(const APattern: string): TDamages;
|
||||
function TConditionRecord.CalcCombinationsBlockMultiValidations(const ABlockLength: Integer; constref ADamages:
|
||||
TDamages; constref AIndices: TIndexArray; const AStartIndex, AStopIndex: Integer): Int64;
|
||||
var
|
||||
i, high: Integer;
|
||||
position: TValidationPositionInfo;
|
||||
positions: TValidationPositionInfos;
|
||||
validationPositionOffsets: TValidationPositionOffsets;
|
||||
offsets: TIndexArray;
|
||||
begin
|
||||
positions := TValidationPositionInfos.Create;
|
||||
high := Length(AIndices) - 1;
|
||||
// Initializes first info record.
|
||||
position.ValidationIndex := AIndices[0];
|
||||
position.MaxStart := ADamages[0].Start;
|
||||
position.MinStart := 1;
|
||||
for i := 1 to high do
|
||||
if AIndices[i] <> position.ValidationIndex then
|
||||
begin
|
||||
// Finalizes current info record.
|
||||
position.MaxStart := Min(position.MaxStart, ADamages[i].Start - 1 - FValidation[position.ValidationIndex]);
|
||||
position.MinStart := Max(position.MinStart,
|
||||
ADamages[i - 1].Start + ADamages[i - 1].Length - 1 - FValidation[position.ValidationIndex] + 1);
|
||||
positions.Add(position);
|
||||
// Initializes next info record.
|
||||
position.ValidationIndex := AIndices[i];
|
||||
position.MaxStart := ADamages[i].Start;
|
||||
position.MinStart := position.MinStart + FValidation[position.ValidationIndex] + 1;
|
||||
end;
|
||||
// Finalizes last info record.
|
||||
position.MaxStart := Min(position.MaxStart, ABlockLength + 1 - FValidation[position.ValidationIndex]);
|
||||
position.MinStart := Max(position.MinStart,
|
||||
ADamages[high].Start + ADamages[high].Length - FValidation[position.ValidationIndex]);
|
||||
positions.Add(position);
|
||||
|
||||
WriteLn(' validation position infos');
|
||||
for position in positions do
|
||||
WriteLn(' ', position.ValidationIndex, ' ', position.MinStart, ' ', position.MaxStart);
|
||||
|
||||
WriteLn(' offsets');
|
||||
validationPositionOffsets := TValidationPositionOffsets.Create(FValidation, positions);
|
||||
for offsets in validationPositionOffsets do
|
||||
CalcCombinationsBlockAssignedValidations(ABlockLength, positions, offsets, AStartIndex, AStopIndex);
|
||||
validationPositionOffsets.Free;
|
||||
|
||||
positions.Free;
|
||||
end;
|
||||
|
||||
function TConditionRecord.CalcCombinationsBlockAssignedValidations(const ABlockLength: Integer; constref APositionInfos:
|
||||
TValidationPositionInfos; constref AOffsets: TIndexArray; const AStartIndex, AStopIndex: Integer): Int64;
|
||||
var
|
||||
i, space, freedom, count: Integer;
|
||||
begin
|
||||
Write(' ');
|
||||
for i in AOffsets do
|
||||
Write(i, ' ');
|
||||
|
||||
Write(' count/space/freedom: ');
|
||||
// TODO: Number of combinations is binom(count + freedom, freedom).
|
||||
if AStartIndex < APositionInfos[0].ValidationIndex then
|
||||
begin
|
||||
count := APositionInfos[0].ValidationIndex - AStartIndex;
|
||||
space := AOffsets[0] - 2;
|
||||
freedom := space - FValidationLengths[AStartIndex, APositionInfos[0].ValidationIndex];
|
||||
Write(count, '/', space, '/', freedom, ' ');
|
||||
end
|
||||
else
|
||||
Write('X ');
|
||||
for i := 0 to APositionInfos.Count - 2 do
|
||||
if APositionInfos[i].ValidationIndex + 1 < APositionInfos[i + 1].ValidationIndex then
|
||||
begin
|
||||
count := APositionInfos[i + 1].ValidationIndex - APositionInfos[i].ValidationIndex - 1;
|
||||
space := AOffsets[i + 1] - AOffsets[i] - FValidation[APositionInfos[i].ValidationIndex] - 2;
|
||||
freedom := space - FValidationLengths[APositionInfos[i].ValidationIndex + 1, APositionInfos[i + 1].ValidationIndex];
|
||||
Write(count, '/', space, '/', freedom, ' ');
|
||||
end
|
||||
else
|
||||
Write('X ');
|
||||
if APositionInfos.Last.ValidationIndex < AStopIndex then
|
||||
begin
|
||||
count := AStopIndex - APositionInfos.Last.ValidationIndex;
|
||||
space := ABlockLength - AOffsets[APositionInfos.Count - 1] - FValidation[APositionInfos.Last.ValidationIndex];
|
||||
freedom := space - FValidationLengths[APositionInfos.Last.ValidationIndex + 1, AStopIndex + 1];
|
||||
Write(count, '/', space, '/', freedom, ' ');
|
||||
end
|
||||
else
|
||||
Write('X ');
|
||||
|
||||
WriteLn;
|
||||
end;
|
||||
|
||||
function TConditionRecord.ParseDamages(const ABlock: string): TDamages;
|
||||
var
|
||||
i, len: Integer;
|
||||
damage: TDamage;
|
||||
begin
|
||||
Result := TDamages.Create;
|
||||
damage.Length := 0;
|
||||
len := Length(APattern);
|
||||
len := Length(ABlock);
|
||||
for i := 1 to len do
|
||||
// The pattern must only contain damage and wildcard characters here.
|
||||
if APattern[i] = CDamagedChar then
|
||||
if ABlock[i] = CDamagedChar then
|
||||
begin
|
||||
if damage.Length = 0 then
|
||||
damage.Start := i;
|
||||
|
@ -354,20 +609,20 @@ end;
|
|||
|
||||
constructor TConditionRecord.Create;
|
||||
begin
|
||||
FBlockPatterns := TStringList.Create;
|
||||
FBlocks := TStringList.Create;
|
||||
FValidation := TIntegerList.Create;
|
||||
FDamagesBlocks := TDamagesBlocks.Create;
|
||||
end;
|
||||
|
||||
destructor TConditionRecord.Destroy;
|
||||
begin
|
||||
FBlockPatterns.Free;
|
||||
FBlocks.Free;
|
||||
FValidation.Free;
|
||||
FDamagesBlocks.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TConditionRecord.AddBlockPatterns(const APattern: string);
|
||||
procedure TConditionRecord.AddBlocks(const APattern: string);
|
||||
var
|
||||
split: TStringArray;
|
||||
part: string;
|
||||
|
@ -376,7 +631,7 @@ begin
|
|||
for part in split do
|
||||
if Length(part) > 0 then
|
||||
begin
|
||||
FBlockPatterns.Add(part);
|
||||
FBlocks.Add(part);
|
||||
FDamagesBlocks.Add(ParseDamages(part));
|
||||
end;
|
||||
end;
|
||||
|
@ -399,11 +654,12 @@ begin
|
|||
//FPatternLengths := CalcPatternLengths;
|
||||
InitMinIndices;
|
||||
|
||||
SetLength(indices, FBlockPatterns.Count + 1);
|
||||
SetLength(indices, FBlocks.Count + 1);
|
||||
high := Length(indices) - 2;
|
||||
indices[0] := 0;
|
||||
indices[high + 1] := FValidation.Count;
|
||||
|
||||
// TODO: Use TMultiIndexEnumerator for this.
|
||||
Result := 0;
|
||||
k := 0;
|
||||
repeat
|
||||
|
@ -419,7 +675,7 @@ begin
|
|||
//WriteLn(j, ' ', FMinIndices[i - 1]);
|
||||
|
||||
indices[i] := Max(indices[i - 1], FMinIndices[i - 1]);
|
||||
while FValidationLengths[indices[i - 1], indices[i]] > Length(FBlockPatterns[i - 1]) do
|
||||
while FValidationLengths[indices[i - 1], indices[i]] > Length(FBlocks[i - 1]) do
|
||||
begin
|
||||
Dec(i);
|
||||
Inc(indices[i]);
|
||||
|
@ -428,7 +684,7 @@ begin
|
|||
Inc(i);
|
||||
end;
|
||||
|
||||
//if FValidationLengths[indices[0], indices[1]] > Length(FBlockPatterns[0]) then
|
||||
//if FValidationLengths[indices[0], indices[1]] > Length(FBlocks[0]) then
|
||||
// Break;
|
||||
|
||||
Result := Result + CalcCombinations(indices);
|
||||
|
@ -436,7 +692,7 @@ begin
|
|||
k := high;
|
||||
while (k > 0)
|
||||
and ((indices[k] = FValidation.Count)
|
||||
or (FValidationLengths[indices[k - 1], indices[k] + 1] > Length(FBlockPatterns[k - 1]))) do
|
||||
or (FValidationLengths[indices[k - 1], indices[k] + 1] > Length(FBlocks[k - 1]))) do
|
||||
Dec(k);
|
||||
Inc(indices[k]);
|
||||
until k = 0;
|
||||
|
@ -460,13 +716,13 @@ begin
|
|||
mainSplit := ALine.Split([' ']);
|
||||
|
||||
// Adds blocks for part 1.
|
||||
conditionRecord1.AddBlockPatterns(mainSplit[0]);
|
||||
conditionRecord1.AddBlocks(mainSplit[0]);
|
||||
|
||||
// Adds blocks for part 2.
|
||||
unfolded := mainSplit[0];
|
||||
for i := 2 to CPart2Repetition do
|
||||
unfolded := unfolded + CWildcardChar + mainSplit[0];
|
||||
conditionRecord2.AddBlockPatterns(unfolded);
|
||||
conditionRecord2.AddBlocks(unfolded);
|
||||
|
||||
// Adds validation numbers.
|
||||
split := mainSplit[1].Split([',']);
|
||||
|
@ -475,14 +731,14 @@ begin
|
|||
for i := 1 to CPart2Repetition do
|
||||
conditionRecord2.Validation.AddRange(conditionRecord1.Validation);
|
||||
|
||||
//for part in conditionRecord1.BlockPatterns do
|
||||
//for part in conditionRecord1.Blocks do
|
||||
// WriteLn(part);
|
||||
//for i in conditionRecord1.Validation do
|
||||
// WriteLn(i);
|
||||
//
|
||||
//WriteLn;
|
||||
//
|
||||
// for part in conditionRecord2.BlockPatterns do
|
||||
// for part in conditionRecord2.Blocks do
|
||||
// WriteLn(part);
|
||||
// for i in conditionRecord2.Validation do
|
||||
// WriteLn(i);
|
||||
|
@ -498,7 +754,7 @@ end;
|
|||
|
||||
procedure THotSprings.Finish;
|
||||
begin
|
||||
|
||||
ProcessDataLine('?????#??##??????#??????? 5,3,1,2,1');
|
||||
end;
|
||||
|
||||
function THotSprings.GetDataFileName: string;
|
||||
|
|
Loading…
Reference in New Issue