I'm a Sr. Software Engineer at Flashpoint. I specialize in Python and Go, building functional, practical, and maintainable web systems leveraging Kubernetes and the cloud. Blog opinions are my own.
This one seemed pretty straightforward, so I knocked it out in Python in an effort to get caught up. I forgot about the "no repeats" rule and stared at my terminal recursing infinitely for a while. Also, deque was a great idea, but I didn't realize you couldn't slice a deque in Python, which made copying them partially a bit awkward.
"""Day 22: Crab Combat
Play a crab in Combat (War) and calculate the score of the winner.
"""fromcollectionsimportdequefromcopyimportdeepcopydefparse(filename):"""Parses the input file into a list of players numbers. Input file
has the format:
Player 1:
1
2
3
Player 2:
4
5
6
Supports arbitrary numbers of players.
"""players=[deque()]current=0withopen(filename,"r")asf:forlineinf:line=line.strip()ifline.isnumeric():players[current].append(int(line))continueifnotline:current+=1players.append(deque())returnplayersdefpart1(players):"""Simulate a game of war and then calculate the score of the
winner.
"""whileall(playerforplayerinplayers):plays=[player.popleft()forplayerinplayers]winner=max((value,ind)for(ind,value)inenumerate(plays))players[winner[1]].extend(sorted(plays,reverse=True))returnmax(calculate_score(player)forplayerinplayers)defrecursive_war(p1,p2):"""Recursive war follows these rules:
1. If a particular configuration has been seen before in a game,
Player 1 automatically wins.
2. Otherwise, if either player's number is greater than the number
of cards they have, the player with the highest number wins.
3. Otherwise, the winner is the winner of a sub-game, where
players play with the 1-nth cards in their deck where n is the
value of their 0th card.
Subgames do not affect parent games' decks (i.e. they are played
with copies).
Returns the calculated score of the winner of the root game's deck.
Not designed for arbitrary #'s of players. Only two.
"""seen=set()whilep1andp2:ifstr(p1)+str(p2)inseen:return0,calculate_score(p1)else:seen.add(str(p1)+str(p2))v1,v2=p1.popleft(),p2.popleft()ifv1<=len(p1)andv2<=len(p2):winner,_score=recursive_war(deque(list(p1)[:v1]),deque(list(p2)[:v2]))else:winner=0ifv1>v2else1ifwinner==0:p1.extend([v1,v2])else:p2.extend([v2,v1])ifp1:return0,calculate_score(p1)else:return1,calculate_score(p2)defcalculate_score(player):"""Calculate the "score" of a player's deck. Their bottom card
times 1 plus their second bottom card times 2 plus ...
"""returnsum(val*indforind,valinenumerate(reversed(player),start=1))defpart2(players):"""Calculate the score of a winner of recursive War."""winner,score=recursive_war(*players)returnscoreif__name__=="__main__":players=parse("data/day22_test.txt")assertpart1(deepcopy(players))==306assertpart2(players)==291print("All tests passed!")players=parse("data/day22.txt")print("Part 1: ",part1(deepcopy(players)))print("Part 2: ",part2(players))
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
This one seemed pretty straightforward, so I knocked it out in Python in an effort to get caught up. I forgot about the "no repeats" rule and stared at my terminal recursing infinitely for a while. Also,
dequewas a great idea, but I didn't realize you couldn't slice adequein Python, which made copying them partially a bit awkward.