Skip to content

Commit

Permalink
Merge pull request #4 from tiberiushunter/day7-2023
Browse files Browse the repository at this point in the history
Day 7 2023
  • Loading branch information
tiberiushunter authored Dec 10, 2023
2 parents 09fc56f + e897a4b commit 5c1b5c7
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 2 deletions.
20 changes: 20 additions & 0 deletions AdventOfCode.Solutions/Enums/PlayingCard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace AdventOfCode.Solutions.Models;

public enum PlayingCard
{
Joker = 0,
AceLow = 1,
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
Eight = 8,
Nine = 9,
Ten = 10,
Jack = 11,
Queen = 12,
King = 13,
AceHigh = 14,
}
2 changes: 1 addition & 1 deletion AdventOfCode.Solutions/_2023/Day3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private int FindPartNumber(string input, int index)
return -1;
}

private List<(int x, int y)> boundaryCoords =
private readonly List<(int x, int y)> boundaryCoords =
[
(-1, 1),
(0, 1),
Expand Down
251 changes: 251 additions & 0 deletions AdventOfCode.Solutions/_2023/Day7.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
using AdventOfCode.Domain.Interfaces;
using AdventOfCode.Solutions.Helpers;
using AdventOfCode.Solutions.Models;

namespace AdventOfCode.Solutions._2023;

public class Day7 : IDay
{
public string Title => "Camel Cards";

public string PartA(string input)
{
var sets = InputHelper.ToStringArray(input);

List<Hand> hands = sets
.Select(set => set.Split(' '))
.Select(set => new Hand(
int.Parse(set[1]),
set[0].Select(card => CharCardToPlayingCard(card)).ToList())).ToList();

List<Hand>[] handTypes = [[], [], [], [], [], [], []];

foreach (var hand in hands)
{
if (FiveOfAKind(hand.Cards)) { handTypes.ElementAt(0).Add(hand); continue; }
if (FourOfAKind(hand.Cards)) { handTypes.ElementAt(1).Add(hand); continue; }
if (FullHouse(hand.Cards)) { handTypes.ElementAt(2).Add(hand); continue; }
if (ThreeOfAKind(hand.Cards)) { handTypes.ElementAt(3).Add(hand); continue; }
if (TwoPair(hand.Cards)) { handTypes.ElementAt(4).Add(hand); continue; }
if (OnePair(hand.Cards)) { handTypes.ElementAt(5).Add(hand); continue; }
if (HighCard(hand.Cards)) { handTypes.ElementAt(6).Add(hand); continue; }
}

var rankedHands = RankHandsByTypes(handTypes);

long totalWinnings = CalculateWinnings(rankedHands);

return totalWinnings.ToString();
}

public string PartB(string input)
{
var sets = InputHelper.ToStringArray(input);

List<Hand> hands = sets
.Select(set => set.Split(' '))
.Select(set => new Hand(
int.Parse(set[1]),
set[0].Select(card => CharCardToPlayingCardJokerWildCards(card)).ToList())).ToList();

List<Hand>[] handTypes = [[], [], [], [], [], [], []];

foreach (var hand in hands)
{
if (FiveOfAKindWithWildcards(hand.Cards)) { handTypes.ElementAt(0).Add(hand); continue; }
if (FourOfAKindWithWildcards(hand.Cards)) { handTypes.ElementAt(1).Add(hand); continue; }
if (FullHouseWithWildcards(hand.Cards)) { handTypes.ElementAt(2).Add(hand); continue; }
if (ThreeOfAKindWithWildcards(hand.Cards)) { handTypes.ElementAt(3).Add(hand); continue; }
if (TwoPairWithWildcards(hand.Cards)) { handTypes.ElementAt(4).Add(hand); continue; }
if (OnePairWithWildcards(hand.Cards)) { handTypes.ElementAt(5).Add(hand); continue; }
if (HighCardWithWildcards(hand.Cards)) { handTypes.ElementAt(6).Add(hand); continue; }
}

var rankedHands = RankHandsByTypes(handTypes);

long totalWinnings = CalculateWinnings(rankedHands);

return totalWinnings.ToString();
}

private static PlayingCard CharCardToPlayingCard(char card)
{
return card switch
{
'A' => PlayingCard.AceHigh,
'2' => PlayingCard.Two,
'3' => PlayingCard.Three,
'4' => PlayingCard.Four,
'5' => PlayingCard.Five,
'6' => PlayingCard.Six,
'7' => PlayingCard.Seven,
'8' => PlayingCard.Eight,
'9' => PlayingCard.Nine,
'T' => PlayingCard.Ten,
'J' => PlayingCard.Jack,
'Q' => PlayingCard.Queen,
'K' => PlayingCard.King,
_ => PlayingCard.AceLow,
};
}

private static PlayingCard CharCardToPlayingCardJokerWildCards(char card)
{
return card switch
{
'J' => PlayingCard.Joker,
'A' => PlayingCard.AceHigh,
'2' => PlayingCard.Two,
'3' => PlayingCard.Three,
'4' => PlayingCard.Four,
'5' => PlayingCard.Five,
'6' => PlayingCard.Six,
'7' => PlayingCard.Seven,
'8' => PlayingCard.Eight,
'9' => PlayingCard.Nine,
'T' => PlayingCard.Ten,
'Q' => PlayingCard.Queen,
'K' => PlayingCard.King,
_ => PlayingCard.AceLow,
};
}

private static bool FiveOfAKind(List<PlayingCard> hand)
{
return hand.Distinct().Count() == 1;
}

private static bool FourOfAKind(List<PlayingCard> hand)
{
return hand.GroupBy(card => card).Any(a => a.Count() == 4);
}

private static bool FullHouse(List<PlayingCard> hand)
{
return hand.GroupBy(card => card).Where(a => a.Count() >= 2).Count() == 2
&& hand.Distinct().Count() == 2;
}

private static bool ThreeOfAKind(List<PlayingCard> hand)
{
return hand.GroupBy(card => card).Any(a => a.Count() == 3);
}

private static bool TwoPair(List<PlayingCard> hand)
{
return hand.GroupBy(card => card).Where(a => a.Count() == 2).Count() == 2;
}

private static bool OnePair(List<PlayingCard> hand)
{
return hand.GroupBy(card => card).Any(a => a.Count() == 2);
}

private static bool HighCard(List<PlayingCard> hand)
{
return hand.Distinct().Count() == 5;
}

private static bool FiveOfAKindWithWildcards(List<PlayingCard> hand)
{
var handWithoutWildcards = hand.Where(card => card != PlayingCard.Joker).ToList();

return handWithoutWildcards.Distinct().Count() <= 1;
}

private static bool FourOfAKindWithWildcards(List<PlayingCard> hand)
{
var numberOfWildCards = hand.Where(card => card == PlayingCard.Joker).Count();
var handWithoutWildcards = hand.Where(card => card != PlayingCard.Joker).ToList();

return handWithoutWildcards.GroupBy(card => card).Any(a => a.Count() == 4 - numberOfWildCards);
}

private static bool FullHouseWithWildcards(List<PlayingCard> hand)
{
var handWithoutWildcards = hand.Where(card => card != PlayingCard.Joker).ToList();

return hand.GroupBy(card => card).Where(a => a.Count() >= 2).Count() == 2
&& handWithoutWildcards.Distinct().Count() == 2;
}

private static bool ThreeOfAKindWithWildcards(List<PlayingCard> hand)
{
var numberOfWildCards = hand.Where(card => card == PlayingCard.Joker).Count();
var handWithoutWildcards = hand.Where(card => card != PlayingCard.Joker).ToList();

return handWithoutWildcards.GroupBy(card => card).Any(a => a.Count() == 3 - numberOfWildCards);
}

private static bool TwoPairWithWildcards(List<PlayingCard> hand)
{
var numberOfWildCards = hand.Where(card => card == PlayingCard.Joker).Count();

return hand.GroupBy(card => card).Where(a => a.Count() == 2 - numberOfWildCards).Count() == 2 - numberOfWildCards;
}

private static bool OnePairWithWildcards(List<PlayingCard> hand)
{
var numberOfWildCards = hand.Where(card => card == PlayingCard.Joker).Count();

return hand.GroupBy(card => card).Any(a => a.Count() == 2 - numberOfWildCards);
}

private static bool HighCardWithWildcards(List<PlayingCard> hand)
{
var handWithoutWildcards = hand.Where(card => card != PlayingCard.Joker).ToList();

return handWithoutWildcards.Distinct().Count() == handWithoutWildcards.Count;
}

private List<Hand> RankHandsByTypes(List<Hand>[] hands)
{
List<Hand> rankedTypeByHands = [];

for (int i = 0; i < hands.Length; i++)
{
hands[i] =
[
.. hands[i]
.OrderByDescending(x => x.Cards[4])
.OrderByDescending(x => x.Cards[3])
.OrderByDescending(x => x.Cards[2])
.OrderByDescending(x => x.Cards[1])
.OrderByDescending(x => x.Cards[0])
];
}

foreach (var rank in hands)
{
rankedTypeByHands.AddRange(rank);
}

return rankedTypeByHands;
}

private long CalculateWinnings(List<Hand> hands)
{
long total = 0;

hands.Reverse();

for (int i = 1; i <= hands.Count; i++)
{
total += hands[i - 1].Bid * i;
}

return total;
}

internal class Hand
{
public List<PlayingCard> Cards { get; }
public int Bid { get; }

public Hand(int bid, List<PlayingCard> cards)
{
Bid = bid;
Cards = cards;
}
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Feel free to run through the solutions (*Note: Potential Spoilers* :see_no_evil:
|2020|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|||||||
|2021|:star2:|:star2:|||||||||||||||||||||||
|2022|||||||||||||||||||||||||
|2023|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|||||||||||||||||||
|2023|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:|:star2:||||||||||||||||||

<!-- GETTING STARTED -->
## Getting Started
Expand Down
30 changes: 30 additions & 0 deletions Tests/AdventOfCode.Solutions.Tests/_2023/Day7Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace AdventOfCode.Solutions.Tests._2023;

public class Day7Tests : DayTests
{
[Test]
public async Task PartA()
{
// Arrange
string expected = "247961593";

// Act
var solution = await _solverService.SolveDay(2023, 7);

// Assert
solution.PartA.Solution.Should().Be(expected);
}

[Test]
public async Task PartB()
{
// Arrange
string expected = "248750699";

// Act
var solution = await _solverService.SolveDay(2023, 7);

// Assert
solution.PartB.Solution.Should().Be(expected);
}
}

0 comments on commit 5c1b5c7

Please sign in to comment.