Added solution for "Day 7: Camel Cards", part 2
This commit is contained in:
		
							parent
							
								
									3f74b7c664
								
							
						
					
					
						commit
						6b5048b7ef
					
				@ -39,12 +39,13 @@ type
 | 
			
		||||
  TCardHand = class
 | 
			
		||||
  private
 | 
			
		||||
    FHand: string;
 | 
			
		||||
    FType: TCardHandType;
 | 
			
		||||
    FType, FJokerType: TCardHandType;
 | 
			
		||||
    FBid: Cardinal;
 | 
			
		||||
    function GetCardValue(const ACard: Char): Cardinal;
 | 
			
		||||
    procedure CalcCountersFromHand(constref counters: TCardCounters);
 | 
			
		||||
    function CalcTypeFromCounters(constref counters: TCardCounters): TCardHandType;
 | 
			
		||||
    function CalcJokerTypeFromCounters(constref counters: TCardCounters): TCardHandType;
 | 
			
		||||
  public
 | 
			
		||||
    constructor Create(const ALine: string);
 | 
			
		||||
    function CompareTo(constref AOther: TCardHand): Integer;
 | 
			
		||||
    property Bid: Cardinal read FBid;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
@ -53,8 +54,20 @@ type
 | 
			
		||||
  { TCardHandComparer }
 | 
			
		||||
 | 
			
		||||
  TCardHandComparer = class(TInterfacedObject, specialize IComparer<TCardHand>)
 | 
			
		||||
  protected
 | 
			
		||||
    function CompareCardValue(constref AHand1, AHand2: TCardHand): Integer;
 | 
			
		||||
    function GetCardValue(const ACard: Char): Cardinal; virtual;
 | 
			
		||||
  public
 | 
			
		||||
    function Compare(constref AHand1, AHand2: TCardHand): Integer;
 | 
			
		||||
    function Compare(constref AHand1, AHand2: TCardHand): Integer; virtual;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  { TJokerCardHandComparer }
 | 
			
		||||
 | 
			
		||||
  TJokerCardHandComparer = class(TCardHandComparer)
 | 
			
		||||
  protected
 | 
			
		||||
    function GetCardValue(const ACard: Char): Cardinal; override;
 | 
			
		||||
  public
 | 
			
		||||
    function Compare(constref AHand1, AHand2: TCardHand): Integer; override;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  { TCamelCards }
 | 
			
		||||
@ -75,33 +88,14 @@ implementation
 | 
			
		||||
 | 
			
		||||
{ TCardHand }
 | 
			
		||||
 | 
			
		||||
function TCardHand.GetCardValue(const ACard: Char): Cardinal;
 | 
			
		||||
begin
 | 
			
		||||
  if not TryStrToDWord(ACard, Result) then
 | 
			
		||||
    case ACard of
 | 
			
		||||
      'A': Result := 14;
 | 
			
		||||
      'K': Result := 13;
 | 
			
		||||
      'Q': Result := 12;
 | 
			
		||||
      'J': Result := 11;
 | 
			
		||||
      'T': Result := 10;
 | 
			
		||||
      else Result := 0;
 | 
			
		||||
    end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
constructor TCardHand.Create(const ALine: string);
 | 
			
		||||
procedure TCardHand.CalcCountersFromHand(constref counters: TCardCounters);
 | 
			
		||||
var
 | 
			
		||||
  split: TStringArray;
 | 
			
		||||
  counters: TCardCounters;
 | 
			
		||||
  counter: TCardCounter;
 | 
			
		||||
  i: Integer;
 | 
			
		||||
  c: Char;
 | 
			
		||||
  found: Boolean;
 | 
			
		||||
begin
 | 
			
		||||
  split := ALine.Split(' ');
 | 
			
		||||
  FHand := split[0];
 | 
			
		||||
  FBid := StrToDWord(split[1]);
 | 
			
		||||
 | 
			
		||||
  counters := TCardCounters.Create;
 | 
			
		||||
  counters.Clear;
 | 
			
		||||
 | 
			
		||||
  // Creates a counter for each different card value and counts cards per card value.
 | 
			
		||||
  for c in FHand do
 | 
			
		||||
@ -127,45 +121,131 @@ begin
 | 
			
		||||
      counters.Add(counter);
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  // Determines the hand type from the counters.
 | 
			
		||||
  case counters.Count of
 | 
			
		||||
    1: FType := htFiveOfAKind;
 | 
			
		||||
    2:
 | 
			
		||||
      if (counters[0].Count = 4) or (counters[1].Count = 4) then
 | 
			
		||||
        FType := htFourOfAKind
 | 
			
		||||
      else
 | 
			
		||||
        FType := htFullHouse;
 | 
			
		||||
    3:
 | 
			
		||||
      if (counters[0].Count = 3) or (counters[1].Count = 3) or (counters[2].Count = 3) then
 | 
			
		||||
        FType := htThreeOfAKind
 | 
			
		||||
      else
 | 
			
		||||
        FType := htTwoPair;
 | 
			
		||||
    4: FType := htOnePair;
 | 
			
		||||
    5: FType := htHighCard;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  counters.Free;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TCardHand.CompareTo(constref AOther: TCardHand): Integer;
 | 
			
		||||
var
 | 
			
		||||
  i: Integer;
 | 
			
		||||
function TCardHand.CalcTypeFromCounters(constref counters: TCardCounters): TCardHandType;
 | 
			
		||||
begin
 | 
			
		||||
  Result := Ord(FType) - Ord(AOther.FType);
 | 
			
		||||
  i := 1;
 | 
			
		||||
  while (Result = 0) and (i <= FHand.Length) do
 | 
			
		||||
  begin
 | 
			
		||||
    Result := GetCardValue(FHand[i]) - GetCardValue(AOther.FHand[i]);
 | 
			
		||||
    Inc(i);
 | 
			
		||||
  // Determines the hand type from the counters.
 | 
			
		||||
  case counters.Count of
 | 
			
		||||
    1: Result := htFiveOfAKind;
 | 
			
		||||
    2:
 | 
			
		||||
      if (counters[0].Count = 4) or (counters[1].Count = 4) then
 | 
			
		||||
        Result := htFourOfAKind
 | 
			
		||||
      else
 | 
			
		||||
        Result := htFullHouse;
 | 
			
		||||
    3:
 | 
			
		||||
      if (counters[0].Count = 3) or (counters[1].Count = 3) or (counters[2].Count = 3) then
 | 
			
		||||
        Result := htThreeOfAKind
 | 
			
		||||
      else
 | 
			
		||||
        Result := htTwoPair;
 | 
			
		||||
    4: Result := htOnePair;
 | 
			
		||||
    5: Result := htHighCard;
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TCardHand.CalcJokerTypeFromCounters(constref counters: TCardCounters): TCardHandType;
 | 
			
		||||
var
 | 
			
		||||
  i, maxCount, maxCountIndex, jokerIndex: Integer;
 | 
			
		||||
  jokerCounter, counter: TCardCounter;
 | 
			
		||||
begin
 | 
			
		||||
  if counters.Count > 1 then
 | 
			
		||||
  begin
 | 
			
		||||
    // Finds Jokers and the best card value.
 | 
			
		||||
    maxCount := 0;
 | 
			
		||||
    jokerIndex := -1;
 | 
			
		||||
    for i := 0 to counters.Count - 1 do
 | 
			
		||||
    begin
 | 
			
		||||
      if counters[i].Card = 'J' then
 | 
			
		||||
      begin
 | 
			
		||||
        jokerIndex := i;
 | 
			
		||||
        jokerCounter := counters[i];
 | 
			
		||||
      end
 | 
			
		||||
      else if maxCount < counters[i].Count then
 | 
			
		||||
      begin
 | 
			
		||||
        maxCount := counters[i].Count;
 | 
			
		||||
        maxCountIndex := i;
 | 
			
		||||
      end;
 | 
			
		||||
    end;
 | 
			
		||||
 | 
			
		||||
    // Uses Jokers for the best card value.
 | 
			
		||||
    if jokerIndex >= 0 then
 | 
			
		||||
    begin
 | 
			
		||||
      counter := counters[maxCountIndex];
 | 
			
		||||
      Inc(counter.Count, jokerCounter.Count);
 | 
			
		||||
      counters[maxCountIndex] := counter;
 | 
			
		||||
      counters.Delete(jokerIndex);
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  Result := CalcTypeFromCounters(counters);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
constructor TCardHand.Create(const ALine: string);
 | 
			
		||||
var
 | 
			
		||||
  split: TStringArray;
 | 
			
		||||
  counters: TCardCounters;
 | 
			
		||||
begin
 | 
			
		||||
  split := ALine.Split(' ');
 | 
			
		||||
  FHand := split[0];
 | 
			
		||||
  FBid := StrToDWord(split[1]);
 | 
			
		||||
 | 
			
		||||
  counters := TCardCounters.Create;
 | 
			
		||||
  CalcCountersFromHand(counters);
 | 
			
		||||
  FType := CalcTypeFromCounters(counters);
 | 
			
		||||
  FJokerType := CalcJokerTypeFromCounters(counters);
 | 
			
		||||
  counters.Free;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
{ TCardHandComparer }
 | 
			
		||||
 | 
			
		||||
function TCardHandComparer.CompareCardValue(constref AHand1, AHand2: TCardHand): Integer;
 | 
			
		||||
var
 | 
			
		||||
  i: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  Result := 0;
 | 
			
		||||
  i := 1;
 | 
			
		||||
  while (Result = 0) and (i <= AHand1.FHand.Length) do
 | 
			
		||||
  begin
 | 
			
		||||
    Result := GetCardValue(AHand1.FHand[i]) - GetCardValue(AHand2.FHand[i]);
 | 
			
		||||
    Inc(i);
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TCardHandComparer.GetCardValue(const ACard: Char): Cardinal;
 | 
			
		||||
begin
 | 
			
		||||
  if not TryStrToDWord(ACard, Result) then
 | 
			
		||||
    case ACard of
 | 
			
		||||
      'A': Result := 14;
 | 
			
		||||
      'K': Result := 13;
 | 
			
		||||
      'Q': Result := 12;
 | 
			
		||||
      'J': Result := 11;
 | 
			
		||||
      'T': Result := 10;
 | 
			
		||||
      else Result := 0;
 | 
			
		||||
    end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TCardHandComparer.Compare(constref AHand1, AHand2: TCardHand): Integer;
 | 
			
		||||
begin
 | 
			
		||||
  Result := AHand1.CompareTo(AHand2);
 | 
			
		||||
  Result := Ord(AHand1.FType) - Ord(AHand2.FType);
 | 
			
		||||
  if Result = 0 then
 | 
			
		||||
    Result := CompareCardValue(AHand1, AHand2);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
{ TJokerCardHandComparer }
 | 
			
		||||
 | 
			
		||||
function TJokerCardHandComparer.GetCardValue(const ACard: Char): Cardinal;
 | 
			
		||||
begin
 | 
			
		||||
  if ACard = 'J' then
 | 
			
		||||
    Result := 1
 | 
			
		||||
  else
 | 
			
		||||
    Result := inherited GetCardValue(ACard);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TJokerCardHandComparer.Compare(constref AHand1, AHand2: TCardHand): Integer;
 | 
			
		||||
begin
 | 
			
		||||
  Result := Ord(AHand1.FJokerType) - Ord(AHand2.FJokerType);
 | 
			
		||||
  if Result = 0 then
 | 
			
		||||
    Result := CompareCardValue(AHand1, AHand2);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
{ TCamelCards }
 | 
			
		||||
@ -189,6 +269,7 @@ end;
 | 
			
		||||
procedure TCamelCards.Finish;
 | 
			
		||||
var
 | 
			
		||||
  comparer: TCardHandComparer;
 | 
			
		||||
  jokerComparer: TJokerCardHandComparer;
 | 
			
		||||
  i: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  comparer := TCardHandComparer.Create;
 | 
			
		||||
@ -197,6 +278,13 @@ begin
 | 
			
		||||
 | 
			
		||||
  for i := 0 to FHands.Count - 1 do
 | 
			
		||||
    Inc(FPart1, FHands[i].Bid * (i + 1));
 | 
			
		||||
 | 
			
		||||
  jokerComparer := TJokerCardHandComparer.Create;
 | 
			
		||||
  FHands.Sort(jokerComparer);
 | 
			
		||||
  jokerComparer.Free;
 | 
			
		||||
 | 
			
		||||
  for i := 0 to FHands.Count - 1 do
 | 
			
		||||
    Inc(FPart2, FHands[i].Bid * (i + 1));
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TCamelCards.GetDataFileName: string;
 | 
			
		||||
 | 
			
		||||
@ -62,7 +62,7 @@ end;
 | 
			
		||||
 | 
			
		||||
procedure TCamelCardsFullDataTestCase.TestPart2;
 | 
			
		||||
begin
 | 
			
		||||
  AssertEquals(-1, FSolver.GetResultPart2);
 | 
			
		||||
  AssertEquals(254115617, FSolver.GetResultPart2);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
{ TCamelCardsExampleTestCase }
 | 
			
		||||
@ -79,7 +79,7 @@ end;
 | 
			
		||||
 | 
			
		||||
procedure TCamelCardsExampleTestCase.TestPart2;
 | 
			
		||||
begin
 | 
			
		||||
  AssertEquals(-1, FSolver.GetResultPart2);
 | 
			
		||||
  AssertEquals(5905, FSolver.GetResultPart2);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
initialization
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user