aboutsummaryrefslogtreecommitdiff
path: root/2018/src/day09.cpp
blob: d1b4eb0ae2433ae56346661d37f58363da5ae7f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
#include <vector>

using namespace std;

namespace {

struct Marble {
	explicit Marble(long score)
	    : score{ score }
	{
	}

	Marble(long score, Marble* prev, Marble* next)
	    : score{ score }
	    , prev{ prev }
	    , next{ next }
	{
	}

	[[nodiscard]]
	Marble* insert_after_two(long value) const
	{
		auto* insert_after = this->next;

		auto* new_marble = new Marble(value, insert_after, insert_after->next); // NOLINT

		insert_after->next->prev = new_marble;
		insert_after->next       = new_marble;

		return new_marble;
	}

	[[nodiscard]]
	pair<Marble*, long> remove_seventh_back()
	{
		auto* to_remove = this;
		for ( int i = 0; i != 7; ++i ) {
			to_remove = to_remove->prev;
		}

		to_remove->prev->next = to_remove->next;
		to_remove->next->prev = to_remove->prev;

		auto* new_current = to_remove->next;
		auto  score       = to_remove->score;

		delete to_remove; // NOLINT

		return { new_current, score };
	}

	long    score;
	Marble* prev{ this };
	Marble* next{ this };
};

long
solve(const size_t players, const long last_marble)
{
	auto current = new Marble(0); // NOLINT

	vector<long> scores(players, 0);
	size_t       player = 0;

	for ( long marble = 1; marble <= last_marble; ++marble ) {
		if ( marble % 23 != 0 ) {
			current = current->insert_after_two(marble);
		}
		else {
			auto [new_current, removed_score] = current->remove_seventh_back();

			scores[player] += marble + removed_score;
			current = new_current;
		}

		player += 1;
		player %= players;
	}

	Marble* start = current;
	do {
		Marble* next = start->next;
		delete start; // NOLINT
		start = next;
	} while ( start != current );

	return ranges::max(scores);
}

void
part1(const size_t players, const long last_marble)
{
	cout << "Part 1: " << solve(players, last_marble) << '\n';
}

void
part2(const size_t players, const long last_marble)
{
	cout << "Part 2: " << solve(players, last_marble * 100) << '\n';
}

} // namespace

int
main()
{
	static const size_t players = 400;
	static const long   points  = 71864;

	part1(players, points);
	part2(players, points);
}