Add .clang-format and apply it

This commit is contained in:
2021-12-02 07:18:16 +00:00
parent e58dede1b6
commit cd5e2538df
103 changed files with 2714 additions and 2132 deletions

54
.clang-format Normal file
View File

@@ -0,0 +1,54 @@
---
AlwaysBreakTemplateDeclarations: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterFunction: true
AfterStruct: true
AfterUnion: true
IndentBraces: false
BeforeElse: true
BeforeCatch: true
BreakStringLiterals: true
ColumnLimit: 100
CompactNamespaces: true
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
FixNamespaceComments: true
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^".*-messages\.hh"$'
Priority: 3
- Regex: '<catch2/'
Priority: 20
- Regex: '^"util/'
Priority: 2
- Regex: '^"gd/(libgen|nl_types)\.h"$'
Priority: 0
- Regex: '^"gd/'
Priority: 1
- Regex: '<[[:alnum:]_.]+>'
Priority: 100
IndentPPDirectives: AfterHash
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
Standard: Cpp11
...

View File

@@ -2,7 +2,8 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
int main(int argc, char **argv) { int main(int argc, char** argv)
{
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
int floor = 0; int floor = 0;
for (auto c : line) { for (auto c : line) {

View File

@@ -2,7 +2,8 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
int main(int argc, char **argv) { int main(int argc, char** argv)
{
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
int floor = 0; int floor = 0;
std::string::size_type pos = 0; std::string::size_type pos = 0;

View File

@@ -3,11 +3,13 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
struct Box { struct Box
{
/** Construct box. /** Construct box.
* \param s String representation of dimensions 'lxwxh' * \param s String representation of dimensions 'lxwxh'
*/ */
Box(std::string const &s) { Box(std::string const& s)
{
std::size_t pos = 0; std::size_t pos = 0;
l_ = std::stoul(s, &pos, 10); l_ = std::stoul(s, &pos, 10);
assert(s[pos] == 'x'); assert(s[pos] == 'x');
@@ -20,7 +22,8 @@ struct Box {
} }
// How much paper does this box need? // How much paper does this box need?
unsigned long paper_needed() const { unsigned long paper_needed() const
{
unsigned long s1 = l_ * w_; unsigned long s1 = l_ * w_;
unsigned long s2 = w_ * h_; unsigned long s2 = w_ * h_;
unsigned long s3 = h_ * l_; unsigned long s3 = h_ * l_;
@@ -32,7 +35,8 @@ struct Box {
unsigned long h_; unsigned long h_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
unsigned long total = 0; unsigned long total = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
Box b(line); Box b(line);

View File

@@ -3,11 +3,13 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
struct Box { struct Box
{
/** Construct box. /** Construct box.
* \param s String representation of dimensions 'lxwxh' * \param s String representation of dimensions 'lxwxh'
*/ */
Box(std::string const &s) { Box(std::string const& s)
{
std::size_t pos = 0; std::size_t pos = 0;
l_ = std::stoul(s, &pos, 10); l_ = std::stoul(s, &pos, 10);
assert(s[pos] == 'x'); assert(s[pos] == 'x');
@@ -20,7 +22,8 @@ struct Box {
} }
// How much paper does this box need? // How much paper does this box need?
unsigned long paper_needed() const { unsigned long paper_needed() const
{
unsigned long s1 = l_ * w_; unsigned long s1 = l_ * w_;
unsigned long s2 = w_ * h_; unsigned long s2 = w_ * h_;
unsigned long s3 = h_ * l_; unsigned long s3 = h_ * l_;
@@ -28,7 +31,8 @@ struct Box {
} }
// How much ribbon do we need? // How much ribbon do we need?
unsigned long ribbon_needed() const { unsigned long ribbon_needed() const
{
// The various side perimeters - we want the min of these multiplied by // The various side perimeters - we want the min of these multiplied by
// volume. // volume.
unsigned long p1 = 2 * (l_ + w_); unsigned long p1 = 2 * (l_ + w_);
@@ -42,7 +46,8 @@ struct Box {
unsigned long h_; unsigned long h_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
unsigned long total = 0; unsigned long total = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
Box b(line); Box b(line);

View File

@@ -4,18 +4,19 @@
#include <set> #include <set>
#include <string> #include <string>
struct Pos { struct Pos
{
Pos(int x, int y) : x_(x), y_(y) {} Pos(int x, int y) : x_(x), y_(y) {}
bool operator<(Pos const &rhs) const noexcept { bool operator<(Pos const& rhs) const noexcept
{
return x_ < rhs.x_ || (x_ == rhs.x_ && y_ < rhs.y_); return x_ < rhs.x_ || (x_ == rhs.x_ && y_ < rhs.y_);
} }
bool operator==(Pos const &rhs) const noexcept { bool operator==(Pos const& rhs) const noexcept { return x_ == rhs.x_ && y_ == rhs.y_; }
return x_ == rhs.x_ && y_ == rhs.y_;
}
void move(char c) { void move(char c)
{
switch (c) { switch (c) {
case '>': case '>':
++x_; ++x_;
@@ -39,7 +40,8 @@ struct Pos {
int y_; int y_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
std::set<Pos> visited; std::set<Pos> visited;
Pos santa(0, 0); Pos santa(0, 0);

View File

@@ -4,18 +4,19 @@
#include <set> #include <set>
#include <string> #include <string>
struct Pos { struct Pos
{
Pos(int x, int y) : x_(x), y_(y) {} Pos(int x, int y) : x_(x), y_(y) {}
bool operator<(Pos const &rhs) const noexcept { bool operator<(Pos const& rhs) const noexcept
{
return x_ < rhs.x_ || (x_ == rhs.x_ && y_ < rhs.y_); return x_ < rhs.x_ || (x_ == rhs.x_ && y_ < rhs.y_);
} }
bool operator==(Pos const &rhs) const noexcept { bool operator==(Pos const& rhs) const noexcept { return x_ == rhs.x_ && y_ == rhs.y_; }
return x_ == rhs.x_ && y_ == rhs.y_;
}
void move(char c) noexcept { void move(char c) noexcept
{
switch (c) { switch (c) {
case '>': case '>':
++x_; ++x_;
@@ -39,7 +40,8 @@ struct Pos {
int y_; int y_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
std::set<Pos> visited; std::set<Pos> visited;
Pos santa(0, 0); Pos santa(0, 0);
@@ -51,7 +53,8 @@ int main(int argc, char **argv) {
if (do_robo) { if (do_robo) {
robo_santa.move(c); robo_santa.move(c);
visited.insert(robo_santa); visited.insert(robo_santa);
} else { }
else {
santa.move(c); santa.move(c);
visited.insert(santa); visited.insert(santa);
} }

View File

@@ -8,7 +8,8 @@
using MD5Digest = unsigned char[EVP_MAX_MD_SIZE]; using MD5Digest = unsigned char[EVP_MAX_MD_SIZE];
unsigned int md5(MD5Digest digest, std::string const &s) { unsigned int md5(MD5Digest digest, std::string const& s)
{
EVP_MD const* md{EVP_md5()}; EVP_MD const* md{EVP_md5()};
unsigned int md_len; unsigned int md_len;
@@ -20,14 +21,16 @@ unsigned int md5(MD5Digest digest, std::string const &s) {
return md_len; return md_len;
} }
bool is_valid(std::string const &s) { bool is_valid(std::string const& s)
{
MD5Digest digest; MD5Digest digest;
auto len = md5(digest, s); auto len = md5(digest, s);
assert(len >= 3); assert(len >= 3);
return digest[0] == 0 && digest[1] == 0 && (digest[2] & 0xf0) == 0; return digest[0] == 0 && digest[1] == 0 && (digest[2] & 0xf0) == 0;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
unsigned i = 0; unsigned i = 0;
while (!is_valid(line + std::to_string(i))) { while (!is_valid(line + std::to_string(i))) {

View File

@@ -8,7 +8,8 @@
using MD5Digest = unsigned char[EVP_MAX_MD_SIZE]; using MD5Digest = unsigned char[EVP_MAX_MD_SIZE];
unsigned int md5(MD5Digest digest, std::string const &s) { unsigned int md5(MD5Digest digest, std::string const& s)
{
EVP_MD const* md{EVP_md5()}; EVP_MD const* md{EVP_md5()};
unsigned int md_len; unsigned int md_len;
@@ -20,14 +21,16 @@ unsigned int md5(MD5Digest digest, std::string const &s) {
return md_len; return md_len;
} }
bool is_valid(std::string const &s) { bool is_valid(std::string const& s)
{
MD5Digest digest; MD5Digest digest;
auto len = md5(digest, s); auto len = md5(digest, s);
assert(len >= 3); assert(len >= 3);
return digest[0] == 0 && digest[1] == 0 && digest[2] == 0; return digest[0] == 0 && digest[1] == 0 && digest[2] == 0;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
unsigned i = 0; unsigned i = 0;
while (!is_valid(line + std::to_string(i))) { while (!is_valid(line + std::to_string(i))) {

View File

@@ -9,7 +9,8 @@
// >=3 vowels // >=3 vowels
// At least one double letter // At least one double letter
// No instances of 'ab', 'cd', 'pq', or 'xy'. // No instances of 'ab', 'cd', 'pq', or 'xy'.
bool is_nice(std::string const &s) noexcept { bool is_nice(std::string const& s) noexcept
{
unsigned vowel_count = 0; unsigned vowel_count = 0;
bool repeated = false; bool repeated = false;
char last = '\0'; char last = '\0';
@@ -22,8 +23,8 @@ bool is_nice(std::string const &s) noexcept {
if (c == last) { if (c == last) {
repeated = true; repeated = true;
} }
if ((last == 'a' && c == 'b') || (last == 'c' && c == 'd') || if ((last == 'a' && c == 'b') || (last == 'c' && c == 'd') || (last == 'p' && c == 'q') ||
(last == 'p' && c == 'q') || (last == 'x' && c == 'y')) { (last == 'x' && c == 'y')) {
return false; return false;
} }
last = c; last = c;
@@ -32,7 +33,8 @@ bool is_nice(std::string const &s) noexcept {
return repeated && vowel_count >= 3; return repeated && vowel_count >= 3;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
unsigned nice_strings; unsigned nice_strings;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
nice_strings += is_nice(line); nice_strings += is_nice(line);

View File

@@ -8,7 +8,8 @@
// Nice strings have: // Nice strings have:
// repeated double letters - but not overlapping // repeated double letters - but not overlapping
// repeated letters separated by one other. // repeated letters separated by one other.
bool is_nice(std::string const &s) noexcept { bool is_nice(std::string const& s) noexcept
{
bool repeated_pair = false; bool repeated_pair = false;
bool repeated_sep = false; bool repeated_sep = false;
@@ -34,7 +35,8 @@ bool is_nice(std::string const &s) noexcept {
return repeated_pair && repeated_sep; return repeated_pair && repeated_sep;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
unsigned nice_strings; unsigned nice_strings;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
nice_strings += is_nice(line); nice_strings += is_nice(line);

View File

@@ -10,10 +10,11 @@ enum class Action { TurnOn, Toggle, TurnOff };
using Point = std::pair<unsigned, unsigned>; using Point = std::pair<unsigned, unsigned>;
/// A command /// A command
struct Command { struct Command
Command(std::string const &s) { {
const char *re = Command(std::string const& s)
"(turn on|toggle|turn off)\\s(\\d+),(\\d+)\\sthrough\\s(\\d+),(\\d+)"; {
const char* re = "(turn on|toggle|turn off)\\s(\\d+),(\\d+)\\sthrough\\s(\\d+),(\\d+)";
std::smatch m; std::smatch m;
if (!std::regex_search(s, m, std::regex(re))) { if (!std::regex_search(s, m, std::regex(re))) {
std::cerr << "Unable to interpret:" << s << "\n"; std::cerr << "Unable to interpret:" << s << "\n";
@@ -21,11 +22,14 @@ struct Command {
} }
if (m.str(1) == std::string("turn on")) { if (m.str(1) == std::string("turn on")) {
act_ = Action::TurnOn; act_ = Action::TurnOn;
} else if (m.str(1) == std::string("turn off")) { }
else if (m.str(1) == std::string("turn off")) {
act_ = Action::TurnOff; act_ = Action::TurnOff;
} else if (m.str(1) == std::string("toggle")) { }
else if (m.str(1) == std::string("toggle")) {
act_ = Action::Toggle; act_ = Action::Toggle;
} else { }
else {
assert(false); assert(false);
} }
bottom_left_.first = std::stoul(m.str(2), nullptr, 10); bottom_left_.first = std::stoul(m.str(2), nullptr, 10);
@@ -40,8 +44,11 @@ struct Command {
}; };
/// Array of lights /// Array of lights
template <unsigned N> struct Array { template<unsigned N>
Array() noexcept { struct Array
{
Array() noexcept
{
for (unsigned i = 0; i < N; ++i) { for (unsigned i = 0; i < N; ++i) {
for (unsigned j = 0; j < N; ++j) { for (unsigned j = 0; j < N; ++j) {
lights_[i][j] = false; lights_[i][j] = false;
@@ -50,16 +57,15 @@ template <unsigned N> struct Array {
} }
/// Apply a command /// Apply a command
void apply(Command const &command) noexcept { void apply(Command const& command) noexcept
{
assert(command.bottom_left_.first < N); assert(command.bottom_left_.first < N);
assert(command.bottom_left_.second < N); assert(command.bottom_left_.second < N);
assert(command.top_right_.first < N); assert(command.top_right_.first < N);
assert(command.top_right_.second < N); assert(command.top_right_.second < N);
for (unsigned i = command.bottom_left_.first; i <= command.top_right_.first; for (unsigned i = command.bottom_left_.first; i <= command.top_right_.first; ++i) {
++i) { for (unsigned j = command.bottom_left_.second; j <= command.top_right_.second; ++j) {
for (unsigned j = command.bottom_left_.second;
j <= command.top_right_.second; ++j) {
switch (command.act_) { switch (command.act_) {
case Action::TurnOn: case Action::TurnOn:
lights_[i][j] = true; lights_[i][j] = true;
@@ -76,7 +82,8 @@ template <unsigned N> struct Array {
} }
/// How many lights are on /// How many lights are on
unsigned num_on() const noexcept { unsigned num_on() const noexcept
{
unsigned count = 0; unsigned count = 0;
for (unsigned i = 0; i < N; ++i) { for (unsigned i = 0; i < N; ++i) {
for (unsigned j = 0; j < N; ++j) { for (unsigned j = 0; j < N; ++j) {
@@ -88,7 +95,8 @@ template <unsigned N> struct Array {
} }
/// Output a bitmap /// Output a bitmap
void bitmap() const { void bitmap() const
{
std::cout << "P1\n" << N << " " << N << "\n"; std::cout << "P1\n" << N << " " << N << "\n";
for (unsigned i = 0; i < N; ++i) { for (unsigned i = 0; i < N; ++i) {
for (unsigned j = 0; j < N; ++j) { for (unsigned j = 0; j < N; ++j) {
@@ -104,7 +112,8 @@ template <unsigned N> struct Array {
bool lights_[N][N]; bool lights_[N][N];
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Array<1000> arr; Array<1000> arr;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
Command cmd(line); Command cmd(line);

View File

@@ -7,10 +7,11 @@
enum class Action { TurnOn, Toggle, TurnOff }; enum class Action { TurnOn, Toggle, TurnOff };
using Point = std::pair<unsigned, unsigned>; using Point = std::pair<unsigned, unsigned>;
struct Command { struct Command
Command(std::string const &s) { {
const char *re = Command(std::string const& s)
"(turn on|toggle|turn off)\\s(\\d+),(\\d+)\\sthrough\\s(\\d+),(\\d+)"; {
const char* re = "(turn on|toggle|turn off)\\s(\\d+),(\\d+)\\sthrough\\s(\\d+),(\\d+)";
std::smatch m; std::smatch m;
if (!std::regex_search(s, m, std::regex(re))) { if (!std::regex_search(s, m, std::regex(re))) {
std::cerr << "Unable to interpret:" << s << "\n"; std::cerr << "Unable to interpret:" << s << "\n";
@@ -18,11 +19,14 @@ struct Command {
} }
if (m.str(1) == std::string("turn on")) { if (m.str(1) == std::string("turn on")) {
act_ = Action::TurnOn; act_ = Action::TurnOn;
} else if (m.str(1) == std::string("turn off")) { }
else if (m.str(1) == std::string("turn off")) {
act_ = Action::TurnOff; act_ = Action::TurnOff;
} else if (m.str(1) == std::string("toggle")) { }
else if (m.str(1) == std::string("toggle")) {
act_ = Action::Toggle; act_ = Action::Toggle;
} else { }
else {
assert(false); assert(false);
} }
bottom_left_.first = std::stoul(m.str(2), nullptr, 10); bottom_left_.first = std::stoul(m.str(2), nullptr, 10);
@@ -36,8 +40,11 @@ struct Command {
Point top_right_; Point top_right_;
}; };
template <unsigned N> struct Array { template<unsigned N>
Array() noexcept { struct Array
{
Array() noexcept
{
for (unsigned i = 0; i < N; ++i) { for (unsigned i = 0; i < N; ++i) {
for (unsigned j = 0; j < N; ++j) { for (unsigned j = 0; j < N; ++j) {
lights_[i][j] = 0; lights_[i][j] = 0;
@@ -45,16 +52,15 @@ template <unsigned N> struct Array {
} }
} }
void apply(Command const &command) noexcept { void apply(Command const& command) noexcept
{
assert(command.bottom_left_.first < N); assert(command.bottom_left_.first < N);
assert(command.bottom_left_.second < N); assert(command.bottom_left_.second < N);
assert(command.top_right_.first < N); assert(command.top_right_.first < N);
assert(command.top_right_.second < N); assert(command.top_right_.second < N);
for (unsigned i = command.bottom_left_.first; i <= command.top_right_.first; for (unsigned i = command.bottom_left_.first; i <= command.top_right_.first; ++i) {
++i) { for (unsigned j = command.bottom_left_.second; j <= command.top_right_.second; ++j) {
for (unsigned j = command.bottom_left_.second;
j <= command.top_right_.second; ++j) {
switch (command.act_) { switch (command.act_) {
case Action::TurnOn: case Action::TurnOn:
++lights_[i][j]; ++lights_[i][j];
@@ -72,7 +78,8 @@ template <unsigned N> struct Array {
} }
} }
unsigned brightness() const noexcept { unsigned brightness() const noexcept
{
unsigned count = 0; unsigned count = 0;
for (unsigned i = 0; i < N; ++i) { for (unsigned i = 0; i < N; ++i) {
for (unsigned j = 0; j < N; ++j) { for (unsigned j = 0; j < N; ++j) {
@@ -83,7 +90,8 @@ template <unsigned N> struct Array {
} }
/// Output a bitmap /// Output a bitmap
void bitmap() const { void bitmap() const
{
unsigned max = 0; unsigned max = 0;
for (unsigned i = 0; i < N; ++i) { for (unsigned i = 0; i < N; ++i) {
for (unsigned j = 0; j < N; ++j) { for (unsigned j = 0; j < N; ++j) {
@@ -103,7 +111,8 @@ template <unsigned N> struct Array {
unsigned lights_[N][N]; unsigned lights_[N][N];
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Array<1000> arr; Array<1000> arr;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
Command cmd(line); Command cmd(line);

View File

@@ -24,9 +24,14 @@
// implementation) // implementation)
// helper type for the visitor #4 // helper type for the visitor #4
template <class... Ts> struct Overloaded : Ts... { using Ts::operator()...; }; template<class... Ts>
struct Overloaded : Ts...
{
using Ts::operator()...;
};
// explicit deduction guide (not needed as of C++20) // explicit deduction guide (not needed as of C++20)
template <class... Ts> Overloaded(Ts...) -> Overloaded<Ts...>; template<class... Ts>
Overloaded(Ts...) -> Overloaded<Ts...>;
/// Instruction action /// Instruction action
enum class Action { enum class Action {
@@ -39,7 +44,8 @@ enum class Action {
}; };
/// Pretty-print action /// Pretty-print action
std::ostream &operator<<(std::ostream &os, Action act) { std::ostream& operator<<(std::ostream& os, Action act)
{
switch (act) { switch (act) {
case Action::Set: case Action::Set:
os << "SET"; os << "SET";
@@ -68,9 +74,10 @@ using Wire = std::string; ///< Wire name (string)
using Signal = std::variant<Value, Wire>; ///< Either a wire or explicit value using Signal = std::variant<Value, Wire>; ///< Either a wire or explicit value
/// Outputter for a signal /// Outputter for a signal
std::ostream &operator<<(std::ostream &os, Signal const &signal) { std::ostream& operator<<(std::ostream& os, Signal const& signal)
{
return std::visit( return std::visit(
[&os](auto &&arg) -> std::ostream & { [&os](auto&& arg) -> std::ostream& {
os << arg; os << arg;
return os; return os;
}, },
@@ -78,7 +85,8 @@ std::ostream &operator<<(std::ostream &os, Signal const &signal) {
} }
/** \brief An instruction. */ /** \brief An instruction. */
struct Instruction { struct Instruction
{
/** \brief Construct an instruction. /** \brief Construct an instruction.
* *
* \subsection Grammar * \subsection Grammar
@@ -92,7 +100,8 @@ struct Instruction {
* binop := signal op signal '->' wire * binop := signal op signal '->' wire
* instr := binop | not | set * instr := binop | not | set
*/ */
Instruction(std::string const &s) { Instruction(std::string const& s)
{
if (parse_bin_op(s)) { if (parse_bin_op(s)) {
return; return;
} }
@@ -110,20 +119,22 @@ struct Instruction {
Action action() const noexcept { return act_; } Action action() const noexcept { return act_; }
/// Get the destination wire /// Get the destination wire
Wire const &dest() const noexcept { return dest_; } Wire const& dest() const noexcept { return dest_; }
/// Get the first (or only) source /// Get the first (or only) source
Signal const &src1() const noexcept { return src1_; } Signal const& src1() const noexcept { return src1_; }
/// Get the second source /// Get the second source
Signal const &src2() const noexcept { Signal const& src2() const noexcept
{
assert(act_ != Action::Set && act_ != Action::Not); assert(act_ != Action::Set && act_ != Action::Not);
return src2_; return src2_;
} }
private: private:
/// Parse a <not> instruction. Return true if successful. /// Parse a <not> instruction. Return true if successful.
bool parse_not(std::string const &s) { bool parse_not(std::string const& s)
{
if (s.substr(0, 4) == "NOT ") { if (s.substr(0, 4) == "NOT ") {
std::string::size_type pos = 4; std::string::size_type pos = 4;
while (s[pos] == ' ') { while (s[pos] == ' ') {
@@ -135,7 +146,8 @@ private:
} }
/// Parse a <bin_op> instruction. Return true if successful. /// Parse a <bin_op> instruction. Return true if successful.
bool parse_bin_op(std::string const &s) { bool parse_bin_op(std::string const& s)
{
static const std::regex re("^([[:lower:][:digit:]]+) ([[:upper:]]+) " static const std::regex re("^([[:lower:][:digit:]]+) ([[:upper:]]+) "
"([[:lower:][:digit:]]+) -> ([[:lower:]]+)"); "([[:lower:][:digit:]]+) -> ([[:lower:]]+)");
std::smatch m; std::smatch m;
@@ -145,13 +157,17 @@ private:
if (m.str(2) == "AND") { if (m.str(2) == "AND") {
act_ = Action::And; act_ = Action::And;
} else if (m.str(2) == "OR") { }
else if (m.str(2) == "OR") {
act_ = Action::Or; act_ = Action::Or;
} else if (m.str(2) == "LSHIFT") { }
else if (m.str(2) == "LSHIFT") {
act_ = Action::LShift; act_ = Action::LShift;
} else if (m.str(2) == "RSHIFT") { }
else if (m.str(2) == "RSHIFT") {
act_ = Action::RShift; act_ = Action::RShift;
} else { }
else {
return false; return false;
} }
dest_ = m.str(4); dest_ = m.str(4);
@@ -165,7 +181,8 @@ private:
/// ///
/// Also used for the latter half of <not> parsing. ACT tells you what is /// Also used for the latter half of <not> parsing. ACT tells you what is
/// being parsed. Returns true if parsing successful. /// being parsed. Returns true if parsing successful.
bool parse_set(std::string const &s, Action act = Action::Set) { bool parse_set(std::string const& s, Action act = Action::Set)
{
static const std::regex re("^([[:lower:][:digit:]]+) -> ([[:lower:]]+)"); static const std::regex re("^([[:lower:][:digit:]]+) -> ([[:lower:]]+)");
std::smatch m; std::smatch m;
if (!std::regex_search(s, m, re)) { if (!std::regex_search(s, m, re)) {
@@ -179,12 +196,14 @@ private:
} }
/// Make a Signal from a string. /// Make a Signal from a string.
Signal make_signal(std::string const &s) { Signal make_signal(std::string const& s)
{
if (std::isdigit(s[0])) { if (std::isdigit(s[0])) {
auto u = std::stoul(s, nullptr, 10); auto u = std::stoul(s, nullptr, 10);
assert(u <= UINT16_MAX); assert(u <= UINT16_MAX);
return Signal(static_cast<std::uint16_t>(u)); return Signal(static_cast<std::uint16_t>(u));
} else { }
else {
return Signal(s); return Signal(s);
} }
} }
@@ -195,7 +214,8 @@ private:
}; };
/// Outputter for an instruction. /// Outputter for an instruction.
std::ostream &operator<<(std::ostream &os, Instruction const &instr) { std::ostream& operator<<(std::ostream& os, Instruction const& instr)
{
os << instr.action() << " " << instr.dest() << ", " << instr.src1(); os << instr.action() << " " << instr.dest() << ", " << instr.src1();
if (instr.action() != Action::Set && instr.action() != Action::Not) { if (instr.action() != Action::Set && instr.action() != Action::Not) {
os << ", " << instr.src2(); os << ", " << instr.src2();
@@ -207,53 +227,55 @@ std::ostream &operator<<(std::ostream &os, Instruction const &instr) {
using ValueMap = std::map<Wire, Value>; ///< Map wires to values using ValueMap = std::map<Wire, Value>; ///< Map wires to values
using Instructions = std::vector<Instruction>; ///< Instructions to execute using Instructions = std::vector<Instruction>; ///< Instructions to execute
struct VM { struct VM
{
/// Add an instruction the the list we have /// Add an instruction the the list we have
void add_instr(Instruction const &instr) { instrs_.push_back(instr); } void add_instr(Instruction const& instr) { instrs_.push_back(instr); }
/// Has this wire a known value? /// Has this wire a known value?
bool has_value(Wire const &w) const noexcept { bool has_value(Wire const& w) const noexcept { return values_.find(w) != values_.end(); }
return values_.find(w) != values_.end();
}
/// Has this signal a known value? /// Has this signal a known value?
bool has_value(Signal const &s) const noexcept { bool has_value(Signal const& s) const noexcept
return std::visit(Overloaded{[](Value v) { return true; }, {
[&](Wire const &w) { return has_value(w); }}, return std::visit(
s); Overloaded{[](Value v) { return true; }, [&](Wire const& w) { return has_value(w); }}, s);
} }
/// Get the value on the wire /// Get the value on the wire
Value value(Wire const &w) const noexcept { Value value(Wire const& w) const noexcept
{
assert(has_value(w)); assert(has_value(w));
return values_.find(w)->second; return values_.find(w)->second;
} }
/// Get the value of a signal /// Get the value of a signal
Value value(Signal const &s) const noexcept { Value value(Signal const& s) const noexcept
return std::visit(Overloaded{[](Value v) { return v; }, {
[&](Wire const &w) { return value(w); }}, return std::visit(
s); Overloaded{[](Value v) { return v; }, [&](Wire const& w) { return value(w); }}, s);
} }
/// Set the value of a wire /// Set the value of a wire
void value(Wire const &w, Value value) { void value(Wire const& w, Value value)
{
auto [it, success] = values_.insert({w, value}); auto [it, success] = values_.insert({w, value});
assert(success); assert(success);
} }
/// Set the value of a signal /// Set the value of a signal
void value(Signal const &s, Value v) { void value(Signal const& s, Value v)
std::visit(Overloaded{[v](Value v2) { assert(v == v2); }, {
[&, v](Wire const &w) { value(w, v); }}, std::visit(
s); Overloaded{[v](Value v2) { assert(v == v2); }, [&, v](Wire const& w) { value(w, v); }}, s);
} }
/// Execute the instructions. Returns true if we have updated some wire /// Execute the instructions. Returns true if we have updated some wire
/// values. /// values.
bool execute() { bool execute()
{
bool done_anything = false; bool done_anything = false;
for (auto const &instr : instrs_) { for (auto const& instr : instrs_) {
done_anything |= execute_instr(instr); done_anything |= execute_instr(instr);
} }
@@ -268,15 +290,15 @@ private:
* An instruction may not be executed if the incoming signals have not been * An instruction may not be executed if the incoming signals have not been
* set yet. * set yet.
*/ */
bool execute_instr(Instruction const &instr) { bool execute_instr(Instruction const& instr)
{
std::cout << instr << " # "; std::cout << instr << " # ";
// First of all check there is something to do - i.e. that the destination // First of all check there is something to do - i.e. that the destination
// register has not been set already. // register has not been set already.
Wire dest = instr.dest(); Wire dest = instr.dest();
if (has_value(dest)) { if (has_value(dest)) {
std::cout << "already has value: " << dest << " = " << value(dest) std::cout << "already has value: " << dest << " = " << value(dest) << "\n";
<< "\n";
return false; return false;
} }
@@ -286,17 +308,13 @@ private:
case Action::Not: case Action::Not:
return execute_single_src(instr, [](Value src) { return ~src; }); return execute_single_src(instr, [](Value src) { return ~src; });
case Action::And: case Action::And:
return execute_double_src( return execute_double_src(instr, [](Value src1, Value src2) { return src1 & src2; });
instr, [](Value src1, Value src2) { return src1 & src2; });
case Action::Or: case Action::Or:
return execute_double_src( return execute_double_src(instr, [](Value src1, Value src2) { return src1 | src2; });
instr, [](Value src1, Value src2) { return src1 | src2; });
case Action::LShift: case Action::LShift:
return execute_double_src( return execute_double_src(instr, [](Value src1, Value src2) { return src1 << src2; });
instr, [](Value src1, Value src2) { return src1 << src2; });
case Action::RShift: case Action::RShift:
return execute_double_src( return execute_double_src(instr, [](Value src1, Value src2) { return src1 >> src2; });
instr, [](Value src1, Value src2) { return src1 >> src2; });
} }
return false; return false;
@@ -307,8 +325,8 @@ private:
* \param fn How to modify the source value to the dest. * \param fn How to modify the source value to the dest.
* \return True if we executed the function. * \return True if we executed the function.
*/ */
bool execute_single_src(Instruction const &instr, bool execute_single_src(Instruction const& instr, std::function<Value(Value)> fn)
std::function<Value(Value)> fn) { {
Wire dest = instr.dest(); Wire dest = instr.dest();
Signal src = instr.src1(); Signal src = instr.src1();
if (has_value(src)) { if (has_value(src)) {
@@ -326,8 +344,8 @@ private:
* \param fn How to modify the source values to the dest. * \param fn How to modify the source values to the dest.
* \return True if we executed the function. * \return True if we executed the function.
*/ */
bool execute_double_src(Instruction const &instr, bool execute_double_src(Instruction const& instr, std::function<Value(Value, Value)> fn)
std::function<Value(Value, Value)> fn) { {
Wire dest = instr.dest(); Wire dest = instr.dest();
Signal src1 = instr.src1(); Signal src1 = instr.src1();
Signal src2 = instr.src2(); Signal src2 = instr.src2();
@@ -345,7 +363,8 @@ private:
Instructions instrs_; Instructions instrs_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
VM vm; VM vm;
// Parse the input // Parse the input
@@ -365,7 +384,8 @@ int main(int argc, char **argv) {
std::cout << "a = "; std::cout << "a = ";
if (!vm.has_value(a)) { if (!vm.has_value(a)) {
std::cout << "UNSET\n"; std::cout << "UNSET\n";
} else { }
else {
std::cout << vm.value(a) << "\n"; std::cout << vm.value(a) << "\n";
} }

View File

@@ -24,9 +24,14 @@
// implementation) // implementation)
// helper type for the visitor #4 // helper type for the visitor #4
template <class... Ts> struct Overloaded : Ts... { using Ts::operator()...; }; template<class... Ts>
struct Overloaded : Ts...
{
using Ts::operator()...;
};
// explicit deduction guide (not needed as of C++20) // explicit deduction guide (not needed as of C++20)
template <class... Ts> Overloaded(Ts...) -> Overloaded<Ts...>; template<class... Ts>
Overloaded(Ts...) -> Overloaded<Ts...>;
/// Instruction action /// Instruction action
enum class Action { enum class Action {
@@ -39,7 +44,8 @@ enum class Action {
}; };
/// Pretty-print action /// Pretty-print action
std::ostream &operator<<(std::ostream &os, Action act) { std::ostream& operator<<(std::ostream& os, Action act)
{
switch (act) { switch (act) {
case Action::Set: case Action::Set:
os << "SET"; os << "SET";
@@ -68,9 +74,10 @@ using Wire = std::string; ///< Wire name (string)
using Signal = std::variant<Value, Wire>; ///< Either a wire or explicit value using Signal = std::variant<Value, Wire>; ///< Either a wire or explicit value
/// Outputter for a signal /// Outputter for a signal
std::ostream &operator<<(std::ostream &os, Signal const &signal) { std::ostream& operator<<(std::ostream& os, Signal const& signal)
{
return std::visit( return std::visit(
[&os](auto &&arg) -> std::ostream & { [&os](auto&& arg) -> std::ostream& {
os << arg; os << arg;
return os; return os;
}, },
@@ -78,7 +85,8 @@ std::ostream &operator<<(std::ostream &os, Signal const &signal) {
} }
/** \brief An instruction. */ /** \brief An instruction. */
struct Instruction { struct Instruction
{
/** \brief Construct an instruction. /** \brief Construct an instruction.
* *
* \subsection Grammar * \subsection Grammar
@@ -92,7 +100,8 @@ struct Instruction {
* binop := signal op signal '->' wire * binop := signal op signal '->' wire
* instr := binop | not | set * instr := binop | not | set
*/ */
Instruction(std::string const &s) { Instruction(std::string const& s)
{
if (parse_bin_op(s)) { if (parse_bin_op(s)) {
return; return;
} }
@@ -110,20 +119,22 @@ struct Instruction {
Action action() const noexcept { return act_; } Action action() const noexcept { return act_; }
/// Get the destination wire /// Get the destination wire
Wire const &dest() const noexcept { return dest_; } Wire const& dest() const noexcept { return dest_; }
/// Get the first (or only) source /// Get the first (or only) source
Signal const &src1() const noexcept { return src1_; } Signal const& src1() const noexcept { return src1_; }
/// Get the second source /// Get the second source
Signal const &src2() const noexcept { Signal const& src2() const noexcept
{
assert(act_ != Action::Set && act_ != Action::Not); assert(act_ != Action::Set && act_ != Action::Not);
return src2_; return src2_;
} }
private: private:
/// Parse a <not> instruction. Return true if successful. /// Parse a <not> instruction. Return true if successful.
bool parse_not(std::string const &s) { bool parse_not(std::string const& s)
{
if (s.substr(0, 4) == "NOT ") { if (s.substr(0, 4) == "NOT ") {
std::string::size_type pos = 4; std::string::size_type pos = 4;
while (s[pos] == ' ') { while (s[pos] == ' ') {
@@ -135,7 +146,8 @@ private:
} }
/// Parse a <bin_op> instruction. Return true if successful. /// Parse a <bin_op> instruction. Return true if successful.
bool parse_bin_op(std::string const &s) { bool parse_bin_op(std::string const& s)
{
static const std::regex re("^([[:lower:][:digit:]]+) ([[:upper:]]+) " static const std::regex re("^([[:lower:][:digit:]]+) ([[:upper:]]+) "
"([[:lower:][:digit:]]+) -> ([[:lower:]]+)"); "([[:lower:][:digit:]]+) -> ([[:lower:]]+)");
std::smatch m; std::smatch m;
@@ -145,13 +157,17 @@ private:
if (m.str(2) == "AND") { if (m.str(2) == "AND") {
act_ = Action::And; act_ = Action::And;
} else if (m.str(2) == "OR") { }
else if (m.str(2) == "OR") {
act_ = Action::Or; act_ = Action::Or;
} else if (m.str(2) == "LSHIFT") { }
else if (m.str(2) == "LSHIFT") {
act_ = Action::LShift; act_ = Action::LShift;
} else if (m.str(2) == "RSHIFT") { }
else if (m.str(2) == "RSHIFT") {
act_ = Action::RShift; act_ = Action::RShift;
} else { }
else {
return false; return false;
} }
dest_ = m.str(4); dest_ = m.str(4);
@@ -165,7 +181,8 @@ private:
/// ///
/// Also used for the latter half of <not> parsing. ACT tells you what is /// Also used for the latter half of <not> parsing. ACT tells you what is
/// being parsed. Returns true if parsing successful. /// being parsed. Returns true if parsing successful.
bool parse_set(std::string const &s, Action act = Action::Set) { bool parse_set(std::string const& s, Action act = Action::Set)
{
static const std::regex re("^([[:lower:][:digit:]]+) -> ([[:lower:]]+)"); static const std::regex re("^([[:lower:][:digit:]]+) -> ([[:lower:]]+)");
std::smatch m; std::smatch m;
if (!std::regex_search(s, m, re)) { if (!std::regex_search(s, m, re)) {
@@ -179,12 +196,14 @@ private:
} }
/// Make a Signal from a string. /// Make a Signal from a string.
Signal make_signal(std::string const &s) { Signal make_signal(std::string const& s)
{
if (std::isdigit(s[0])) { if (std::isdigit(s[0])) {
auto u = std::stoul(s, nullptr, 10); auto u = std::stoul(s, nullptr, 10);
assert(u <= UINT16_MAX); assert(u <= UINT16_MAX);
return Signal(static_cast<std::uint16_t>(u)); return Signal(static_cast<std::uint16_t>(u));
} else { }
else {
return Signal(s); return Signal(s);
} }
} }
@@ -195,7 +214,8 @@ private:
}; };
/// Outputter for an instruction. /// Outputter for an instruction.
std::ostream &operator<<(std::ostream &os, Instruction const &instr) { std::ostream& operator<<(std::ostream& os, Instruction const& instr)
{
os << instr.action() << " " << instr.dest() << ", " << instr.src1(); os << instr.action() << " " << instr.dest() << ", " << instr.src1();
if (instr.action() != Action::Set && instr.action() != Action::Not) { if (instr.action() != Action::Set && instr.action() != Action::Not) {
os << ", " << instr.src2(); os << ", " << instr.src2();
@@ -207,53 +227,55 @@ std::ostream &operator<<(std::ostream &os, Instruction const &instr) {
using ValueMap = std::map<Wire, Value>; ///< Map wires to values using ValueMap = std::map<Wire, Value>; ///< Map wires to values
using Instructions = std::vector<Instruction>; ///< Instructions to execute using Instructions = std::vector<Instruction>; ///< Instructions to execute
struct VM { struct VM
{
/// Add an instruction the the list we have /// Add an instruction the the list we have
void add_instr(Instruction const &instr) { instrs_.push_back(instr); } void add_instr(Instruction const& instr) { instrs_.push_back(instr); }
/// Has this wire a known value? /// Has this wire a known value?
bool has_value(Wire const &w) const noexcept { bool has_value(Wire const& w) const noexcept { return values_.find(w) != values_.end(); }
return values_.find(w) != values_.end();
}
/// Has this signal a known value? /// Has this signal a known value?
bool has_value(Signal const &s) const noexcept { bool has_value(Signal const& s) const noexcept
return std::visit(Overloaded{[](Value v) { return true; }, {
[&](Wire const &w) { return has_value(w); }}, return std::visit(
s); Overloaded{[](Value v) { return true; }, [&](Wire const& w) { return has_value(w); }}, s);
} }
/// Get the value on the wire /// Get the value on the wire
Value value(Wire const &w) const noexcept { Value value(Wire const& w) const noexcept
{
assert(has_value(w)); assert(has_value(w));
return values_.find(w)->second; return values_.find(w)->second;
} }
/// Get the value of a signal /// Get the value of a signal
Value value(Signal const &s) const noexcept { Value value(Signal const& s) const noexcept
return std::visit(Overloaded{[](Value v) { return v; }, {
[&](Wire const &w) { return value(w); }}, return std::visit(
s); Overloaded{[](Value v) { return v; }, [&](Wire const& w) { return value(w); }}, s);
} }
/// Set the value of a wire /// Set the value of a wire
void value(Wire const &w, Value value) { void value(Wire const& w, Value value)
{
auto [it, success] = values_.insert({w, value}); auto [it, success] = values_.insert({w, value});
assert(success); assert(success);
} }
/// Set the value of a signal /// Set the value of a signal
void value(Signal const &s, Value v) { void value(Signal const& s, Value v)
std::visit(Overloaded{[v](Value v2) { assert(v == v2); }, {
[&, v](Wire const &w) { value(w, v); }}, std::visit(
s); Overloaded{[v](Value v2) { assert(v == v2); }, [&, v](Wire const& w) { value(w, v); }}, s);
} }
/// Execute the instructions. Returns true if we have updated some wire /// Execute the instructions. Returns true if we have updated some wire
/// values. /// values.
bool execute() { bool execute()
{
bool done_anything = false; bool done_anything = false;
for (auto const &instr : instrs_) { for (auto const& instr : instrs_) {
done_anything |= execute_instr(instr); done_anything |= execute_instr(instr);
} }
@@ -268,15 +290,15 @@ private:
* An instruction may not be executed if the incoming signals have not been * An instruction may not be executed if the incoming signals have not been
* set yet. * set yet.
*/ */
bool execute_instr(Instruction const &instr) { bool execute_instr(Instruction const& instr)
{
std::cout << instr << " # "; std::cout << instr << " # ";
// First of all check there is something to do - i.e. that the destination // First of all check there is something to do - i.e. that the destination
// register has not been set already. // register has not been set already.
Wire dest = instr.dest(); Wire dest = instr.dest();
if (has_value(dest)) { if (has_value(dest)) {
std::cout << "already has value: " << dest << " = " << value(dest) std::cout << "already has value: " << dest << " = " << value(dest) << "\n";
<< "\n";
return false; return false;
} }
@@ -286,17 +308,13 @@ private:
case Action::Not: case Action::Not:
return execute_single_src(instr, [](Value src) { return ~src; }); return execute_single_src(instr, [](Value src) { return ~src; });
case Action::And: case Action::And:
return execute_double_src( return execute_double_src(instr, [](Value src1, Value src2) { return src1 & src2; });
instr, [](Value src1, Value src2) { return src1 & src2; });
case Action::Or: case Action::Or:
return execute_double_src( return execute_double_src(instr, [](Value src1, Value src2) { return src1 | src2; });
instr, [](Value src1, Value src2) { return src1 | src2; });
case Action::LShift: case Action::LShift:
return execute_double_src( return execute_double_src(instr, [](Value src1, Value src2) { return src1 << src2; });
instr, [](Value src1, Value src2) { return src1 << src2; });
case Action::RShift: case Action::RShift:
return execute_double_src( return execute_double_src(instr, [](Value src1, Value src2) { return src1 >> src2; });
instr, [](Value src1, Value src2) { return src1 >> src2; });
} }
return false; return false;
@@ -307,8 +325,8 @@ private:
* \param fn How to modify the source value to the dest. * \param fn How to modify the source value to the dest.
* \return True if we executed the function. * \return True if we executed the function.
*/ */
bool execute_single_src(Instruction const &instr, bool execute_single_src(Instruction const& instr, std::function<Value(Value)> fn)
std::function<Value(Value)> fn) { {
Wire dest = instr.dest(); Wire dest = instr.dest();
Signal src = instr.src1(); Signal src = instr.src1();
if (has_value(src)) { if (has_value(src)) {
@@ -326,8 +344,8 @@ private:
* \param fn How to modify the source values to the dest. * \param fn How to modify the source values to the dest.
* \return True if we executed the function. * \return True if we executed the function.
*/ */
bool execute_double_src(Instruction const &instr, bool execute_double_src(Instruction const& instr, std::function<Value(Value, Value)> fn)
std::function<Value(Value, Value)> fn) { {
Wire dest = instr.dest(); Wire dest = instr.dest();
Signal src1 = instr.src1(); Signal src1 = instr.src1();
Signal src2 = instr.src2(); Signal src2 = instr.src2();
@@ -345,7 +363,8 @@ private:
Instructions instrs_; Instructions instrs_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
VM vm; VM vm;
// Parse the input // Parse the input
@@ -365,7 +384,8 @@ int main(int argc, char **argv) {
std::cout << "a = "; std::cout << "a = ";
if (!vm.has_value(a)) { if (!vm.has_value(a)) {
std::cout << "UNSET\n"; std::cout << "UNSET\n";
} else { }
else {
std::cout << vm.value(a) << "\n"; std::cout << vm.value(a) << "\n";
} }

View File

@@ -8,7 +8,8 @@
enum class State { Begin, Normal, Escape, Hex1, Hex2, End }; enum class State { Begin, Normal, Escape, Hex1, Hex2, End };
std::string unescape(std::string const &s) { std::string unescape(std::string const& s)
{
std::string unescaped; std::string unescaped;
static const std::string hex = "0123456789abcdef0123456789ABCDEF"; static const std::string hex = "0123456789abcdef0123456789ABCDEF";
@@ -23,9 +24,11 @@ std::string unescape(std::string const &s) {
case State::Normal: case State::Normal:
if (c == '\\') { if (c == '\\') {
state = State::Escape; state = State::Escape;
} else if (c == '"') { }
else if (c == '"') {
state = State::End; state = State::End;
} else { }
else {
unescaped += c; unescaped += c;
} }
break; break;
@@ -33,10 +36,12 @@ std::string unescape(std::string const &s) {
if (c == '\\' || c == '"') { if (c == '\\' || c == '"') {
state = State::Normal; state = State::Normal;
unescaped += c; unescaped += c;
} else if (c == 'x') { }
else if (c == 'x') {
byte = 0; byte = 0;
state = State::Hex1; state = State::Hex1;
} else { }
else {
assert(false); assert(false);
} }
break; break;
@@ -62,16 +67,16 @@ std::string unescape(std::string const &s) {
return unescaped; return unescaped;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
unsigned len = 0; unsigned len = 0;
// Parse the input // Parse the input
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
std::string unescaped = unescape(line); std::string unescaped = unescape(line);
len += line.length() - unescaped.length(); len += line.length() - unescaped.length();
std::cout << line << ": " << line.length() << " written bytes, " std::cout << line << ": " << line.length() << " written bytes, " << unescaped.length()
<< unescaped.length() << " memory bytes, difference: " << " memory bytes, difference: " << line.length() - unescaped.length() << "\n";
<< line.length() - unescaped.length() << "\n";
} }
std::cout << len << "\n"; std::cout << len << "\n";

View File

@@ -6,7 +6,8 @@
#include <string> #include <string>
#include <variant> #include <variant>
std::string escape(std::string const &s) { std::string escape(std::string const& s)
{
std::string escaped; std::string escaped;
escaped += '"'; escaped += '"';
for (auto c : s) { for (auto c : s) {
@@ -19,16 +20,16 @@ std::string escape(std::string const &s) {
return escaped; return escaped;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
unsigned len = 0; unsigned len = 0;
// Parse the input // Parse the input
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
std::string escaped = escape(line); std::string escaped = escape(line);
len += escaped.length() - line.length(); len += escaped.length() - line.length();
std::cout << line << ": " << line.length() << " memory bytes, " std::cout << line << ": " << line.length() << " memory bytes, " << escaped.length()
<< escaped.length() << " escaped bytes, difference: " << " escaped bytes, difference: " << escaped.length() - line.length() << "\n";
<< escaped.length() - line.length() << "\n";
} }
std::cout << len << "\n"; std::cout << len << "\n";

View File

@@ -13,8 +13,10 @@ using Edge = std::pair<Node, Node>;
using Nodes = std::set<Node>; using Nodes = std::set<Node>;
using Edges = std::map<Edge, Weight>; using Edges = std::map<Edge, Weight>;
struct Graph { struct Graph
void add_edge(std::string const &s) { {
void add_edge(std::string const& s)
{
static const std::regex re("(.+) to (.+) = (\\d+)"); static const std::regex re("(.+) to (.+) = (\\d+)");
std::smatch m; std::smatch m;
if (!std::regex_search(s, m, re)) { if (!std::regex_search(s, m, re)) {
@@ -35,7 +37,8 @@ struct Graph {
std::cout << n1 << " <-> " << n2 << " weight: " << w << "\n"; std::cout << n1 << " <-> " << n2 << " weight: " << w << "\n";
} }
Weight solve_tsp() const { Weight solve_tsp() const
{
Weight min_weight = ~0U; Weight min_weight = ~0U;
std::vector<Node> nodes(nodes_.begin(), nodes_.end()); std::vector<Node> nodes(nodes_.begin(), nodes_.end());
std::sort(nodes.begin(), nodes.end()); std::sort(nodes.begin(), nodes.end());
@@ -64,7 +67,8 @@ struct Graph {
Edges weights_; Edges weights_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Graph g; Graph g;
// Parse the input // Parse the input

View File

@@ -13,8 +13,10 @@ using Edge = std::pair<Node, Node>;
using Nodes = std::set<Node>; using Nodes = std::set<Node>;
using Edges = std::map<Edge, Weight>; using Edges = std::map<Edge, Weight>;
struct Graph { struct Graph
void add_edge(std::string const &s) { {
void add_edge(std::string const& s)
{
static const std::regex re("(.+) to (.+) = (\\d+)"); static const std::regex re("(.+) to (.+) = (\\d+)");
std::smatch m; std::smatch m;
if (!std::regex_search(s, m, re)) { if (!std::regex_search(s, m, re)) {
@@ -35,7 +37,8 @@ struct Graph {
std::cout << n1 << " <-> " << n2 << " weight: " << w << "\n"; std::cout << n1 << " <-> " << n2 << " weight: " << w << "\n";
} }
Weight solve_tsp() const { Weight solve_tsp() const
{
Weight min_weight = ~0U; Weight min_weight = ~0U;
visit_all_perms([&min_weight](Weight w) { visit_all_perms([&min_weight](Weight w) {
if (w < min_weight) { if (w < min_weight) {
@@ -46,7 +49,8 @@ struct Graph {
return min_weight; return min_weight;
} }
Weight solve_max_tsp() const { Weight solve_max_tsp() const
{
Weight max_weight = 0; Weight max_weight = 0;
visit_all_perms([&max_weight](Weight w) { visit_all_perms([&max_weight](Weight w) {
if (w > max_weight) { if (w > max_weight) {
@@ -58,7 +62,9 @@ struct Graph {
} }
private: private:
template <typename Fn> void visit_all_perms(Fn fn) const { template<typename Fn>
void visit_all_perms(Fn fn) const
{
std::vector<Node> nodes(nodes_.begin(), nodes_.end()); std::vector<Node> nodes(nodes_.begin(), nodes_.end());
std::sort(nodes.begin(), nodes.end()); std::sort(nodes.begin(), nodes.end());
do { do {
@@ -80,7 +86,8 @@ private:
Edges weights_; Edges weights_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Graph g; Graph g;
// Parse the input // Parse the input

View File

@@ -7,7 +7,8 @@
#include <string> #include <string>
#include <variant> #include <variant>
std::string look_and_say(std::string const &s) { std::string look_and_say(std::string const& s)
{
std::string result; std::string result;
for (std::string::size_type i = 0; i < s.length();) { for (std::string::size_type i = 0; i < s.length();) {
unsigned num = 0; unsigned num = 0;
@@ -22,14 +23,13 @@ std::string look_and_say(std::string const &s) {
return result; return result;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
std::cout << "Application 0, length = " << line.length() << ": " << line std::cout << "Application 0, length = " << line.length() << ": " << line << "\n";
<< "\n";
for (int i = 1; i < 41; ++i) { for (int i = 1; i < 41; ++i) {
line = look_and_say(line); line = look_and_say(line);
std::cout << "Application " << i << ", length = " << line.length() std::cout << "Application " << i << ", length = " << line.length() << "\n";
<< "\n";
} }
std::cout << "Length: " << line.length() << "\n"; std::cout << "Length: " << line.length() << "\n";
} }

View File

@@ -7,7 +7,8 @@
#include <string> #include <string>
#include <variant> #include <variant>
std::string look_and_say(std::string const &s) { std::string look_and_say(std::string const& s)
{
std::string result; std::string result;
for (std::string::size_type i = 0; i < s.length();) { for (std::string::size_type i = 0; i < s.length();) {
unsigned num = 0; unsigned num = 0;
@@ -22,14 +23,13 @@ std::string look_and_say(std::string const &s) {
return result; return result;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
std::cout << "Application 0, length = " << line.length() << ": " << line std::cout << "Application 0, length = " << line.length() << ": " << line << "\n";
<< "\n";
for (int i = 1; i < 51; ++i) { for (int i = 1; i < 51; ++i) {
line = look_and_say(line); line = look_and_say(line);
std::cout << "Application " << i << ", length = " << line.length() std::cout << "Application " << i << ", length = " << line.length() << "\n";
<< "\n";
} }
std::cout << "Length: " << line.length() << "\n"; std::cout << "Length: " << line.length() << "\n";
} }

View File

@@ -9,7 +9,8 @@
bool illegal_char(char c) { return c == 'i' || c == 'l' || c == 'o'; } bool illegal_char(char c) { return c == 'i' || c == 'l' || c == 'o'; }
void pre_advance_password(std::string &s) { void pre_advance_password(std::string& s)
{
std::string::size_type pos = 0; std::string::size_type pos = 0;
while (pos < s.length() && !illegal_char(s[pos])) { while (pos < s.length() && !illegal_char(s[pos])) {
++pos; ++pos;
@@ -23,14 +24,16 @@ void pre_advance_password(std::string &s) {
} }
} }
void advance_password(std::string &s) { void advance_password(std::string& s)
{
auto pos = s.length() - 1; auto pos = s.length() - 1;
while (true) { while (true) {
if (s[pos] == 'z') { if (s[pos] == 'z') {
assert(pos != 0); assert(pos != 0);
s[pos] = 'a'; s[pos] = 'a';
pos -= 1; pos -= 1;
} else { }
else {
++s[pos]; ++s[pos];
if (illegal_char(s[pos])) { if (illegal_char(s[pos])) {
++s[pos]; ++s[pos];
@@ -40,7 +43,8 @@ void advance_password(std::string &s) {
} }
} }
bool valid_password(std::string const &s) { bool valid_password(std::string const& s)
{
unsigned double_count = 0; unsigned double_count = 0;
bool run = false; bool run = false;
char last2 = '\0'; char last2 = '\0';
@@ -48,7 +52,8 @@ bool valid_password(std::string const &s) {
for (auto c : s) { for (auto c : s) {
if (c == last && last2 != c) { if (c == last && last2 != c) {
++double_count; ++double_count;
} else if (c == last + 1 && c == last2 + 2) { }
else if (c == last + 1 && c == last2 + 2) {
run = true; run = true;
} }
last2 = last; last2 = last;
@@ -58,7 +63,8 @@ bool valid_password(std::string const &s) {
return double_count >= 2 && run; return double_count >= 2 && run;
} }
std::string next_password(std::string const &s) { std::string next_password(std::string const& s)
{
std::string result = s; std::string result = s;
pre_advance_password(result); pre_advance_password(result);
do { do {
@@ -67,11 +73,11 @@ std::string next_password(std::string const &s) {
return result; return result;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
std::string next = next_password(line); std::string next = next_password(line);
std::cout << "Current password: " << line << "; Next password: " << next std::cout << "Current password: " << line << "; Next password: " << next << "\n";
<< "\n";
} }
return 0; return 0;
} }

View File

@@ -9,7 +9,8 @@
bool illegal_char(char c) { return c == 'i' || c == 'l' || c == 'o'; } bool illegal_char(char c) { return c == 'i' || c == 'l' || c == 'o'; }
void pre_advance_password(std::string &s) { void pre_advance_password(std::string& s)
{
std::string::size_type pos = 0; std::string::size_type pos = 0;
while (pos < s.length() && !illegal_char(s[pos])) { while (pos < s.length() && !illegal_char(s[pos])) {
++pos; ++pos;
@@ -23,14 +24,16 @@ void pre_advance_password(std::string &s) {
} }
} }
void advance_password(std::string &s) { void advance_password(std::string& s)
{
auto pos = s.length() - 1; auto pos = s.length() - 1;
while (true) { while (true) {
if (s[pos] == 'z') { if (s[pos] == 'z') {
assert(pos != 0); assert(pos != 0);
s[pos] = 'a'; s[pos] = 'a';
pos -= 1; pos -= 1;
} else { }
else {
++s[pos]; ++s[pos];
if (illegal_char(s[pos])) { if (illegal_char(s[pos])) {
++s[pos]; ++s[pos];
@@ -40,7 +43,8 @@ void advance_password(std::string &s) {
} }
} }
bool valid_password(std::string const &s) { bool valid_password(std::string const& s)
{
unsigned double_count = 0; unsigned double_count = 0;
bool run = false; bool run = false;
char last2 = '\0'; char last2 = '\0';
@@ -48,7 +52,8 @@ bool valid_password(std::string const &s) {
for (auto c : s) { for (auto c : s) {
if (c == last && last2 != c) { if (c == last && last2 != c) {
++double_count; ++double_count;
} else if (c == last + 1 && c == last2 + 2) { }
else if (c == last + 1 && c == last2 + 2) {
run = true; run = true;
} }
last2 = last; last2 = last;
@@ -58,7 +63,8 @@ bool valid_password(std::string const &s) {
return double_count >= 2 && run; return double_count >= 2 && run;
} }
std::string next_password(std::string const &s) { std::string next_password(std::string const& s)
{
std::string result = s; std::string result = s;
pre_advance_password(result); pre_advance_password(result);
do { do {
@@ -67,7 +73,8 @@ std::string next_password(std::string const &s) {
return result; return result;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
std::string next = next_password(line); std::string next = next_password(line);
std::string next2 = next_password(next); std::string next2 = next_password(next);

View File

@@ -7,7 +7,8 @@
#include <string> #include <string>
#include <variant> #include <variant>
int parse_numbers(std::string const &s) { int parse_numbers(std::string const& s)
{
static const std::regex re("-?\\d+"); static const std::regex re("-?\\d+");
std::string left = s; std::string left = s;
std::smatch m; std::smatch m;
@@ -20,7 +21,8 @@ int parse_numbers(std::string const &s) {
return acc; return acc;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
int acc = 0; int acc = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
acc += parse_numbers(line); acc += parse_numbers(line);

View File

@@ -8,7 +8,8 @@
#include <string> #include <string>
#include <variant> #include <variant>
int do_parse(std::string const &s, std::string::size_type &pos) { int do_parse(std::string const& s, std::string::size_type& pos)
{
int result = 0; int result = 0;
bool ignore = false; bool ignore = false;
@@ -16,16 +17,20 @@ int do_parse(std::string const &s, std::string::size_type &pos) {
if (s[pos] == '{') { if (s[pos] == '{') {
++pos; ++pos;
result += do_parse(s, pos); result += do_parse(s, pos);
} else if (s[pos] == '[') { }
else if (s[pos] == '[') {
++pos; ++pos;
result += do_parse(s, pos); result += do_parse(s, pos);
} else if (s[pos] == '}') { }
else if (s[pos] == '}') {
++pos; ++pos;
return ignore ? 0 : result; return ignore ? 0 : result;
} else if (s[pos] == ']') { }
else if (s[pos] == ']') {
++pos; ++pos;
return result; return result;
} else if (s[pos] == '"') { }
else if (s[pos] == '"') {
++pos; ++pos;
auto e = s.find('"', pos); auto e = s.find('"', pos);
assert(e != std::string::npos); assert(e != std::string::npos);
@@ -34,11 +39,13 @@ int do_parse(std::string const &s, std::string::size_type &pos) {
ignore = true; ignore = true;
} }
pos = e + 1; pos = e + 1;
} else if (std::isdigit(s[pos]) || s[pos] == '-') { }
else if (std::isdigit(s[pos]) || s[pos] == '-') {
std::size_t len = 0; std::size_t len = 0;
result += std::stoi(s.substr(pos), &len); result += std::stoi(s.substr(pos), &len);
pos += len; pos += len;
} else { }
else {
assert(s[pos] == ',' || s[pos] == ':'); assert(s[pos] == ',' || s[pos] == ':');
++pos; ++pos;
} }
@@ -47,14 +54,16 @@ int do_parse(std::string const &s, std::string::size_type &pos) {
return result; return result;
} }
int parse_numbers(std::string const &s) { int parse_numbers(std::string const& s)
{
std::string::size_type pos = 0; std::string::size_type pos = 0;
int result = do_parse(s, pos); int result = do_parse(s, pos);
assert(pos == s.size()); assert(pos == s.size());
return result; return result;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
int acc = 0; int acc = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
acc += parse_numbers(line); acc += parse_numbers(line);

View File

@@ -9,7 +9,8 @@
#include <string> #include <string>
#include <variant> #include <variant>
struct Graph { struct Graph
{
using Node = std::string; using Node = std::string;
using Weight = int; using Weight = int;
using Nodes = std::set<Node>; using Nodes = std::set<Node>;
@@ -17,9 +18,9 @@ struct Graph {
using Edge = std::pair<Node, Node>; using Edge = std::pair<Node, Node>;
using EdgeWeights = std::map<Edge, Weight>; using EdgeWeights = std::map<Edge, Weight>;
void add_edge(std::string const &s) { void add_edge(std::string const& s)
static const std::regex re( {
"(\\w+) would (gain|lose) (\\d+) happiness units? " static const std::regex re("(\\w+) would (gain|lose) (\\d+) happiness units? "
"by sitting next to (\\w+)."); "by sitting next to (\\w+).");
std::smatch m; std::smatch m;
if (std::regex_search(s, m, re)) { if (std::regex_search(s, m, re)) {
@@ -30,18 +31,20 @@ struct Graph {
delta = -delta; delta = -delta;
} }
weights_.insert({{m.str(1), m.str(4)}, delta}); weights_.insert({{m.str(1), m.str(4)}, delta});
} else { }
else {
assert(false); assert(false);
} }
} }
Weight max_happiness() const { Weight max_happiness() const
{
int max_happiness = INT_MIN; int max_happiness = INT_MIN;
NodeList nl(nodes_.begin(), nodes_.end()); NodeList nl(nodes_.begin(), nodes_.end());
std::sort(nl.begin(), nl.end()); std::sort(nl.begin(), nl.end());
do { do {
std::cout << "\r"; std::cout << "\r";
for (auto const &s : nl) { for (auto const& s : nl) {
std::cout << s << " "; std::cout << s << " ";
} }
int h = happiness(nl); int h = happiness(nl);
@@ -56,7 +59,8 @@ struct Graph {
return max_happiness; return max_happiness;
} }
int happiness(NodeList const &nl) const { int happiness(NodeList const& nl) const
{
int h = 0; int h = 0;
h += weights_.find(std::make_pair(nl[nl.size() - 1], nl[0]))->second; h += weights_.find(std::make_pair(nl[nl.size() - 1], nl[0]))->second;
h += weights_.find(std::make_pair(nl[0], nl[nl.size() - 1]))->second; h += weights_.find(std::make_pair(nl[0], nl[nl.size() - 1]))->second;
@@ -71,7 +75,8 @@ struct Graph {
EdgeWeights weights_; EdgeWeights weights_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Graph g; Graph g;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
g.add_edge(line); g.add_edge(line);

View File

@@ -9,7 +9,8 @@
#include <string> #include <string>
#include <variant> #include <variant>
struct Graph { struct Graph
{
Graph() { nodes_.insert("self"); } Graph() { nodes_.insert("self"); }
using Node = std::string; using Node = std::string;
using Weight = int; using Weight = int;
@@ -18,9 +19,9 @@ struct Graph {
using Edge = std::pair<Node, Node>; using Edge = std::pair<Node, Node>;
using EdgeWeights = std::map<Edge, Weight>; using EdgeWeights = std::map<Edge, Weight>;
void add_edge(std::string const &s) { void add_edge(std::string const& s)
static const std::regex re( {
"(\\w+) would (gain|lose) (\\d+) happiness units? " static const std::regex re("(\\w+) would (gain|lose) (\\d+) happiness units? "
"by sitting next to (\\w+)."); "by sitting next to (\\w+).");
std::smatch m; std::smatch m;
if (std::regex_search(s, m, re)) { if (std::regex_search(s, m, re)) {
@@ -33,18 +34,20 @@ struct Graph {
delta = -delta; delta = -delta;
} }
weights_.insert({{m.str(1), m.str(4)}, delta}); weights_.insert({{m.str(1), m.str(4)}, delta});
} else { }
else {
assert(false); assert(false);
} }
} }
Weight max_happiness() const { Weight max_happiness() const
{
int max_happiness = INT_MIN; int max_happiness = INT_MIN;
NodeList nl(nodes_.begin(), nodes_.end()); NodeList nl(nodes_.begin(), nodes_.end());
std::sort(nl.begin(), nl.end()); std::sort(nl.begin(), nl.end());
do { do {
std::cout << "\r"; std::cout << "\r";
for (auto const &s : nl) { for (auto const& s : nl) {
std::cout << s << " "; std::cout << s << " ";
} }
int h = happiness(nl); int h = happiness(nl);
@@ -59,7 +62,8 @@ struct Graph {
return max_happiness; return max_happiness;
} }
int happiness(NodeList const &nl) const { int happiness(NodeList const& nl) const
{
int h = 0; int h = 0;
h += weights_.find(std::make_pair(nl[nl.size() - 1], nl[0]))->second; h += weights_.find(std::make_pair(nl[nl.size() - 1], nl[0]))->second;
h += weights_.find(std::make_pair(nl[0], nl[nl.size() - 1]))->second; h += weights_.find(std::make_pair(nl[0], nl[nl.size() - 1]))->second;
@@ -74,7 +78,8 @@ struct Graph {
EdgeWeights weights_; EdgeWeights weights_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Graph g; Graph g;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
g.add_edge(line); g.add_edge(line);

View File

@@ -11,7 +11,8 @@
using Distance = unsigned long; using Distance = unsigned long;
Distance distance(std::string const &s, unsigned t) { Distance distance(std::string const& s, unsigned t)
{
static const std::regex re("(\\w+) can fly (\\d+) km/s for (\\d+) seconds?, " static const std::regex re("(\\w+) can fly (\\d+) km/s for (\\d+) seconds?, "
"but then must rest for (\\d+) seconds?."); "but then must rest for (\\d+) seconds?.");
std::smatch m; std::smatch m;
@@ -32,15 +33,17 @@ Distance distance(std::string const &s, unsigned t) {
t = std::min(t, fly_time); t = std::min(t, fly_time);
result += t * fly_speed; result += t * fly_speed;
std::cout << m.str(1) << "(" << fly_speed << ", " << fly_time << ", " std::cout << m.str(1) << "(" << fly_speed << ", " << fly_time << ", " << rest_time
<< rest_time << ") = " << result << "\n"; << ") = " << result << "\n";
return result; return result;
} else { }
else {
assert(false); assert(false);
} }
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Distance max_d = 0; Distance max_d = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
max_d = std::max(max_d, distance(line, 2503)); max_d = std::max(max_d, distance(line, 2503));

View File

@@ -16,10 +16,11 @@ using Speed = unsigned long;
struct Reindeer; struct Reindeer;
using ReindeerSet = std::set<Reindeer>; using ReindeerSet = std::set<Reindeer>;
struct Reindeer { struct Reindeer
Reindeer(std::string const &s) { {
static const std::regex re( Reindeer(std::string const& s)
"(\\w+) can fly (\\d+) km/s for (\\d+) seconds?, " {
static const std::regex re("(\\w+) can fly (\\d+) km/s for (\\d+) seconds?, "
"but then must rest for (\\d+) seconds?."); "but then must rest for (\\d+) seconds?.");
std::smatch m; std::smatch m;
if (std::regex_search(s, m, re)) { if (std::regex_search(s, m, re)) {
@@ -27,18 +28,18 @@ struct Reindeer {
speed_ = std::stoul(m.str(2)); speed_ = std::stoul(m.str(2));
fly_time_ = std::stoul(m.str(3)); fly_time_ = std::stoul(m.str(3));
rest_time_ = std::stoul(m.str(4)); rest_time_ = std::stoul(m.str(4));
} else { }
else {
assert(false); assert(false);
} }
} }
bool operator<(Reindeer const &rhs) const noexcept { bool operator<(Reindeer const& rhs) const noexcept { return name_ < rhs.name_; }
return name_ < rhs.name_;
}
std::string const &name() const { return name_; } std::string const& name() const { return name_; }
Distance distance(Time t) const { // Period and number of them Distance distance(Time t) const
{ // Period and number of them
Time period = fly_time_ + rest_time_; Time period = fly_time_ + rest_time_;
unsigned periods = t / period; unsigned periods = t / period;
@@ -59,7 +60,8 @@ struct Reindeer {
Time rest_time_; Time rest_time_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
ReindeerSet reindeer; ReindeerSet reindeer;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
@@ -68,9 +70,8 @@ int main(int argc, char **argv) {
std::map<std::string, unsigned> score; std::map<std::string, unsigned> score;
for (unsigned t = 1; t < 2504; ++t) { for (unsigned t = 1; t < 2504; ++t) {
auto it = auto it = std::max_element(reindeer.begin(), reindeer.end(),
std::max_element(reindeer.begin(), reindeer.end(), [t](Reindeer const& lhs, Reindeer const& rhs) -> bool {
[t](Reindeer const &lhs, Reindeer const &rhs) -> bool {
return lhs.distance(t) < rhs.distance(t); return lhs.distance(t) < rhs.distance(t);
}); });
auto [iit, success] = score.insert({it->name(), 1}); auto [iit, success] = score.insert({it->name(), 1});
@@ -79,8 +80,8 @@ int main(int argc, char **argv) {
} }
} }
auto it = std::max_element(score.begin(), score.end(), auto it =
[](auto const &lhs, auto const &rhs) -> bool { std::max_element(score.begin(), score.end(), [](auto const& lhs, auto const& rhs) -> bool {
return lhs.second < rhs.second; return lhs.second < rhs.second;
}); });
std::cout << it->first << " wins with a score of " << it->second << "\n"; std::cout << it->first << " wins with a score of " << it->second << "\n";

View File

@@ -12,8 +12,10 @@
using Score = long; using Score = long;
using PropertyMap = std::map<std::string, Score>; using PropertyMap = std::map<std::string, Score>;
struct Ingredient { struct Ingredient
explicit Ingredient(std::string const &s) { {
explicit Ingredient(std::string const& s)
{
auto colon = s.find(':'); auto colon = s.find(':');
name_ = s.substr(0, colon); name_ = s.substr(0, colon);
auto suffix = s.substr(colon + 1); auto suffix = s.substr(colon + 1);
@@ -22,25 +24,24 @@ struct Ingredient {
static const std::regex re(",? (\\w+) (-?\\d+)"); static const std::regex re(",? (\\w+) (-?\\d+)");
std::smatch m; std::smatch m;
if (std::regex_search(suffix, m, re)) { if (std::regex_search(suffix, m, re)) {
auto [it, success] = auto [it, success] = properties_.insert({m.str(1), std::stol(m.str(2))});
properties_.insert({m.str(1), std::stol(m.str(2))});
assert(success); assert(success);
std::cout << " " << it->first << ": " << it->second << "\n"; std::cout << " " << it->first << ": " << it->second << "\n";
suffix = m.suffix(); suffix = m.suffix();
} else { }
else {
assert(false); assert(false);
} }
} }
} }
bool operator<(Ingredient const &rhs) const noexcept { bool operator<(Ingredient const& rhs) const noexcept { return name_ < rhs.name_; }
return name_ < rhs.name_;
}
std::string const &name() const noexcept { return name_; } std::string const& name() const noexcept { return name_; }
void update_score(Score amount, PropertyMap &totals) const { void update_score(Score amount, PropertyMap& totals) const
for (auto const &kv : properties_) { {
for (auto const& kv : properties_) {
if (kv.first == "calories") { if (kv.first == "calories") {
continue; continue;
} }
@@ -56,20 +57,20 @@ private:
PropertyMap properties_; PropertyMap properties_;
}; };
struct Ingredients { struct Ingredients
void add_ingredient(std::string const &s) { {
ingredients_.push_back(Ingredient(s)); void add_ingredient(std::string const& s) { ingredients_.push_back(Ingredient(s)); }
}
Score best_combination(Score amount) const { Score best_combination(Score amount) const
{
PropertyMap totals; PropertyMap totals;
return best_combination(amount, ingredients_.begin(), 0UL, totals); return best_combination(amount, ingredients_.begin(), 0UL, totals);
} }
private: private:
Score best_combination(Score amount, Score best_combination(Score amount, std::vector<Ingredient>::const_iterator it, Score best_score,
std::vector<Ingredient>::const_iterator it, PropertyMap& totals) const
Score best_score, PropertyMap &totals) const { {
it->update_score(amount, totals); it->update_score(amount, totals);
auto it2 = it; auto it2 = it;
++it2; ++it2;
@@ -83,17 +84,17 @@ private:
for (auto allocation = amount - 1; allocation > 0; --allocation) { for (auto allocation = amount - 1; allocation > 0; --allocation) {
it->update_score(-1, totals); it->update_score(-1, totals);
best_score = best_score =
std::max(best_score, best_combination(amount - allocation, it2, std::max(best_score, best_combination(amount - allocation, it2, best_score, totals));
best_score, totals));
} }
it->update_score(-1, totals); it->update_score(-1, totals);
return best_score; return best_score;
} }
Score calculate_score(PropertyMap const &totals) const { Score calculate_score(PropertyMap const& totals) const
{
Score r = 1; Score r = 1;
for (auto const &kv : totals) { for (auto const& kv : totals) {
if (kv.first == "calories") { if (kv.first == "calories") {
continue; continue;
} }
@@ -109,7 +110,8 @@ private:
std::vector<Ingredient> ingredients_; std::vector<Ingredient> ingredients_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Ingredients ingredients; Ingredients ingredients;
std::string line; std::string line;

View File

@@ -12,8 +12,10 @@
using Score = long; using Score = long;
using PropertyMap = std::map<std::string, Score>; using PropertyMap = std::map<std::string, Score>;
struct Ingredient { struct Ingredient
explicit Ingredient(std::string const &s) { {
explicit Ingredient(std::string const& s)
{
auto colon = s.find(':'); auto colon = s.find(':');
name_ = s.substr(0, colon); name_ = s.substr(0, colon);
auto suffix = s.substr(colon + 1); auto suffix = s.substr(colon + 1);
@@ -22,25 +24,24 @@ struct Ingredient {
static const std::regex re(",? (\\w+) (-?\\d+)"); static const std::regex re(",? (\\w+) (-?\\d+)");
std::smatch m; std::smatch m;
if (std::regex_search(suffix, m, re)) { if (std::regex_search(suffix, m, re)) {
auto [it, success] = auto [it, success] = properties_.insert({m.str(1), std::stol(m.str(2))});
properties_.insert({m.str(1), std::stol(m.str(2))});
assert(success); assert(success);
std::cout << " " << it->first << ": " << it->second << "\n"; std::cout << " " << it->first << ": " << it->second << "\n";
suffix = m.suffix(); suffix = m.suffix();
} else { }
else {
assert(false); assert(false);
} }
} }
} }
bool operator<(Ingredient const &rhs) const noexcept { bool operator<(Ingredient const& rhs) const noexcept { return name_ < rhs.name_; }
return name_ < rhs.name_;
}
std::string const &name() const noexcept { return name_; } std::string const& name() const noexcept { return name_; }
void update_score(Score amount, PropertyMap &totals) const { void update_score(Score amount, PropertyMap& totals) const
for (auto const &kv : properties_) { {
for (auto const& kv : properties_) {
auto [it, success] = totals.insert({kv.first, amount * kv.second}); auto [it, success] = totals.insert({kv.first, amount * kv.second});
if (!success) { if (!success) {
it->second += amount * kv.second; it->second += amount * kv.second;
@@ -53,20 +54,20 @@ private:
PropertyMap properties_; PropertyMap properties_;
}; };
struct Ingredients { struct Ingredients
void add_ingredient(std::string const &s) { {
ingredients_.push_back(Ingredient(s)); void add_ingredient(std::string const& s) { ingredients_.push_back(Ingredient(s)); }
}
Score best_combination(Score amount) const { Score best_combination(Score amount) const
{
PropertyMap totals; PropertyMap totals;
return best_combination(amount, ingredients_.begin(), 0UL, totals); return best_combination(amount, ingredients_.begin(), 0UL, totals);
} }
private: private:
Score best_combination(Score amount, Score best_combination(Score amount, std::vector<Ingredient>::const_iterator it, Score best_score,
std::vector<Ingredient>::const_iterator it, PropertyMap& totals) const
Score best_score, PropertyMap &totals) const { {
it->update_score(amount, totals); it->update_score(amount, totals);
auto it2 = it; auto it2 = it;
++it2; ++it2;
@@ -80,18 +81,18 @@ private:
for (auto allocation = amount - 1; allocation > 0; --allocation) { for (auto allocation = amount - 1; allocation > 0; --allocation) {
it->update_score(-1, totals); it->update_score(-1, totals);
best_score = best_score =
std::max(best_score, best_combination(amount - allocation, it2, std::max(best_score, best_combination(amount - allocation, it2, best_score, totals));
best_score, totals));
} }
it->update_score(-1, totals); it->update_score(-1, totals);
return best_score; return best_score;
} }
Score calculate_score(PropertyMap const &totals) const { Score calculate_score(PropertyMap const& totals) const
{
Score r = 1; Score r = 1;
Score calories = 0; Score calories = 0;
for (auto const &kv : totals) { for (auto const& kv : totals) {
if (kv.first == "calories") { if (kv.first == "calories") {
calories += kv.second; calories += kv.second;
continue; continue;
@@ -110,7 +111,8 @@ private:
std::vector<Ingredient> ingredients_; std::vector<Ingredient> ingredients_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Ingredients ingredients; Ingredients ingredients;
std::string line; std::string line;

View File

@@ -22,7 +22,8 @@ static const InfoMap the_real_aunt_sue({{"children", 3},
{"cars", 2}, {"cars", 2},
{"perfumes", 1}}); {"perfumes", 1}});
bool matches_sue(std::string const &s) { bool matches_sue(std::string const& s)
{
assert(s.substr(0, 4) == "Sue "); assert(s.substr(0, 4) == "Sue ");
std::size_t pos = 4; std::size_t pos = 4;
std::size_t len = 0; std::size_t len = 0;
@@ -34,7 +35,8 @@ bool matches_sue(std::string const &s) {
while (pos < s.size()) { while (pos < s.size()) {
if (s[pos] == ' ' || s[pos] == ',') { if (s[pos] == ' ' || s[pos] == ',') {
++pos; ++pos;
} else { }
else {
auto colon = s.find(':', pos); auto colon = s.find(':', pos);
assert(colon != std::string::npos); assert(colon != std::string::npos);
std::string name = s.substr(pos, colon - pos); std::string name = s.substr(pos, colon - pos);
@@ -57,7 +59,8 @@ bool matches_sue(std::string const &s) {
return true; return true;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
if (matches_sue(line)) { if (matches_sue(line)) {

View File

@@ -28,7 +28,8 @@ static const InfoMap the_real_aunt_sue({{"children", {3, Equality}},
{"cars", {2, Equality}}, {"cars", {2, Equality}},
{"perfumes", {1, Equality}}}); {"perfumes", {1, Equality}}});
bool matches_sue(std::string const &s) { bool matches_sue(std::string const& s)
{
assert(s.substr(0, 4) == "Sue "); assert(s.substr(0, 4) == "Sue ");
std::size_t pos = 4; std::size_t pos = 4;
std::size_t len = 0; std::size_t len = 0;
@@ -40,7 +41,8 @@ bool matches_sue(std::string const &s) {
while (pos < s.size()) { while (pos < s.size()) {
if (s[pos] == ' ' || s[pos] == ',') { if (s[pos] == ' ' || s[pos] == ',') {
++pos; ++pos;
} else { }
else {
auto colon = s.find(':', pos); auto colon = s.find(':', pos);
assert(colon != std::string::npos); assert(colon != std::string::npos);
std::string name = s.substr(pos, colon - pos); std::string name = s.substr(pos, colon - pos);
@@ -63,7 +65,8 @@ bool matches_sue(std::string const &s) {
return true; return true;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
if (matches_sue(line)) { if (matches_sue(line)) {

View File

@@ -14,9 +14,9 @@ constexpr Quantity total = 150;
using Quantities = std::vector<Quantity>; using Quantities = std::vector<Quantity>;
unsigned count_combinations(Quantities::const_iterator it, unsigned count_combinations(Quantities::const_iterator it, Quantities::const_iterator end,
Quantities::const_iterator end, Quantity amount, Quantity amount, unsigned depth = 0)
unsigned depth = 0) { {
// We have no room for this container // We have no room for this container
std::cout << std::string(depth, ' ') << *it << ": " << amount << "\n"; std::cout << std::string(depth, ' ') << *it << ": " << amount << "\n";
if (amount < *it) { if (amount < *it) {
@@ -36,7 +36,8 @@ unsigned count_combinations(Quantities::const_iterator it,
return result; return result;
} }
unsigned count_combinations(Quantities const &containers) { unsigned count_combinations(Quantities const& containers)
{
unsigned result = 0; unsigned result = 0;
for (auto it = containers.begin(); it != containers.end(); ++it) { for (auto it = containers.begin(); it != containers.end(); ++it) {
result += count_combinations(it, containers.end(), total); result += count_combinations(it, containers.end(), total);
@@ -44,7 +45,8 @@ unsigned count_combinations(Quantities const &containers) {
return result; return result;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
Quantities containers; Quantities containers;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -14,11 +14,11 @@ constexpr Quantity total = 150;
using Quantities = std::vector<Quantity>; using Quantities = std::vector<Quantity>;
template <typename Fn1, typename Fn2> template<typename Fn1, typename Fn2>
unsigned count_combinations(Quantities::const_iterator it, unsigned count_combinations(Quantities::const_iterator it, Quantities::const_iterator end,
Quantities::const_iterator end, Quantity amount, Quantity amount, unsigned depth, Fn1 base_result, unsigned init_addend,
unsigned depth, Fn1 base_result, Fn2 adder)
unsigned init_addend, Fn2 adder) { {
// We have no room for this container // We have no room for this container
std::cout << std::string(depth, ' ') << *it << ": " << amount; std::cout << std::string(depth, ' ') << *it << ": " << amount;
if (amount < *it) { if (amount < *it) {
@@ -36,45 +36,42 @@ unsigned count_combinations(Quantities::const_iterator it,
amount -= *it; amount -= *it;
auto result = init_addend; auto result = init_addend;
while (++it != end) { while (++it != end) {
auto child_score = count_combinations(it, end, amount, depth + 1, auto child_score =
base_result, init_addend, adder); count_combinations(it, end, amount, depth + 1, base_result, init_addend, adder);
result = adder(result, child_score); result = adder(result, child_score);
} }
std::cout << std::string(depth, ' ') << "Recursion result: " << result std::cout << std::string(depth, ' ') << "Recursion result: " << result << "\n";
<< "\n";
return result; return result;
} }
template <typename Fn1, typename Fn2> template<typename Fn1, typename Fn2>
unsigned count_combinations(Quantities const &containers, Quantity amount, unsigned count_combinations(Quantities const& containers, Quantity amount, Fn1 base_result,
Fn1 base_result, unsigned init_addend, Fn2 adder) { unsigned init_addend, Fn2 adder)
{
unsigned result = init_addend; unsigned result = init_addend;
for (auto it = containers.begin(); it != containers.end(); ++it) { for (auto it = containers.begin(); it != containers.end(); ++it) {
result = adder(result, count_combinations(it, containers.end(), total, 0, result = adder(
base_result, init_addend, adder)); result, count_combinations(it, containers.end(), total, 0, base_result, init_addend, adder));
} }
return result; return result;
} }
unsigned find_shortest_combination(Quantities const &containers) { unsigned find_shortest_combination(Quantities const& containers)
{
return count_combinations( return count_combinations(
containers, total, [](unsigned depth) { return depth; }, UINT_MAX, containers, total, [](unsigned depth) { return depth; }, UINT_MAX,
[](unsigned current, unsigned child_score) { [](unsigned current, unsigned child_score) { return std::min(current, child_score); });
return std::min(current, child_score);
});
} }
unsigned count_min_length_combinations(Quantities const &containers, unsigned count_min_length_combinations(Quantities const& containers, unsigned expected_depth)
unsigned expected_depth) { {
return count_combinations( return count_combinations(
containers, total, containers, total, [expected_depth](unsigned depth) { return depth == expected_depth; }, 0,
[expected_depth](unsigned depth) { return depth == expected_depth; }, 0, [](unsigned current, unsigned child_score) { return current + child_score; });
[](unsigned current, unsigned child_score) {
return current + child_score;
});
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
Quantities containers; Quantities containers;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -10,9 +10,10 @@
#include <string> #include <string>
#include <variant> #include <variant>
struct ConwayState { struct ConwayState
ConwayState(std::size_t width, std::string const &s) {
: width_(width), state_(width_ * width_, 0) { ConwayState(std::size_t width, std::string const& s) : width_(width), state_(width_ * width_, 0)
{
assert(s.size() == width_ * width_); assert(s.size() == width_ * width_);
for (std::size_t i = 0; i < state_.size(); ++i) { for (std::size_t i = 0; i < state_.size(); ++i) {
@@ -22,7 +23,8 @@ struct ConwayState {
} }
} }
ConwayState next_state() const { ConwayState next_state() const
{
ConwayState next(*this); ConwayState next(*this);
for (std::size_t i = 0; i < state_.size(); ++i) { for (std::size_t i = 0; i < state_.size(); ++i) {
if (state_[i] == (2 | active_) || state_[i] == (3 | active_)) { if (state_[i] == (2 | active_) || state_[i] == (3 | active_)) {
@@ -36,23 +38,22 @@ struct ConwayState {
return next; return next;
} }
std::size_t num_active() const { std::size_t num_active() const
return std::accumulate(state_.begin(), state_.end(), std::size_t(0), {
[](std::size_t current, unsigned char info) { return std::accumulate(
return current + ((info & active_) != 0); state_.begin(), state_.end(), std::size_t(0),
}); [](std::size_t current, unsigned char info) { return current + ((info & active_) != 0); });
} }
private: private:
void flip(std::size_t idx) { void flip(std::size_t idx)
{
state_[idx] = state_[idx] ^ active_; state_[idx] = state_[idx] ^ active_;
int delta = ((state_[idx] & active_) == active_) ? 1 : -1; int delta = ((state_[idx] & active_) == active_) ? 1 : -1;
std::size_t row = idx / width_; std::size_t row = idx / width_;
std::size_t col = idx % width_; std::size_t col = idx % width_;
for (std::size_t r = std::max(std::size_t(1), row) - 1; for (std::size_t r = std::max(std::size_t(1), row) - 1; r < std::min(width_, row + 2); ++r) {
r < std::min(width_, row + 2); ++r) { for (std::size_t c = std::max(std::size_t(1), col) - 1; c < std::min(width_, col + 2); ++c) {
for (std::size_t c = std::max(std::size_t(1), col) - 1;
c < std::min(width_, col + 2); ++c) {
if (r == row && c == col) { if (r == row && c == col) {
continue; continue;
} }
@@ -65,10 +66,11 @@ private:
std::vector<unsigned char> state_; std::vector<unsigned char> state_;
static constexpr unsigned char active_ = 0x80; static constexpr unsigned char active_ = 0x80;
friend std::ostream &operator<<(std::ostream &os, ConwayState const &state); friend std::ostream& operator<<(std::ostream& os, ConwayState const& state);
}; };
std::ostream &operator<<(std::ostream &os, ConwayState const &state) { std::ostream& operator<<(std::ostream& os, ConwayState const& state)
{
std::size_t c = 0; std::size_t c = 0;
for (auto s : state.state_) { for (auto s : state.state_) {
os << (s & ConwayState::active_ ? '#' : '.'); os << (s & ConwayState::active_ ? '#' : '.');
@@ -82,7 +84,8 @@ std::ostream &operator<<(std::ostream &os, ConwayState const &state) {
return os; return os;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
std::size_t width = 0; std::size_t width = 0;
std::string init; std::string init;

View File

@@ -10,9 +10,10 @@
#include <string> #include <string>
#include <variant> #include <variant>
struct ConwayState { struct ConwayState
ConwayState(std::size_t width, std::string const &s) {
: width_(width), state_(width_ * width_, 0) { ConwayState(std::size_t width, std::string const& s) : width_(width), state_(width_ * width_, 0)
{
assert(s.size() == width_ * width_); assert(s.size() == width_ * width_);
flip(0); flip(0);
@@ -27,11 +28,11 @@ struct ConwayState {
} }
} }
ConwayState next_state() const { ConwayState next_state() const
{
ConwayState next(*this); ConwayState next(*this);
for (std::size_t i = 0; i < state_.size(); ++i) { for (std::size_t i = 0; i < state_.size(); ++i) {
if (i == 0 || i == width_ - 1 || i == width_ * (width_ - 1) || if (i == 0 || i == width_ - 1 || i == width_ * (width_ - 1) || i == width_ * width_ - 1) {
i == width_ * width_ - 1) {
continue; continue;
} }
if (state_[i] == (2 | active_) || state_[i] == (3 | active_)) { if (state_[i] == (2 | active_) || state_[i] == (3 | active_)) {
@@ -45,23 +46,22 @@ struct ConwayState {
return next; return next;
} }
std::size_t num_active() const { std::size_t num_active() const
return std::accumulate(state_.begin(), state_.end(), std::size_t(0), {
[](std::size_t current, unsigned char info) { return std::accumulate(
return current + ((info & active_) != 0); state_.begin(), state_.end(), std::size_t(0),
}); [](std::size_t current, unsigned char info) { return current + ((info & active_) != 0); });
} }
private: private:
void flip(std::size_t idx) { void flip(std::size_t idx)
{
state_[idx] = state_[idx] ^ active_; state_[idx] = state_[idx] ^ active_;
int delta = ((state_[idx] & active_) == active_) ? 1 : -1; int delta = ((state_[idx] & active_) == active_) ? 1 : -1;
std::size_t row = idx / width_; std::size_t row = idx / width_;
std::size_t col = idx % width_; std::size_t col = idx % width_;
for (std::size_t r = std::max(std::size_t(1), row) - 1; for (std::size_t r = std::max(std::size_t(1), row) - 1; r < std::min(width_, row + 2); ++r) {
r < std::min(width_, row + 2); ++r) { for (std::size_t c = std::max(std::size_t(1), col) - 1; c < std::min(width_, col + 2); ++c) {
for (std::size_t c = std::max(std::size_t(1), col) - 1;
c < std::min(width_, col + 2); ++c) {
if (r == row && c == col) { if (r == row && c == col) {
continue; continue;
} }
@@ -74,10 +74,11 @@ private:
std::vector<unsigned char> state_; std::vector<unsigned char> state_;
static constexpr unsigned char active_ = 0x80; static constexpr unsigned char active_ = 0x80;
friend std::ostream &operator<<(std::ostream &os, ConwayState const &state); friend std::ostream& operator<<(std::ostream& os, ConwayState const& state);
}; };
std::ostream &operator<<(std::ostream &os, ConwayState const &state) { std::ostream& operator<<(std::ostream& os, ConwayState const& state)
{
std::size_t c = 0; std::size_t c = 0;
for (auto s : state.state_) { for (auto s : state.state_) {
os << (s & ConwayState::active_ ? '#' : '.'); os << (s & ConwayState::active_ ? '#' : '.');
@@ -91,7 +92,8 @@ std::ostream &operator<<(std::ostream &os, ConwayState const &state) {
return os; return os;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
std::size_t width = 0; std::size_t width = 0;
std::string init; std::string init;

View File

@@ -10,30 +10,31 @@
#include <string> #include <string>
#include <variant> #include <variant>
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::multimap<std::string, std::string> replacements; std::multimap<std::string, std::string> replacements;
bool collecting_replacements = true; bool collecting_replacements = true;
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
if (line.empty()) { if (line.empty()) {
collecting_replacements = false; collecting_replacements = false;
} else if (collecting_replacements) { }
else if (collecting_replacements) {
auto sep = line.find(" => "); auto sep = line.find(" => ");
replacements.insert({line.substr(0, sep), line.substr(sep + 4)}); replacements.insert({line.substr(0, sep), line.substr(sep + 4)});
} else { }
else {
std::set<std::string> new_molecules; std::set<std::string> new_molecules;
for (unsigned pos = 0; pos < line.size(); ++pos) { for (unsigned pos = 0; pos < line.size(); ++pos) {
auto [it, ite] = replacements.equal_range(line.substr(pos, 1)); auto [it, ite] = replacements.equal_range(line.substr(pos, 1));
while (it != ite) { while (it != ite) {
new_molecules.insert(line.substr(0, pos) + it->second + new_molecules.insert(line.substr(0, pos) + it->second + line.substr(pos + 1));
line.substr(pos + 1));
++it; ++it;
} }
if (pos < line.size() - 1) { if (pos < line.size() - 1) {
auto [it, ite] = replacements.equal_range(line.substr(pos, 2)); auto [it, ite] = replacements.equal_range(line.substr(pos, 2));
while (it != ite) { while (it != ite) {
new_molecules.insert(line.substr(0, pos) + it->second + new_molecules.insert(line.substr(0, pos) + it->second + line.substr(pos + 2));
line.substr(pos + 2));
++it; ++it;
} }
} }

View File

@@ -13,10 +13,11 @@
#include <unordered_set> #include <unordered_set>
#include <variant> #include <variant>
template <typename Map> template<typename Map>
std::size_t dedup(Map const &replacements, std::string &molecule) { std::size_t dedup(Map const& replacements, std::string& molecule)
{
std::size_t steps = 0; std::size_t steps = 0;
for (auto const &kv : replacements) { for (auto const& kv : replacements) {
if (kv.first != kv.second + kv.second) { if (kv.first != kv.second + kv.second) {
continue; continue;
} }
@@ -24,8 +25,7 @@ std::size_t dedup(Map const &replacements, std::string &molecule) {
do { do {
pos = molecule.find(kv.first); pos = molecule.find(kv.first);
if (pos != std::string::npos) { if (pos != std::string::npos) {
molecule = molecule.substr(0, pos) + kv.second + molecule = molecule.substr(0, pos) + kv.second + molecule.substr(pos + kv.first.size());
molecule.substr(pos + kv.first.size());
++steps; ++steps;
} }
} while (pos != std::string::npos); } while (pos != std::string::npos);
@@ -143,21 +143,22 @@ find_molecule(std::unordered_map<std::string, std::string> const &replacements,
} }
#endif #endif
template <typename Map> template<typename Map>
bool is_good_replacement(Map const &replacements, std::string const &nm, bool is_good_replacement(Map const& replacements, std::string const& nm, std::size_t pos,
std::size_t pos, std::size_t replace_len) { std::size_t replace_len)
for (auto const &kv : replacements) { {
for (auto const& kv : replacements) {
auto left = std::max(kv.first.size(), pos) - kv.first.size(); auto left = std::max(kv.first.size(), pos) - kv.first.size();
if (nm.substr(left, kv.first.size() * 2 + replace_len).find(kv.first) != if (nm.substr(left, kv.first.size() * 2 + replace_len).find(kv.first) != std::string::npos) {
std::string::npos) {
return true; return true;
} }
} }
return false; return false;
} }
template <typename Map> template<typename Map>
std::size_t find_molecule(Map &replacements, std::string const &molecule) { std::size_t find_molecule(Map& replacements, std::string const& molecule)
{
std::random_device rd; std::random_device rd;
std::mt19937 g(rd()); std::mt19937 g(rd());
while (true) { while (true) {
@@ -167,7 +168,7 @@ std::size_t find_molecule(Map &replacements, std::string const &molecule) {
std::size_t steps = 0; std::size_t steps = 0;
do { do {
changed = false; changed = false;
for (auto const &kv : replacements) { for (auto const& kv : replacements) {
auto pos = m.find(kv.first); auto pos = m.find(kv.first);
if (pos != std::string::npos) { if (pos != std::string::npos) {
m = m.substr(0, pos) + kv.second + m.substr(pos + kv.first.length()); m = m.substr(0, pos) + kv.second + m.substr(pos + kv.first.length());
@@ -185,17 +186,20 @@ std::size_t find_molecule(Map &replacements, std::string const &molecule) {
} }
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::vector<std::pair<std::string, std::string>> replacements; std::vector<std::pair<std::string, std::string>> replacements;
bool collecting_replacements = true; bool collecting_replacements = true;
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
if (line.empty()) { if (line.empty()) {
collecting_replacements = false; collecting_replacements = false;
} else if (collecting_replacements) { }
else if (collecting_replacements) {
auto sep = line.find(" => "); auto sep = line.find(" => ");
replacements.push_back({line.substr(sep + 4), line.substr(0, sep)}); replacements.push_back({line.substr(sep + 4), line.substr(0, sep)});
} else { }
else {
std::cout << line << "\n"; std::cout << line << "\n";
auto time = find_molecule(replacements, line); auto time = find_molecule(replacements, line);
std::cout << "Solution: " << time << "\n"; std::cout << "Solution: " << time << "\n";

View File

@@ -1,23 +1,25 @@
#include <string>
#include <iostream>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <string>
int main() { int main()
{
std::string line; std::string line;
std::getline(std::cin, line); std::getline(std::cin, line);
auto target{std::stoul(line)}; auto target{std::stoul(line)};
/* This is a really stupid way to do this in terms of effort, but it produces the right answer and doesn't involve /* This is a really stupid way to do this in terms of effort, but it produces the right answer and
* thinking too much: * doesn't involve thinking too much:
* *
* n is the current house we're at. * n is the current house we're at.
*/ */
for (auto n{2UL}; true; ++n) { for (auto n{2UL}; true; ++n) {
auto amt{0UL}; auto amt{0UL};
/* Find the number of presents delivered to house `n`. We do this by walking through all numbers <= sqrt(n) and /* Find the number of presents delivered to house `n`. We do this by walking through all
* seeing if they are a factor. If so we add presents for that number (i) and also (n/i), being careful not to * numbers <= sqrt(n) and seeing if they are a factor. If so we add presents for that number
* double count for square roots. This reduces the amount of work we have to do significantly. * (i) and also (n/i), being careful not to double count for square roots. This reduces the
* amount of work we have to do significantly.
*/ */
for (auto i{1UL}; i <= (n / i); ++i) { for (auto i{1UL}; i <= (n / i); ++i) {
if (n % i == 0) { if (n % i == 0) {

View File

@@ -1,25 +1,28 @@
#include <string>
#include <iostream>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <string>
int main() { int main()
{
std::string line; std::string line;
std::getline(std::cin, line); std::getline(std::cin, line);
auto target{std::stoul(line)}; auto target{std::stoul(line)};
/* This is a really stupid way to do this in terms of effort, but it produces the right answer and doesn't involve /* This is a really stupid way to do this in terms of effort, but it produces the right answer and
* thinking too much: * doesn't involve thinking too much:
* *
* n is the current house we're at. * n is the current house we're at.
*/ */
for (auto n{2UL}; true; ++n) { for (auto n{2UL}; true; ++n) {
auto amt{0UL}; auto amt{0UL};
/* Find the number of presents delivered to house `n`. We do this by walking through all numbers <= sqrt(n) and /* Find the number of presents delivered to house `n`. We do this by walking through all
* seeing if they are a factor. If so we add presents for that number (i) and also (n/i), being careful not to * numbers <= sqrt(n) and seeing if they are a factor. If so we add presents for that number
* double count for square roots. This reduces the amount of work we have to do significantly. * (i) and also (n/i), being careful not to double count for square roots. This reduces the
* amount of work we have to do significantly.
* *
* For the second part we also check to ensure we've not at the 51st delivery or greater for this elf. * For the second part we also check to ensure we've not at the 51st delivery or greater for
* this elf.
*/ */
for (auto i{1UL}; i <= (n / i); ++i) { for (auto i{1UL}; i <= (n / i); ++i) {
if (n % i == 0) { if (n % i == 0) {

View File

@@ -1,12 +1,13 @@
#include <cstdlib>
#include <iostream>
#include <numeric>
#include <string> #include <string>
#include <vector> #include <vector>
#include <iostream>
#include <cstdlib>
#include <numeric>
using namespace std::string_literals; using namespace std::string_literals;
struct Item { struct Item
{
std::string name_; std::string name_;
unsigned long cost_; unsigned long cost_;
unsigned long damage_; unsigned long damage_;
@@ -15,21 +16,25 @@ struct Item {
bool operator==(Item const& rhs) const { return name_ == rhs.name_; } bool operator==(Item const& rhs) const { return name_ == rhs.name_; }
}; };
struct Person { struct Person
Person(unsigned long hp, unsigned long damage, unsigned long armour) : name_("Enemy"), hp_(hp), {
cost_(std::numeric_limits<unsigned>::max()), Person(unsigned long hp, unsigned long damage, unsigned long armour)
damage_(damage), : name_("Enemy"), hp_(hp), cost_(std::numeric_limits<unsigned>::max()), damage_(damage),
armour_(armour) {} armour_(armour)
{
}
Person(Item const &weapon, Item const &armour, Item const &left_ring, Item const &right_ring) : Person(Item const& weapon, Item const& armour, Item const& left_ring, Item const& right_ring)
name_("Player: "s + weapon.name_ + ", "s + armour.name_ + ", "s + left_ring.name_ + ", " + : name_("Player: "s + weapon.name_ + ", "s + armour.name_ + ", "s + left_ring.name_ + ", " +
right_ring.name_), right_ring.name_),
hp_(100), hp_(100), cost_(weapon.cost_ + armour.cost_ + left_ring.cost_ + right_ring.cost_),
cost_(weapon.cost_ + armour.cost_ + left_ring.cost_ + right_ring.cost_),
damage_(weapon.damage_ + armour.damage_ + left_ring.damage_ + right_ring.damage_), damage_(weapon.damage_ + armour.damage_ + left_ring.damage_ + right_ring.damage_),
armour_(weapon.armour_ + armour.armour_ + left_ring.armour_ + right_ring.armour_) {} armour_(weapon.armour_ + armour.armour_ + left_ring.armour_ + right_ring.armour_)
{
}
unsigned get_attacked(Person const &attacker) { unsigned get_attacked(Person const& attacker)
{
auto damage{(attacker.damage_ > armour_) ? attacker.damage_ - armour_ : 1}; auto damage{(attacker.damage_ > armour_) ? attacker.damage_ - armour_ : 1};
hp_ = (hp_ > damage) ? hp_ - damage : 0; hp_ = (hp_ > damage) ? hp_ - damage : 0;
return hp_; return hp_;
@@ -42,7 +47,8 @@ struct Person {
unsigned long armour_; unsigned long armour_;
}; };
unsigned long get_value(std::string const &begin) { unsigned long get_value(std::string const& begin)
{
std::string line; std::string line;
if (!std::getline(std::cin, line)) { if (!std::getline(std::cin, line)) {
std::cerr << "Missing line in input\n"; std::cerr << "Missing line in input\n";
@@ -55,48 +61,42 @@ unsigned long get_value(std::string const &begin) {
return std::stoul(line.substr(begin.length())); return std::stoul(line.substr(begin.length()));
} }
bool me_beats_enemy(Person me, Person enemy) { bool me_beats_enemy(Person me, Person enemy)
{
while (true) { while (true) {
enemy.get_attacked(me); enemy.get_attacked(me);
if (enemy.hp_ == 0) { return true; } if (enemy.hp_ == 0) {
return true;
}
me.get_attacked(enemy); me.get_attacked(enemy);
if (me.hp_ == 0) { return false; } if (me.hp_ == 0) {
return false;
}
} }
} }
int main() { int main()
{
const std::string hp_begin{"Hit Points: "}; const std::string hp_begin{"Hit Points: "};
const std::string d_begin{"Damage: "}; const std::string d_begin{"Damage: "};
const std::string a_begin{"Armor: "}; const std::string a_begin{"Armor: "};
const std::vector<Item> weapons{ const std::vector<Item> weapons{
{"Dagger", 8, 4, 0}, {"Dagger", 8, 4, 0}, {"Shortsword", 10, 5, 0}, {"Warhammer", 25, 6, 0},
{"Shortsword", 10, 5, 0}, {"Longsword", 40, 7, 0}, {"Greataxe", 74, 8, 0},
{"Warhammer", 25, 6, 0},
{"Longsword", 40, 7, 0},
{"Greataxe", 74, 8, 0},
}; };
const std::vector<Item> armours{ const std::vector<Item> armours{
{"Nothing", 0, 0, 0}, {"Nothing", 0, 0, 0}, {"Leather", 13, 0, 1}, {"Chainmail", 31, 0, 2},
{"Leather", 13, 0, 1}, {"Splintmail", 53, 0, 3}, {"Bandedmail", 75, 0, 4}, {"Platedmail", 102, 0, 5},
{"Chainmail", 31, 0, 2},
{"Splintmail", 53, 0, 3},
{"Bandedmail", 75, 0, 4},
{"Platedmail", 102, 0, 5},
}; };
const std::vector<Item> rings{ const std::vector<Item> rings{
{"Empty", 0, 0, 0}, {"Empty", 0, 0, 0}, {"Damage +1", 25, 1, 0}, {"Damage +2", 50, 2, 0},
{"Damage +1", 25, 1, 0}, {"Damage +3", 100, 3, 0}, {"Defense +1", 20, 0, 1}, {"Defense +2", 40, 0, 2},
{"Damage +2", 50, 2, 0},
{"Damage +3", 100, 3, 0},
{"Defense +1", 20, 0, 1},
{"Defense +2", 40, 0, 2},
{"Defense +3", 80, 0, 3}, {"Defense +3", 80, 0, 3},
}; };
auto enemy_hp{get_value(hp_begin)}; auto enemy_hp{get_value(hp_begin)};
auto enemy_damage{get_value(d_begin)}; auto enemy_damage{get_value(d_begin)};
auto enemy_armour{get_value(a_begin)}; auto enemy_armour{get_value(a_begin)};
@@ -104,16 +104,25 @@ int main() {
Person best_result{0, 0, 0}; Person best_result{0, 0, 0};
Person enemy{enemy_hp, enemy_damage, enemy_armour}; Person enemy{enemy_hp, enemy_damage, enemy_armour};
for (auto const &weapon: weapons) { for (auto const& weapon : weapons) {
if (weapon.cost_ > best_result.cost_) { continue; } if (weapon.cost_ > best_result.cost_) {
for (auto const &armour: armours) { continue;
if (weapon.cost_ + armour.cost_ > best_result.cost_) { continue; } }
for (auto const &left_ring: rings) { for (auto const& armour : armours) {
if (weapon.cost_ + armour.cost_ + left_ring.cost_ > best_result.cost_) { continue; } if (weapon.cost_ + armour.cost_ > best_result.cost_) {
for (auto const &right_ring: rings) { continue;
}
for (auto const& left_ring : rings) {
if (weapon.cost_ + armour.cost_ + left_ring.cost_ > best_result.cost_) {
continue;
}
for (auto const& right_ring : rings) {
if (weapon.cost_ + armour.cost_ + left_ring.cost_ + right_ring.cost_ > if (weapon.cost_ + armour.cost_ + left_ring.cost_ + right_ring.cost_ >
best_result.cost_) { continue; } best_result.cost_) {
if (left_ring == right_ring) continue; continue;
}
if (left_ring == right_ring)
continue;
Person me{weapon, armour, left_ring, right_ring}; Person me{weapon, armour, left_ring, right_ring};
if (me_beats_enemy(me, enemy) && me.cost_ < best_result.cost_) { if (me_beats_enemy(me, enemy) && me.cost_ < best_result.cost_) {
best_result = me; best_result = me;

View File

@@ -1,12 +1,13 @@
#include <cstdlib>
#include <iostream>
#include <numeric>
#include <string> #include <string>
#include <vector> #include <vector>
#include <iostream>
#include <cstdlib>
#include <numeric>
using namespace std::string_literals; using namespace std::string_literals;
struct Item { struct Item
{
std::string name_; std::string name_;
unsigned long cost_; unsigned long cost_;
unsigned long damage_; unsigned long damage_;
@@ -15,21 +16,25 @@ struct Item {
bool operator==(Item const& rhs) const { return name_ == rhs.name_; } bool operator==(Item const& rhs) const { return name_ == rhs.name_; }
}; };
struct Person { struct Person
Person(unsigned long hp, unsigned long damage, unsigned long armour) : name_("Enemy"), hp_(hp), {
cost_(std::numeric_limits<unsigned>::max()), Person(unsigned long hp, unsigned long damage, unsigned long armour)
damage_(damage), : name_("Enemy"), hp_(hp), cost_(std::numeric_limits<unsigned>::max()), damage_(damage),
armour_(armour) {} armour_(armour)
{
}
Person(Item const &weapon, Item const &armour, Item const &left_ring, Item const &right_ring) : Person(Item const& weapon, Item const& armour, Item const& left_ring, Item const& right_ring)
name_("Player: "s + weapon.name_ + ", "s + armour.name_ + ", "s + left_ring.name_ + ", " + : name_("Player: "s + weapon.name_ + ", "s + armour.name_ + ", "s + left_ring.name_ + ", " +
right_ring.name_), right_ring.name_),
hp_(100), hp_(100), cost_(weapon.cost_ + armour.cost_ + left_ring.cost_ + right_ring.cost_),
cost_(weapon.cost_ + armour.cost_ + left_ring.cost_ + right_ring.cost_),
damage_(weapon.damage_ + armour.damage_ + left_ring.damage_ + right_ring.damage_), damage_(weapon.damage_ + armour.damage_ + left_ring.damage_ + right_ring.damage_),
armour_(weapon.armour_ + armour.armour_ + left_ring.armour_ + right_ring.armour_) {} armour_(weapon.armour_ + armour.armour_ + left_ring.armour_ + right_ring.armour_)
{
}
unsigned get_attacked(Person const &attacker) { unsigned get_attacked(Person const& attacker)
{
auto damage{(attacker.damage_ > armour_) ? attacker.damage_ - armour_ : 1}; auto damage{(attacker.damage_ > armour_) ? attacker.damage_ - armour_ : 1};
hp_ = (hp_ > damage) ? hp_ - damage : 0; hp_ = (hp_ > damage) ? hp_ - damage : 0;
return hp_; return hp_;
@@ -42,7 +47,8 @@ struct Person {
unsigned long armour_; unsigned long armour_;
}; };
unsigned long get_value(std::string const &begin) { unsigned long get_value(std::string const& begin)
{
std::string line; std::string line;
if (!std::getline(std::cin, line)) { if (!std::getline(std::cin, line)) {
std::cerr << "Missing line in input\n"; std::cerr << "Missing line in input\n";
@@ -55,48 +61,42 @@ unsigned long get_value(std::string const &begin) {
return std::stoul(line.substr(begin.length())); return std::stoul(line.substr(begin.length()));
} }
bool me_beats_enemy(Person me, Person enemy) { bool me_beats_enemy(Person me, Person enemy)
{
while (true) { while (true) {
enemy.get_attacked(me); enemy.get_attacked(me);
if (enemy.hp_ == 0) { return true; } if (enemy.hp_ == 0) {
return true;
}
me.get_attacked(enemy); me.get_attacked(enemy);
if (me.hp_ == 0) { return false; } if (me.hp_ == 0) {
return false;
}
} }
} }
int main() { int main()
{
const std::string hp_begin{"Hit Points: "}; const std::string hp_begin{"Hit Points: "};
const std::string d_begin{"Damage: "}; const std::string d_begin{"Damage: "};
const std::string a_begin{"Armor: "}; const std::string a_begin{"Armor: "};
const std::vector<Item> weapons{ const std::vector<Item> weapons{
{"Dagger", 8, 4, 0}, {"Dagger", 8, 4, 0}, {"Shortsword", 10, 5, 0}, {"Warhammer", 25, 6, 0},
{"Shortsword", 10, 5, 0}, {"Longsword", 40, 7, 0}, {"Greataxe", 74, 8, 0},
{"Warhammer", 25, 6, 0},
{"Longsword", 40, 7, 0},
{"Greataxe", 74, 8, 0},
}; };
const std::vector<Item> armours{ const std::vector<Item> armours{
{"Nothing", 0, 0, 0}, {"Nothing", 0, 0, 0}, {"Leather", 13, 0, 1}, {"Chainmail", 31, 0, 2},
{"Leather", 13, 0, 1}, {"Splintmail", 53, 0, 3}, {"Bandedmail", 75, 0, 4}, {"Platedmail", 102, 0, 5},
{"Chainmail", 31, 0, 2},
{"Splintmail", 53, 0, 3},
{"Bandedmail", 75, 0, 4},
{"Platedmail", 102, 0, 5},
}; };
const std::vector<Item> rings{ const std::vector<Item> rings{
{"Empty", 0, 0, 0}, {"Empty", 0, 0, 0}, {"Damage +1", 25, 1, 0}, {"Damage +2", 50, 2, 0},
{"Damage +1", 25, 1, 0}, {"Damage +3", 100, 3, 0}, {"Defense +1", 20, 0, 1}, {"Defense +2", 40, 0, 2},
{"Damage +2", 50, 2, 0},
{"Damage +3", 100, 3, 0},
{"Defense +1", 20, 0, 1},
{"Defense +2", 40, 0, 2},
{"Defense +3", 80, 0, 3}, {"Defense +3", 80, 0, 3},
}; };
auto enemy_hp{get_value(hp_begin)}; auto enemy_hp{get_value(hp_begin)};
auto enemy_damage{get_value(d_begin)}; auto enemy_damage{get_value(d_begin)};
auto enemy_armour{get_value(a_begin)}; auto enemy_armour{get_value(a_begin)};
@@ -106,11 +106,12 @@ int main() {
worst_result.cost_ = 0; worst_result.cost_ = 0;
Person enemy{enemy_hp, enemy_damage, enemy_armour}; Person enemy{enemy_hp, enemy_damage, enemy_armour};
for (auto const &weapon: weapons) { for (auto const& weapon : weapons) {
for (auto const &armour: armours) { for (auto const& armour : armours) {
for (auto const &left_ring: rings) { for (auto const& left_ring : rings) {
for (auto const &right_ring: rings) { for (auto const& right_ring : rings) {
if (left_ring == right_ring) continue; if (left_ring == right_ring)
continue;
Person me{weapon, armour, left_ring, right_ring}; Person me{weapon, armour, left_ring, right_ring};
if (me_beats_enemy(me, enemy)) { if (me_beats_enemy(me, enemy)) {
if (me.cost_ < best_result.cost_) { if (me.cost_ < best_result.cost_) {
@@ -126,5 +127,6 @@ int main() {
} }
std::cout << "Best person: " << best_result.name_ << " at cost of " << best_result.cost_ << '\n'; std::cout << "Best person: " << best_result.name_ << " at cost of " << best_result.cost_ << '\n';
std::cout << "Worst person: " << worst_result.name_ << " at cost of " << worst_result.cost_ << '\n'; std::cout << "Worst person: " << worst_result.name_ << " at cost of " << worst_result.cost_
<< '\n';
} }

View File

@@ -1,14 +1,18 @@
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <string> #include <string>
#include <vector> #include <vector>
#include <iostream>
#include <cstdlib>
#include <limits>
#include <algorithm>
using namespace std::string_literals; using namespace std::string_literals;
struct State { struct State
State(unsigned long enemy_hp, unsigned long enemy_damage) : enemy_hp_(enemy_hp), enemy_damage_(enemy_damage) {} {
State(unsigned long enemy_hp, unsigned long enemy_damage)
: enemy_hp_(enemy_hp), enemy_damage_(enemy_damage)
{
}
unsigned long my_hp_{50}; unsigned long my_hp_{50};
unsigned long my_mana_{500}; unsigned long my_mana_{500};
@@ -20,14 +24,16 @@ struct State {
unsigned long recharge_counter_{0}; unsigned long recharge_counter_{0};
unsigned long cost_{0}; unsigned long cost_{0};
bool operator==(State const &rhs) const { bool operator==(State const& rhs) const
{
return my_hp_ == rhs.my_hp_ && my_mana_ == rhs.my_mana_ && my_armour_ == rhs.my_armour_ && return my_hp_ == rhs.my_hp_ && my_mana_ == rhs.my_mana_ && my_armour_ == rhs.my_armour_ &&
enemy_hp_ == rhs.enemy_hp_ && enemy_damage_ == rhs.enemy_damage_ && enemy_hp_ == rhs.enemy_hp_ && enemy_damage_ == rhs.enemy_damage_ &&
shield_counter_ == rhs.shield_counter_ && poison_counter_ == rhs.poison_counter_ && shield_counter_ == rhs.shield_counter_ && poison_counter_ == rhs.poison_counter_ &&
recharge_counter_ == rhs.recharge_counter_; recharge_counter_ == rhs.recharge_counter_;
} }
bool apply_effects() { bool apply_effects()
{
if (shield_counter_ > 0) { if (shield_counter_ > 0) {
if (--shield_counter_ == 0) { if (--shield_counter_ == 0) {
my_armour_ -= 7; my_armour_ -= 7;
@@ -44,28 +50,33 @@ struct State {
return enemy_hp_ == 0; return enemy_hp_ == 0;
} }
void hit_enemy(unsigned long damage) { void hit_enemy(unsigned long damage)
{
enemy_hp_ = (damage > enemy_hp_) ? 0 : enemy_hp_ - damage; enemy_hp_ = (damage > enemy_hp_) ? 0 : enemy_hp_ - damage;
} }
void hit_me() { void hit_me()
{
auto amt{my_armour_ >= enemy_damage_ ? 1 : enemy_damage_ - my_armour_}; auto amt{my_armour_ >= enemy_damage_ ? 1 : enemy_damage_ - my_armour_};
my_hp_ = (amt > my_hp_) ? 0 : my_hp_ - amt; my_hp_ = (amt > my_hp_) ? 0 : my_hp_ - amt;
} }
void spend_mana(unsigned long amt) { void spend_mana(unsigned long amt)
{
assert(my_mana_ >= amt); assert(my_mana_ >= amt);
my_mana_ -= amt; my_mana_ -= amt;
cost_ += amt; cost_ += amt;
} }
void enemy_turn() { void enemy_turn()
{
if (!apply_effects()) { if (!apply_effects()) {
hit_me(); hit_me();
} }
} }
[[nodiscard]] State magic_missile() const { [[nodiscard]] State magic_missile() const
{
State next{*this}; State next{*this};
next.spend_mana(53); next.spend_mana(53);
next.hit_enemy(4); next.hit_enemy(4);
@@ -73,7 +84,8 @@ struct State {
return next; return next;
} }
[[nodiscard]] State drain() const { [[nodiscard]] State drain() const
{
State next{*this}; State next{*this};
next.spend_mana(73); next.spend_mana(73);
next.hit_enemy(2); next.hit_enemy(2);
@@ -82,7 +94,8 @@ struct State {
return next; return next;
} }
[[nodiscard]] State shield() const { [[nodiscard]] State shield() const
{
State next{*this}; State next{*this};
assert(shield_counter_ == 0); assert(shield_counter_ == 0);
next.spend_mana(113); next.spend_mana(113);
@@ -92,7 +105,8 @@ struct State {
return next; return next;
} }
[[nodiscard]] State poison() const { [[nodiscard]] State poison() const
{
State next{*this}; State next{*this};
assert(poison_counter_ == 0); assert(poison_counter_ == 0);
next.spend_mana(173); next.spend_mana(173);
@@ -101,7 +115,8 @@ struct State {
return next; return next;
} }
[[nodiscard]] State recharge() const { [[nodiscard]] State recharge() const
{
State next{*this}; State next{*this};
assert(recharge_counter_ == 0); assert(recharge_counter_ == 0);
next.spend_mana(229); next.spend_mana(229);
@@ -111,7 +126,8 @@ struct State {
} }
}; };
unsigned long get_value(std::string const &begin) { unsigned long get_value(std::string const& begin)
{
std::string line; std::string line;
if (!std::getline(std::cin, line)) { if (!std::getline(std::cin, line)) {
std::cerr << "Missing line in input\n"; std::cerr << "Missing line in input\n";
@@ -129,19 +145,22 @@ unsigned long get_value(std::string const &begin) {
* @param states Vector of states * @param states Vector of states
* @param state State to add. * @param state State to add.
* *
* If there is already an element in \a states that is the same as \a state we don't add a new state, instead we just * If there is already an element in \a states that is the same as \a state we don't add a new
* update the cost to the minimum. * state, instead we just update the cost to the minimum.
*/ */
void add_state(std::vector<State> &states, State const &state) { void add_state(std::vector<State>& states, State const& state)
{
auto it = std::find(states.begin(), states.end(), state); auto it = std::find(states.begin(), states.end(), state);
if (it == states.end()) { if (it == states.end()) {
states.push_back(state); states.push_back(state);
} else if (it->cost_ > state.cost_) { }
else if (it->cost_ > state.cost_) {
it->cost_ = state.cost_; it->cost_ = state.cost_;
} }
} }
int main() { int main()
{
const std::string hp_begin{"Hit Points: "}; const std::string hp_begin{"Hit Points: "};
const std::string d_begin{"Damage: "}; const std::string d_begin{"Damage: "};
@@ -157,13 +176,14 @@ int main() {
while (!states.empty()) { while (!states.empty()) {
/* Get the lowest cost element in the list of states and process that. */ /* Get the lowest cost element in the list of states and process that. */
auto it = std::min_element(states.begin(), states.end(), auto it =
[](State const &lhs, State const &rhs) { return lhs.cost_ < rhs.cost_; }); std::min_element(states.begin(), states.end(),
[](State const& lhs, State const& rhs) { return lhs.cost_ < rhs.cost_; });
State candidate{*it}; State candidate{*it};
states.erase(it); states.erase(it);
if (candidate.cost_ >= best_cost) { if (candidate.cost_ >= best_cost) {
/* Because we've searched for the minimum element above we know that all future candidates are going to /* Because we've searched for the minimum element above we know that all future candidates are
* cost more than the current best cost for winning - so just stop here. */ * going to cost more than the current best cost for winning - so just stop here. */
break; break;
} }
@@ -187,8 +207,8 @@ int main() {
states.push_back(candidate); states.push_back(candidate);
} }
/* Handle each of our options (followed by the enemy's turn). Making sure that when we add the state we /* Handle each of our options (followed by the enemy's turn). Making sure that when we add the
* don't duplicate ourselves. * state we don't duplicate ourselves.
*/ */
if (candidate.my_mana_ >= 53) { if (candidate.my_mana_ >= 53) {
add_state(states, candidate.magic_missile()); add_state(states, candidate.magic_missile());

View File

@@ -1,14 +1,18 @@
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <string> #include <string>
#include <vector> #include <vector>
#include <iostream>
#include <cstdlib>
#include <limits>
#include <algorithm>
using namespace std::string_literals; using namespace std::string_literals;
struct State { struct State
State(unsigned long enemy_hp, unsigned long enemy_damage) : enemy_hp_(enemy_hp), enemy_damage_(enemy_damage) {} {
State(unsigned long enemy_hp, unsigned long enemy_damage)
: enemy_hp_(enemy_hp), enemy_damage_(enemy_damage)
{
}
unsigned long my_hp_{50}; unsigned long my_hp_{50};
unsigned long my_mana_{500}; unsigned long my_mana_{500};
@@ -20,14 +24,16 @@ struct State {
unsigned long recharge_counter_{0}; unsigned long recharge_counter_{0};
unsigned long cost_{0}; unsigned long cost_{0};
bool operator==(State const &rhs) const { bool operator==(State const& rhs) const
{
return my_hp_ == rhs.my_hp_ && my_mana_ == rhs.my_mana_ && my_armour_ == rhs.my_armour_ && return my_hp_ == rhs.my_hp_ && my_mana_ == rhs.my_mana_ && my_armour_ == rhs.my_armour_ &&
enemy_hp_ == rhs.enemy_hp_ && enemy_damage_ == rhs.enemy_damage_ && enemy_hp_ == rhs.enemy_hp_ && enemy_damage_ == rhs.enemy_damage_ &&
shield_counter_ == rhs.shield_counter_ && poison_counter_ == rhs.poison_counter_ && shield_counter_ == rhs.shield_counter_ && poison_counter_ == rhs.poison_counter_ &&
recharge_counter_ == rhs.recharge_counter_; recharge_counter_ == rhs.recharge_counter_;
} }
bool apply_effects() { bool apply_effects()
{
if (shield_counter_ > 0) { if (shield_counter_ > 0) {
if (--shield_counter_ == 0) { if (--shield_counter_ == 0) {
my_armour_ -= 7; my_armour_ -= 7;
@@ -44,28 +50,33 @@ struct State {
return enemy_hp_ == 0; return enemy_hp_ == 0;
} }
void hit_enemy(unsigned long damage) { void hit_enemy(unsigned long damage)
{
enemy_hp_ = (damage > enemy_hp_) ? 0 : enemy_hp_ - damage; enemy_hp_ = (damage > enemy_hp_) ? 0 : enemy_hp_ - damage;
} }
void hit_me() { void hit_me()
{
auto amt{my_armour_ >= enemy_damage_ ? 1 : enemy_damage_ - my_armour_}; auto amt{my_armour_ >= enemy_damage_ ? 1 : enemy_damage_ - my_armour_};
my_hp_ = (amt > my_hp_) ? 0 : my_hp_ - amt; my_hp_ = (amt > my_hp_) ? 0 : my_hp_ - amt;
} }
void spend_mana(unsigned long amt) { void spend_mana(unsigned long amt)
{
assert(my_mana_ >= amt); assert(my_mana_ >= amt);
my_mana_ -= amt; my_mana_ -= amt;
cost_ += amt; cost_ += amt;
} }
void enemy_turn() { void enemy_turn()
{
if (!apply_effects()) { if (!apply_effects()) {
hit_me(); hit_me();
} }
} }
[[nodiscard]] State magic_missile() const { [[nodiscard]] State magic_missile() const
{
State next{*this}; State next{*this};
next.spend_mana(53); next.spend_mana(53);
next.hit_enemy(4); next.hit_enemy(4);
@@ -73,7 +84,8 @@ struct State {
return next; return next;
} }
[[nodiscard]] State drain() const { [[nodiscard]] State drain() const
{
State next{*this}; State next{*this};
next.spend_mana(73); next.spend_mana(73);
next.hit_enemy(2); next.hit_enemy(2);
@@ -82,7 +94,8 @@ struct State {
return next; return next;
} }
[[nodiscard]] State shield() const { [[nodiscard]] State shield() const
{
State next{*this}; State next{*this};
assert(shield_counter_ == 0); assert(shield_counter_ == 0);
next.spend_mana(113); next.spend_mana(113);
@@ -92,7 +105,8 @@ struct State {
return next; return next;
} }
[[nodiscard]] State poison() const { [[nodiscard]] State poison() const
{
State next{*this}; State next{*this};
assert(poison_counter_ == 0); assert(poison_counter_ == 0);
next.spend_mana(173); next.spend_mana(173);
@@ -101,7 +115,8 @@ struct State {
return next; return next;
} }
[[nodiscard]] State recharge() const { [[nodiscard]] State recharge() const
{
State next{*this}; State next{*this};
assert(recharge_counter_ == 0); assert(recharge_counter_ == 0);
next.spend_mana(229); next.spend_mana(229);
@@ -111,7 +126,8 @@ struct State {
} }
}; };
unsigned long get_value(std::string const &begin) { unsigned long get_value(std::string const& begin)
{
std::string line; std::string line;
if (!std::getline(std::cin, line)) { if (!std::getline(std::cin, line)) {
std::cerr << "Missing line in input\n"; std::cerr << "Missing line in input\n";
@@ -129,19 +145,22 @@ unsigned long get_value(std::string const &begin) {
* @param states Vector of states * @param states Vector of states
* @param state State to add. * @param state State to add.
* *
* If there is already an element in \a states that is the same as \a state we don't add a new state, instead we just * If there is already an element in \a states that is the same as \a state we don't add a new
* update the cost to the minimum. * state, instead we just update the cost to the minimum.
*/ */
void add_state(std::vector<State> &states, State const &state) { void add_state(std::vector<State>& states, State const& state)
{
auto it = std::find(states.begin(), states.end(), state); auto it = std::find(states.begin(), states.end(), state);
if (it == states.end()) { if (it == states.end()) {
states.push_back(state); states.push_back(state);
} else if (it->cost_ > state.cost_) { }
else if (it->cost_ > state.cost_) {
it->cost_ = state.cost_; it->cost_ = state.cost_;
} }
} }
int main() { int main()
{
const std::string hp_begin{"Hit Points: "}; const std::string hp_begin{"Hit Points: "};
const std::string d_begin{"Damage: "}; const std::string d_begin{"Damage: "};
@@ -157,13 +176,14 @@ int main() {
while (!states.empty()) { while (!states.empty()) {
/* Get the lowest cost element in the list of states and process that. */ /* Get the lowest cost element in the list of states and process that. */
auto it = std::min_element(states.begin(), states.end(), auto it =
[](State const &lhs, State const &rhs) { return lhs.cost_ < rhs.cost_; }); std::min_element(states.begin(), states.end(),
[](State const& lhs, State const& rhs) { return lhs.cost_ < rhs.cost_; });
State candidate{*it}; State candidate{*it};
states.erase(it); states.erase(it);
if (candidate.cost_ >= best_cost) { if (candidate.cost_ >= best_cost) {
/* Because we've searched for the minimum element above we know that all future candidates are going to /* Because we've searched for the minimum element above we know that all future candidates are
* cost more than the current best cost for winning - so just stop here. */ * going to cost more than the current best cost for winning - so just stop here. */
break; break;
} }
@@ -185,8 +205,8 @@ int main() {
states.push_back(candidate); states.push_back(candidate);
} }
/* Handle each of our options (followed by the enemy's turn). Making sure that when we add the state we /* Handle each of our options (followed by the enemy's turn). Making sure that when we add the
* don't duplicate ourselves. * state we don't duplicate ourselves.
*/ */
if (candidate.my_mana_ >= 53) { if (candidate.my_mana_ >= 53) {
add_state(states, candidate.magic_missile()); add_state(states, candidate.magic_missile());

View File

@@ -1,45 +1,43 @@
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include <iostream>
#include <cstdlib>
#include <limits>
#include <algorithm>
#include <map>
enum class Op { enum class Op { hlf, tpl, inc, jmp, jie, jio };
hlf, tpl, inc, jmp, jie, jio enum class Reg { a, b };
};
enum class Reg {
a, b
};
struct Instr { struct Instr
static Op get_opcode(std::string const &str) { {
static std::map<std::string, Op> ops{ static Op get_opcode(std::string const& str)
{"hlf ", Op::hlf}, {
{"tpl ", Op::tpl}, static std::map<std::string, Op> ops{{"hlf ", Op::hlf}, {"tpl ", Op::tpl}, {"inc ", Op::inc},
{"inc ", Op::inc}, {"jmp ", Op::jmp}, {"jie ", Op::jie}, {"jio ", Op::jio}};
{"jmp ", Op::jmp},
{"jie ", Op::jie},
{"jio ", Op::jio}
};
auto it = ops.find(str.substr(0, 4)); auto it = ops.find(str.substr(0, 4));
assert(it != ops.end()); assert(it != ops.end());
return it->second; return it->second;
} }
static Reg get_register(std::string const &str) { static Reg get_register(std::string const& str)
{
assert(str.size() >= 1); assert(str.size() >= 1);
if (str[0] == 'a') { return Reg::a; } if (str[0] == 'a') {
else if (str[0] == 'b') { return Reg::b; } return Reg::a;
else { abort(); } }
else if (str[0] == 'b') {
return Reg::b;
}
else {
abort();
}
} }
static long get_offset(std::string const &str) { static long get_offset(std::string const& str) { return std::stol(str); }
return std::stol(str);
}
explicit Instr(std::string const &str) { explicit Instr(std::string const& str)
{
op_ = get_opcode(str); op_ = get_opcode(str);
switch (op_) { switch (op_) {
case Op::hlf: case Op::hlf:
@@ -70,20 +68,26 @@ struct Instr {
long pc_add_; long pc_add_;
}; };
struct State { struct State
{
unsigned long a_{0}; unsigned long a_{0};
unsigned long b_{0}; unsigned long b_{0};
unsigned long pc_{0}; unsigned long pc_{0};
unsigned long& reg(Reg r) { unsigned long& reg(Reg r)
{
switch (r) { switch (r) {
case Reg::a: return a_; case Reg::a:
case Reg::b: return b_; return a_;
default: abort(); case Reg::b:
return b_;
default:
abort();
} }
} }
void execute(Instr const &instruction) { void execute(Instr const& instruction)
{
switch (instruction.op_) { switch (instruction.op_) {
case Op::hlf: case Op::hlf:
reg(instruction.reg_) /= 2; reg(instruction.reg_) /= 2;
@@ -101,12 +105,16 @@ struct State {
pc_ += instruction.pc_add_; pc_ += instruction.pc_add_;
break; break;
case Op::jie: case Op::jie:
if (reg(instruction.reg_) % 2 == 0) pc_ += instruction.pc_add_; if (reg(instruction.reg_) % 2 == 0)
else pc_ += 1; pc_ += instruction.pc_add_;
else
pc_ += 1;
break; break;
case Op::jio: case Op::jio:
if (reg(instruction.reg_) == 1) pc_ += instruction.pc_add_; if (reg(instruction.reg_) == 1)
else pc_ += 1; pc_ += instruction.pc_add_;
else
pc_ += 1;
break; break;
default: default:
abort(); abort();
@@ -114,7 +122,8 @@ struct State {
} }
}; };
int main() { int main()
{
std::vector<Instr> instructions; std::vector<Instr> instructions;
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -1,45 +1,43 @@
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include <iostream>
#include <cstdlib>
#include <limits>
#include <algorithm>
#include <map>
enum class Op { enum class Op { hlf, tpl, inc, jmp, jie, jio };
hlf, tpl, inc, jmp, jie, jio enum class Reg { a, b };
};
enum class Reg {
a, b
};
struct Instr { struct Instr
static Op get_opcode(std::string const &str) { {
static std::map<std::string, Op> ops{ static Op get_opcode(std::string const& str)
{"hlf ", Op::hlf}, {
{"tpl ", Op::tpl}, static std::map<std::string, Op> ops{{"hlf ", Op::hlf}, {"tpl ", Op::tpl}, {"inc ", Op::inc},
{"inc ", Op::inc}, {"jmp ", Op::jmp}, {"jie ", Op::jie}, {"jio ", Op::jio}};
{"jmp ", Op::jmp},
{"jie ", Op::jie},
{"jio ", Op::jio}
};
auto it = ops.find(str.substr(0, 4)); auto it = ops.find(str.substr(0, 4));
assert(it != ops.end()); assert(it != ops.end());
return it->second; return it->second;
} }
static Reg get_register(std::string const &str) { static Reg get_register(std::string const& str)
{
assert(str.size() >= 1); assert(str.size() >= 1);
if (str[0] == 'a') { return Reg::a; } if (str[0] == 'a') {
else if (str[0] == 'b') { return Reg::b; } return Reg::a;
else { abort(); } }
else if (str[0] == 'b') {
return Reg::b;
}
else {
abort();
}
} }
static long get_offset(std::string const &str) { static long get_offset(std::string const& str) { return std::stol(str); }
return std::stol(str);
}
explicit Instr(std::string const &str) { explicit Instr(std::string const& str)
{
op_ = get_opcode(str); op_ = get_opcode(str);
switch (op_) { switch (op_) {
case Op::hlf: case Op::hlf:
@@ -70,20 +68,26 @@ struct Instr {
long pc_add_; long pc_add_;
}; };
struct State { struct State
{
unsigned long a_{1}; unsigned long a_{1};
unsigned long b_{0}; unsigned long b_{0};
unsigned long pc_{0}; unsigned long pc_{0};
unsigned long& reg(Reg r) { unsigned long& reg(Reg r)
{
switch (r) { switch (r) {
case Reg::a: return a_; case Reg::a:
case Reg::b: return b_; return a_;
default: abort(); case Reg::b:
return b_;
default:
abort();
} }
} }
void execute(Instr const &instruction) { void execute(Instr const& instruction)
{
switch (instruction.op_) { switch (instruction.op_) {
case Op::hlf: case Op::hlf:
reg(instruction.reg_) /= 2; reg(instruction.reg_) /= 2;
@@ -101,12 +105,16 @@ struct State {
pc_ += instruction.pc_add_; pc_ += instruction.pc_add_;
break; break;
case Op::jie: case Op::jie:
if (reg(instruction.reg_) % 2 == 0) pc_ += instruction.pc_add_; if (reg(instruction.reg_) % 2 == 0)
else pc_ += 1; pc_ += instruction.pc_add_;
else
pc_ += 1;
break; break;
case Op::jio: case Op::jio:
if (reg(instruction.reg_) == 1) pc_ += instruction.pc_add_; if (reg(instruction.reg_) == 1)
else pc_ += 1; pc_ += instruction.pc_add_;
else
pc_ += 1;
break; break;
default: default:
abort(); abort();
@@ -114,7 +122,8 @@ struct State {
} }
}; };
int main() { int main()
{
std::vector<Instr> instructions; std::vector<Instr> instructions;
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -1,40 +1,49 @@
#include <string>
#include <vector>
#include <iostream>
#include <cstdlib>
#include <limits>
#include <algorithm> #include <algorithm>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <map> #include <map>
#include <numeric> #include <numeric>
#include <set> #include <set>
#include <string>
#include <vector>
struct State { struct State
{
std::set<unsigned long> weights_; std::set<unsigned long> weights_;
explicit State(unsigned long w) { weights_.insert(w); } explicit State(unsigned long w) { weights_.insert(w); }
std::size_t cost() const { return weights_.size(); } std::size_t cost() const { return weights_.size(); }
unsigned long qe() const { unsigned long qe() const
{
return std::accumulate(weights_.begin(), weights_.end(), 1UL, return std::accumulate(weights_.begin(), weights_.end(), 1UL,
[](unsigned long l, unsigned long w) { return l * w; }); [](unsigned long l, unsigned long w) { return l * w; });
} }
unsigned long weight() const { unsigned long weight() const
{
return std::accumulate(weights_.begin(), weights_.end(), 0UL, return std::accumulate(weights_.begin(), weights_.end(), 0UL,
[](unsigned long l, unsigned long w) { return l + w; }); [](unsigned long l, unsigned long w) { return l + w; });
} }
bool operator==(State const &rhs) const { return weights_ == rhs.weights_; } bool operator==(State const& rhs) const { return weights_ == rhs.weights_; }
bool operator<(State const &rhs) const { bool operator<(State const& rhs) const
if (cost() < rhs.cost()) { return true; } {
if (cost() == rhs.cost()) { return qe() < rhs.qe(); } if (cost() < rhs.cost()) {
return true;
}
if (cost() == rhs.cost()) {
return qe() < rhs.qe();
}
return false; return false;
} }
}; };
int main() { int main()
{
std::vector<unsigned long> weights; std::vector<unsigned long> weights;
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
@@ -43,7 +52,7 @@ int main() {
std::set<State> states; std::set<State> states;
unsigned long target_weight; unsigned long target_weight;
for (auto w: weights) { for (auto w : weights) {
states.insert(State{w}); states.insert(State{w});
target_weight += w; target_weight += w;
} }
@@ -62,7 +71,7 @@ int main() {
continue; continue;
} }
for (auto w: weights) { for (auto w : weights) {
if (current.weights_.find(w) == current.weights_.end()) { if (current.weights_.find(w) == current.weights_.end()) {
auto next{current}; auto next{current};
next.weights_.insert(w); next.weights_.insert(w);

View File

@@ -1,40 +1,49 @@
#include <string>
#include <vector>
#include <iostream>
#include <cstdlib>
#include <limits>
#include <algorithm> #include <algorithm>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <map> #include <map>
#include <numeric> #include <numeric>
#include <set> #include <set>
#include <string>
#include <vector>
struct State { struct State
{
std::set<unsigned long> weights_; std::set<unsigned long> weights_;
explicit State(unsigned long w) { weights_.insert(w); } explicit State(unsigned long w) { weights_.insert(w); }
std::size_t cost() const { return weights_.size(); } std::size_t cost() const { return weights_.size(); }
unsigned long qe() const { unsigned long qe() const
{
return std::accumulate(weights_.begin(), weights_.end(), 1UL, return std::accumulate(weights_.begin(), weights_.end(), 1UL,
[](unsigned long l, unsigned long w) { return l * w; }); [](unsigned long l, unsigned long w) { return l * w; });
} }
unsigned long weight() const { unsigned long weight() const
{
return std::accumulate(weights_.begin(), weights_.end(), 0UL, return std::accumulate(weights_.begin(), weights_.end(), 0UL,
[](unsigned long l, unsigned long w) { return l + w; }); [](unsigned long l, unsigned long w) { return l + w; });
} }
bool operator==(State const &rhs) const { return weights_ == rhs.weights_; } bool operator==(State const& rhs) const { return weights_ == rhs.weights_; }
bool operator<(State const &rhs) const { bool operator<(State const& rhs) const
if (cost() < rhs.cost()) { return true; } {
if (cost() == rhs.cost()) { return qe() < rhs.qe(); } if (cost() < rhs.cost()) {
return true;
}
if (cost() == rhs.cost()) {
return qe() < rhs.qe();
}
return false; return false;
} }
}; };
int main() { int main()
{
std::vector<unsigned long> weights; std::vector<unsigned long> weights;
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
@@ -43,7 +52,7 @@ int main() {
std::set<State> states; std::set<State> states;
unsigned long target_weight; unsigned long target_weight;
for (auto w: weights) { for (auto w : weights) {
states.insert(State{w}); states.insert(State{w});
target_weight += w; target_weight += w;
} }
@@ -62,7 +71,7 @@ int main() {
continue; continue;
} }
for (auto w: weights) { for (auto w : weights) {
if (current.weights_.find(w) == current.weights_.end()) { if (current.weights_.find(w) == current.weights_.end()) {
auto next{current}; auto next{current};
next.weights_.insert(w); next.weights_.insert(w);

View File

@@ -1,11 +1,8 @@
#include <cstdint> #include <cstdint>
#include <string>
#include <iostream> #include <iostream>
#include <string>
std::uint64_t lcg(std::uint64_t val) std::uint64_t lcg(std::uint64_t val) { return (val * 252533) % 33554393; }
{
return (val * 252533) % 33554393;
}
int main() int main()
{ {
@@ -13,7 +10,8 @@ int main()
std::getline(std::cin, line); std::getline(std::cin, line);
using namespace std::string_literals; using namespace std::string_literals;
auto line_begin{"To continue, please consult the code grid in the manual. Enter the code at row "s}; auto line_begin{
"To continue, please consult the code grid in the manual. Enter the code at row "s};
auto line_middle{", column "s}; auto line_middle{", column "s};
auto line_end{"."s}; auto line_end{"."s};

View File

@@ -2,7 +2,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::vector<int> vals; std::vector<int> vals;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
int val = std::stoi(line, nullptr, 10); int val = std::stoi(line, nullptr, 10);

View File

@@ -2,7 +2,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::vector<int> vals; std::vector<int> vals;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
int val = std::stoi(line, nullptr, 10); int val = std::stoi(line, nullptr, 10);
@@ -12,8 +13,8 @@ int main(int argc, char **argv) {
for (std::size_t j = 0; j < i; ++j) { for (std::size_t j = 0; j < i; ++j) {
int64_t v2 = vals[j]; int64_t v2 = vals[j];
if (v1 + v2 + val == 2020) { if (v1 + v2 + val == 2020) {
std::cout << v1 << " * " << v2 << " * " << val << " = " std::cout << v1 << " * " << v2 << " * " << val << " = " << v1 * v2 * std::int64_t(val)
<< v1 * v2 * std::int64_t(val) << "\n"; << "\n";
} }
} }
} }

View File

@@ -3,8 +3,10 @@
#include <string> #include <string>
#include <vector> #include <vector>
struct PasswordChecker { struct PasswordChecker
PasswordChecker(std::string const &s) { {
PasswordChecker(std::string const& s)
{
std::size_t pos = 0; std::size_t pos = 0;
min_ = std::stoul(s, &pos, 10); min_ = std::stoul(s, &pos, 10);
assert(s[pos] == '-'); assert(s[pos] == '-');
@@ -17,7 +19,8 @@ struct PasswordChecker {
password_ = s2.substr(pos + 4); password_ = s2.substr(pos + 4);
} }
bool is_valid() const { bool is_valid() const
{
std::string::size_type count = 0; std::string::size_type count = 0;
for (auto c : password_) { for (auto c : password_) {
if (c == c_) { if (c == c_) {
@@ -34,13 +37,15 @@ struct PasswordChecker {
std::string password_; std::string password_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
unsigned count = 0; unsigned count = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
PasswordChecker check(line); PasswordChecker check(line);
if (check.is_valid()) { if (check.is_valid()) {
++count; ++count;
} else { }
else {
std::cout << "IN"; std::cout << "IN";
} }
std::cout << "VALID: " << line << "\n"; std::cout << "VALID: " << line << "\n";

View File

@@ -3,8 +3,10 @@
#include <string> #include <string>
#include <vector> #include <vector>
struct PasswordChecker { struct PasswordChecker
PasswordChecker(std::string const &s) { {
PasswordChecker(std::string const& s)
{
std::size_t pos = 0; std::size_t pos = 0;
pos1_ = std::stoul(s, &pos, 10); pos1_ = std::stoul(s, &pos, 10);
assert(s[pos] == '-'); assert(s[pos] == '-');
@@ -17,7 +19,8 @@ struct PasswordChecker {
password_ = s2.substr(pos + 4); password_ = s2.substr(pos + 4);
} }
bool is_valid() const { bool is_valid() const
{
std::string::size_type count = 0; std::string::size_type count = 0;
if (password_.at(pos1_ - 1) == c_) { if (password_.at(pos1_ - 1) == c_) {
++count; ++count;
@@ -34,13 +37,15 @@ struct PasswordChecker {
std::string password_; std::string password_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
unsigned count = 0; unsigned count = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
PasswordChecker check(line); PasswordChecker check(line);
if (check.is_valid()) { if (check.is_valid()) {
++count; ++count;
} else { }
else {
std::cout << "IN"; std::cout << "IN";
} }
std::cout << "VALID: " << line << "\n"; std::cout << "VALID: " << line << "\n";

View File

@@ -3,12 +3,14 @@
#include <string> #include <string>
#include <vector> #include <vector>
std::string rotate(std::string const &s, std::string::size_type amount) { std::string rotate(std::string const& s, std::string::size_type amount)
{
auto length = s.length(); auto length = s.length();
return (s + s).substr(amount % length, length); return (s + s).substr(amount % length, length);
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
unsigned count = 0; unsigned count = 0;
std::string::size_type rotation = 0; std::string::size_type rotation = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {

View File

@@ -3,12 +3,14 @@
#include <string> #include <string>
#include <vector> #include <vector>
std::string rotate(std::string const &s, std::string::size_type amount) { std::string rotate(std::string const& s, std::string::size_type amount)
{
auto length = s.length(); auto length = s.length();
return (s + s).substr(amount % length, length); return (s + s).substr(amount % length, length);
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
if (argc != 3) { if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " <right> <down>\n"; std::cerr << "Usage: " << argv[0] << " <right> <down>\n";
return 1; return 1;

View File

@@ -6,7 +6,8 @@
using StringSet = std::set<std::string>; using StringSet = std::set<std::string>;
namespace { namespace {
StringSet parse_line(std::string const &str) { StringSet parse_line(std::string const& str)
{
StringSet result; StringSet result;
std::string::size_type pos = 0; std::string::size_type pos = 0;
@@ -28,20 +29,21 @@ StringSet parse_line(std::string const &str) {
const StringSet mandatory{"byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"}; const StringSet mandatory{"byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"};
const StringSet optional{"cid"}; const StringSet optional{"cid"};
bool is_valid_passport(StringSet const &mandatory_found) { bool is_valid_passport(StringSet const& mandatory_found)
{
return mandatory_found.size() == mandatory.size(); return mandatory_found.size() == mandatory.size();
} }
} // namespace } // namespace
int main(int argc, char **argv) { int main(int argc, char** argv)
{
StringSet mandatory_found; StringSet mandatory_found;
StringSet optional_found; StringSet optional_found;
unsigned valid = 0; unsigned valid = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
if (!line.empty()) { if (!line.empty()) {
auto keys = parse_line(line); auto keys = parse_line(line);
for (auto const &key : keys) { for (auto const& key : keys) {
std::cout << "Key " << key << " is "; std::cout << "Key " << key << " is ";
if (mandatory.find(key) != mandatory.end()) { if (mandatory.find(key) != mandatory.end()) {
auto [it, success] = mandatory_found.insert(key); auto [it, success] = mandatory_found.insert(key);
@@ -49,18 +51,21 @@ int main(int argc, char **argv) {
if (!success) { if (!success) {
std::cout << " (duplicate)"; std::cout << " (duplicate)";
} }
} else if (optional.find(key) != optional.end()) { }
else if (optional.find(key) != optional.end()) {
auto [it, success] = optional_found.insert(key); auto [it, success] = optional_found.insert(key);
std::cout << "optional"; std::cout << "optional";
if (!success) { if (!success) {
std::cout << " (duplicate)"; std::cout << " (duplicate)";
} }
} else { }
else {
std::cout << "unexpected"; std::cout << "unexpected";
} }
std::cout << "\n"; std::cout << "\n";
} }
} else { }
else {
valid += is_valid_passport(mandatory_found); valid += is_valid_passport(mandatory_found);
mandatory_found.clear(); mandatory_found.clear();
optional_found.clear(); optional_found.clear();

View File

@@ -8,7 +8,7 @@
// Various types that are useful // Various types that are useful
using StringSet = std::set<std::string>; using StringSet = std::set<std::string>;
using StringMap = std::map<std::string, std::string>; using StringMap = std::map<std::string, std::string>;
using ValidateFn = std::function<bool(std::string const &)>; using ValidateFn = std::function<bool(std::string const&)>;
using ValidateMap = std::map<std::string, ValidateFn>; using ValidateMap = std::map<std::string, ValidateFn>;
namespace { namespace {
@@ -19,7 +19,8 @@ namespace {
* \a str is expected to look like a space separated list of pairs where each * \a str is expected to look like a space separated list of pairs where each
* pair is of the form 'key:value'. * pair is of the form 'key:value'.
*/ */
StringMap parse_line(std::string const &str) { StringMap parse_line(std::string const& str)
{
StringMap result; StringMap result;
std::string::size_type pos = 0; std::string::size_type pos = 0;
@@ -32,9 +33,8 @@ StringMap parse_line(std::string const &str) {
assert(colon_pos != std::string::npos); assert(colon_pos != std::string::npos);
assert(colon_pos < end_pos); assert(colon_pos < end_pos);
auto key_len = colon_pos - pos; auto key_len = colon_pos - pos;
auto value_len = (end_pos == std::string::npos) auto value_len =
? std::string::npos (end_pos == std::string::npos) ? std::string::npos : (end_pos - (colon_pos + 1));
: (end_pos - (colon_pos + 1));
auto key = str.substr(pos, key_len); auto key = str.substr(pos, key_len);
auto value = str.substr(colon_pos + 1, value_len); auto value = str.substr(colon_pos + 1, value_len);
result.insert({key, value}); result.insert({key, value});
@@ -50,7 +50,8 @@ StringMap parse_line(std::string const &str) {
* \param max Maximum year to accept * \param max Maximum year to accept
* \return True if \a s is in range [min, max] * \return True if \a s is in range [min, max]
*/ */
bool validate_year(std::string const &s, unsigned min, unsigned max) { bool validate_year(std::string const& s, unsigned min, unsigned max)
{
if (s.length() != 4) { if (s.length() != 4) {
return false; return false;
} }
@@ -63,16 +64,17 @@ bool validate_year(std::string const &s, unsigned min, unsigned max) {
} }
/// Validate byr field /// Validate byr field
bool validate_byr(std::string const &s) { return validate_year(s, 1920, 2002); } bool validate_byr(std::string const& s) { return validate_year(s, 1920, 2002); }
/// Validate iyr field /// Validate iyr field
bool validate_iyr(std::string const &s) { return validate_year(s, 2010, 2020); } bool validate_iyr(std::string const& s) { return validate_year(s, 2010, 2020); }
/// Validate eyr field /// Validate eyr field
bool validate_eyr(std::string const &s) { return validate_year(s, 2020, 2030); } bool validate_eyr(std::string const& s) { return validate_year(s, 2020, 2030); }
/// Validate hgt field /// Validate hgt field
bool validate_hgt(std::string const &s) { bool validate_hgt(std::string const& s)
{
std::size_t pos = 0; std::size_t pos = 0;
auto hgt = std::stoul(s, &pos, 10); auto hgt = std::stoul(s, &pos, 10);
if (pos != s.length() - 2) { if (pos != s.length() - 2) {
@@ -80,7 +82,8 @@ bool validate_hgt(std::string const &s) {
} }
if (s[pos] == 'c' && s[pos + 1] == 'm') { if (s[pos] == 'c' && s[pos + 1] == 'm') {
return hgt >= 150 && hgt <= 193; return hgt >= 150 && hgt <= 193;
} else if (s[pos] == 'i' && s[pos + 1] == 'n') { }
else if (s[pos] == 'i' && s[pos + 1] == 'n') {
return hgt >= 59 && hgt <= 76; return hgt >= 59 && hgt <= 76;
} }
return false; return false;
@@ -92,8 +95,8 @@ bool validate_hgt(std::string const &s) {
* \param cs Valid characters * \param cs Valid characters
* \return True iff we pass validation * \return True iff we pass validation
*/ */
bool validate_chars(std::string const &s, std::string::size_type len, bool validate_chars(std::string const& s, std::string::size_type len, std::string const& cs)
std::string const &cs) { {
if (s.length() != len) { if (s.length() != len) {
return false; return false;
} }
@@ -107,7 +110,8 @@ bool validate_chars(std::string const &s, std::string::size_type len,
} }
/// Validate hcl field /// Validate hcl field
bool validate_hcl(std::string const &s) { bool validate_hcl(std::string const& s)
{
if (s.length() != 7) { if (s.length() != 7) {
return false; return false;
} }
@@ -118,46 +122,43 @@ bool validate_hcl(std::string const &s) {
} }
/// Validate ecl field /// Validate ecl field
bool validate_ecl(std::string const &s) { bool validate_ecl(std::string const& s)
static const StringSet valid = {"amb", "blu", "brn", "gry", {
"grn", "hzl", "oth"}; static const StringSet valid = {"amb", "blu", "brn", "gry", "grn", "hzl", "oth"};
return valid.find(s) != valid.end(); return valid.find(s) != valid.end();
} }
/// Validate pid field /// Validate pid field
bool validate_pid(std::string const &s) { bool validate_pid(std::string const& s) { return validate_chars(s, 9, "0123456789"); }
return validate_chars(s, 9, "0123456789");
}
/// Validate cid field /// Validate cid field
bool validate_cid(std::string const &s) { return true; } bool validate_cid(std::string const& s) { return true; }
/// Check if a passport is valid /// Check if a passport is valid
/// ///
/// A passport is valid if it contains all mandatory fields, and passes /// A passport is valid if it contains all mandatory fields, and passes
/// validation on all fields. /// validation on all fields.
bool is_valid_passport(StringMap const &found) { bool is_valid_passport(StringMap const& found)
static const StringSet mandatory{"byr", "iyr", "eyr", "hgt", {
"hcl", "ecl", "pid"}; static const StringSet mandatory{"byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"};
static const ValidateMap validators{ static const ValidateMap validators{
{"byr", validate_byr}, {"iyr", validate_iyr}, {"eyr", validate_eyr}, {"byr", validate_byr}, {"iyr", validate_iyr}, {"eyr", validate_eyr}, {"hgt", validate_hgt},
{"hgt", validate_hgt}, {"hcl", validate_hcl}, {"ecl", validate_ecl}, {"hcl", validate_hcl}, {"ecl", validate_ecl}, {"pid", validate_pid}, {"cid", validate_cid},
{"pid", validate_pid}, {"cid", validate_cid},
}; };
unsigned mandatory_found = 0; unsigned mandatory_found = 0;
for (auto const &kv : found) { for (auto const& kv : found) {
if (mandatory.find(kv.first) != mandatory.end()) { if (mandatory.find(kv.first) != mandatory.end()) {
++mandatory_found; ++mandatory_found;
} }
auto validator = validators.find(kv.first); auto validator = validators.find(kv.first);
if (validator == validators.end()) { if (validator == validators.end()) {
std::cout << "Found invalid key: " << kv.first << "\n"; std::cout << "Found invalid key: " << kv.first << "\n";
} else { }
else {
auto valid = validator->second(kv.second); auto valid = validator->second(kv.second);
if (!valid) { if (!valid) {
std::cout << "Invalid value for key: " << kv.first << ": " << kv.second std::cout << "Invalid value for key: " << kv.first << ": " << kv.second << "\n";
<< "\n";
return false; return false;
} }
} }
@@ -167,15 +168,16 @@ bool is_valid_passport(StringMap const &found) {
} }
} // namespace } // namespace
int main(int argc, char **argv) { int main(int argc, char** argv)
{
StringMap found; StringMap found;
unsigned valid = 0; unsigned valid = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
if (!line.empty()) { if (!line.empty()) {
auto keys = parse_line(line); auto keys = parse_line(line);
found.insert(keys.begin(), keys.end()); found.insert(keys.begin(), keys.end());
} else { }
else {
valid += is_valid_passport(found); valid += is_valid_passport(found);
found.clear(); found.clear();
} }

View File

@@ -9,8 +9,9 @@
* \param s String to parse, must be L2 characters long * \param s String to parse, must be L2 characters long
* \return Position described by s. * \return Position described by s.
*/ */
template <unsigned L2, char LOWER, char UPPER> template<unsigned L2, char LOWER, char UPPER>
unsigned find_pos(std::string const &s) { unsigned find_pos(std::string const& s)
{
assert(s.length() == L2); assert(s.length() == L2);
unsigned low = 0; unsigned low = 0;
unsigned high = 1 << L2; unsigned high = 1 << L2;
@@ -20,9 +21,11 @@ unsigned find_pos(std::string const &s) {
assert(width != 0); assert(width != 0);
if (c == LOWER) { if (c == LOWER) {
high = low + width; high = low + width;
} else if (c == UPPER) { }
else if (c == UPPER) {
low = low + width; low = low + width;
} else { }
else {
assert(false); assert(false);
} }
width >>= 1; width >>= 1;
@@ -32,13 +35,15 @@ unsigned find_pos(std::string const &s) {
return low; return low;
} }
template <unsigned L2R, unsigned L2C> struct Seat { template<unsigned L2R, unsigned L2C>
Seat(std::string const &s) { struct Seat
{
Seat(std::string const& s)
{
assert(s.length() == L2R + L2C); assert(s.length() == L2R + L2C);
row_ = find_pos<L2R, 'F', 'B'>(s.substr(0, L2R)); row_ = find_pos<L2R, 'F', 'B'>(s.substr(0, L2R));
col_ = find_pos<L2C, 'L', 'R'>(s.substr(L2R, L2C)); col_ = find_pos<L2C, 'L', 'R'>(s.substr(L2R, L2C));
std::cout << s << ": row " << row_ << ", column " << col_ << ", seat ID " std::cout << s << ": row " << row_ << ", column " << col_ << ", seat ID " << id() << ".\n";
<< id() << ".\n";
} }
unsigned id() const noexcept { return row_ * (1 << L2C) + col_; } unsigned id() const noexcept { return row_ * (1 << L2C) + col_; }
@@ -47,7 +52,8 @@ template <unsigned L2R, unsigned L2C> struct Seat {
unsigned col_; unsigned col_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
unsigned max_id = 0; unsigned max_id = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {

View File

@@ -15,8 +15,9 @@
* We don't need to keep a record of high at all so the original solution * We don't need to keep a record of high at all so the original solution
* was over enthusiastic. * was over enthusiastic.
*/ */
template <unsigned L2, char LOWER, char UPPER> template<unsigned L2, char LOWER, char UPPER>
unsigned find_pos(std::string const &s) { unsigned find_pos(std::string const& s)
{
assert(s.length() == L2); assert(s.length() == L2);
unsigned low = 0; unsigned low = 0;
unsigned width = 1 << (L2 - 1); unsigned width = 1 << (L2 - 1);
@@ -25,7 +26,8 @@ unsigned find_pos(std::string const &s) {
assert(width != 0); assert(width != 0);
if (c == UPPER) { if (c == UPPER) {
low = low + width; low = low + width;
} else { }
else {
assert(c == LOWER); assert(c == LOWER);
} }
@@ -40,8 +42,9 @@ unsigned find_pos(std::string const &s) {
* \tparam L2R log 2 number of rows * \tparam L2R log 2 number of rows
* \tparam L2C log 2 number of columns * \tparam L2C log 2 number of columns
*/ */
template <unsigned L2R, unsigned L2C> struct Seat { template<unsigned L2R, unsigned L2C>
struct Seat
{
/** \brief Construct the seat. /** \brief Construct the seat.
* \param s String representing seat location, must be L2R + L2C chars. * \param s String representing seat location, must be L2R + L2C chars.
* *
@@ -52,12 +55,12 @@ template <unsigned L2R, unsigned L2C> struct Seat {
* *
* Should have used initialiser lists. * Should have used initialiser lists.
*/ */
Seat(std::string const &s) Seat(std::string const& s)
: row_(find_pos<L2R, 'F', 'B'>(s.substr(0, L2R))), : row_(find_pos<L2R, 'F', 'B'>(s.substr(0, L2R))),
col_(find_pos<L2C, 'L', 'R'>(s.substr(L2R, L2C))) { col_(find_pos<L2C, 'L', 'R'>(s.substr(L2R, L2C)))
{
assert(s.length() == L2R + L2C); assert(s.length() == L2R + L2C);
std::cout << s << ": row " << row_ << ", column " << col_ << ", seat ID " std::cout << s << ": row " << row_ << ", column " << col_ << ", seat ID " << id() << ".\n";
<< id() << ".\n";
} }
/** Get seat ID. */ /** Get seat ID. */
@@ -73,7 +76,8 @@ template <unsigned L2R, unsigned L2C> struct Seat {
* *
* Could have initialised the array better. * Could have initialised the array better.
*/ */
int main(int argc, char **argv) { int main(int argc, char** argv)
{
constexpr unsigned l2r = 7; ///< Log 2 number of rows constexpr unsigned l2r = 7; ///< Log 2 number of rows
constexpr unsigned l2c = 3; ///< Log 2 number of columns constexpr unsigned l2c = 3; ///< Log 2 number of columns
constexpr unsigned max_id = 1 << (l2r + l2c); ///< Max ID. constexpr unsigned max_id = 1 << (l2r + l2c); ///< Max ID.

View File

@@ -5,7 +5,8 @@
// Merge two strings of answers, preserving order and ensuring uniqueness of // Merge two strings of answers, preserving order and ensuring uniqueness of
// each answer. // each answer.
std::string merge_answers(std::string const &a, std::string const &b) { std::string merge_answers(std::string const& a, std::string const& b)
{
std::string result; std::string result;
std::string::size_type pos_a = 0; std::string::size_type pos_a = 0;
std::string::size_type pos_b = 0; std::string::size_type pos_b = 0;
@@ -13,10 +14,12 @@ std::string merge_answers(std::string const &a, std::string const &b) {
if (a[pos_a] < b[pos_b]) { if (a[pos_a] < b[pos_b]) {
result += a[pos_a]; result += a[pos_a];
++pos_a; ++pos_a;
} else if (b[pos_b] < a[pos_a]) { }
else if (b[pos_b] < a[pos_a]) {
result += b[pos_b]; result += b[pos_b];
++pos_b; ++pos_b;
} else { }
else {
assert(a[pos_a] == b[pos_b]); assert(a[pos_a] == b[pos_b]);
result += a[pos_a]; result += a[pos_a];
++pos_a; ++pos_a;
@@ -29,23 +32,22 @@ std::string merge_answers(std::string const &a, std::string const &b) {
return result; return result;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string current_answers; std::string current_answers;
unsigned count = 0; unsigned count = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
if (!line.empty()) { if (!line.empty()) {
std::sort(line.begin(), line.end()); std::sort(line.begin(), line.end());
current_answers = merge_answers(current_answers, line); current_answers = merge_answers(current_answers, line);
} else { }
std::cout << "Length of " << current_answers << " = " else {
<< current_answers.length() << "\n"; std::cout << "Length of " << current_answers << " = " << current_answers.length() << "\n";
count += current_answers.length(); count += current_answers.length();
current_answers.clear(); current_answers.clear();
} }
} }
std::cout << "Length of " << current_answers << " = " std::cout << "Length of " << current_answers << " = " << current_answers.length() << "\n";
<< current_answers.length() << "\n";
count += current_answers.length(); count += current_answers.length();
std::cout << "Total length = " << count << "\n"; std::cout << "Total length = " << count << "\n";

View File

@@ -6,8 +6,10 @@
using OccuranceMap = std::map<char, unsigned>; using OccuranceMap = std::map<char, unsigned>;
struct GroupAnswers { struct GroupAnswers
void add_answers(std::string const &a) { {
void add_answers(std::string const& a)
{
// Increase group size // Increase group size
++group_size_; ++group_size_;
@@ -16,14 +18,16 @@ struct GroupAnswers {
auto it = map_.find(c); auto it = map_.find(c);
if (it == map_.end()) { if (it == map_.end()) {
map_.insert({c, 1}); map_.insert({c, 1});
} else { }
else {
++(it->second); ++(it->second);
} }
} }
} }
// Count the number of answered questions answered by everyone. // Count the number of answered questions answered by everyone.
unsigned all_answer_count() const noexcept { unsigned all_answer_count() const noexcept
{
unsigned count = 0; unsigned count = 0;
for (auto kv : map_) { for (auto kv : map_) {
if (kv.second == group_size_) { if (kv.second == group_size_) {
@@ -34,7 +38,8 @@ struct GroupAnswers {
return count; return count;
} }
void clear() { void clear()
{
map_.clear(); map_.clear();
group_size_ = 0; group_size_ = 0;
} }
@@ -43,13 +48,15 @@ struct GroupAnswers {
unsigned group_size_ = 0; unsigned group_size_ = 0;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
GroupAnswers answers; GroupAnswers answers;
unsigned count = 0; unsigned count = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
if (!line.empty()) { if (!line.empty()) {
answers.add_answers(line); answers.add_answers(line);
} else { }
else {
count += answers.all_answer_count(); count += answers.all_answer_count();
answers.clear(); answers.clear();
} }

View File

@@ -15,10 +15,11 @@ using Weight = unsigned;
using EdgeWeights = std::map<Edge, Weight>; using EdgeWeights = std::map<Edge, Weight>;
using NodeQueue = std::list<Node>; using NodeQueue = std::list<Node>;
std::ostream &operator<<(std::ostream &os, NodeQueue const &q) { std::ostream& operator<<(std::ostream& os, NodeQueue const& q)
{
std::string p = ""; std::string p = "";
os << "["; os << "[";
for (auto const &n : q) { for (auto const& n : q) {
os << p << n; os << p << n;
p = ", "; p = ", ";
} }
@@ -26,10 +27,12 @@ std::ostream &operator<<(std::ostream &os, NodeQueue const &q) {
return os; return os;
} }
struct BagGraph { struct BagGraph
{
BagGraph() { nodes_.insert({"", false}); } BagGraph() { nodes_.insert({"", false}); }
void add_edges(std::string const &s) { void add_edges(std::string const& s)
{
static const auto prefix_re = std::regex("([a-z ]+) bags? contain "); static const auto prefix_re = std::regex("([a-z ]+) bags? contain ");
static const auto suffix_re = std::regex("(\\d)+ ([a-z ]+) bags?[,.]\\s*"); static const auto suffix_re = std::regex("(\\d)+ ([a-z ]+) bags?[,.]\\s*");
static const auto empty_str = std::string("no other bags."); static const auto empty_str = std::string("no other bags.");
@@ -49,7 +52,8 @@ struct BagGraph {
Edge e = std::make_pair("", n2); Edge e = std::make_pair("", n2);
edges_.insert({e, 0}); edges_.insert({e, 0});
std::cout << "<none> -> " << n2 << ": 0\n"; std::cout << "<none> -> " << n2 << ": 0\n";
} else { }
else {
std::smatch suffix_m; std::smatch suffix_m;
if (!std::regex_search(suffix, suffix_m, suffix_re)) { if (!std::regex_search(suffix, suffix_m, suffix_re)) {
std::cout << "Failed to match: " << suffix << "\n"; std::cout << "Failed to match: " << suffix << "\n";
@@ -67,7 +71,8 @@ struct BagGraph {
} }
} }
unsigned num_containers(Node const &n) { unsigned num_containers(Node const& n)
{
NodeQueue queue; NodeQueue queue;
// Initial population of queue: // Initial population of queue:
populate_queue(queue, n); populate_queue(queue, n);
@@ -84,7 +89,8 @@ struct BagGraph {
populate_queue(queue, n1); populate_queue(queue, n1);
++visited; ++visited;
std::cout << "Updated queue: " << queue << "\n"; std::cout << "Updated queue: " << queue << "\n";
} else { }
else {
std::cout << "Already visited\n"; std::cout << "Already visited\n";
} }
} }
@@ -93,8 +99,9 @@ struct BagGraph {
} }
private: private:
void populate_queue(NodeQueue &queue, Node const &n) { void populate_queue(NodeQueue& queue, Node const& n)
for (auto const &kv : edges_) { {
for (auto const& kv : edges_) {
if (kv.first.first == n && !nodes_[kv.first.second]) { if (kv.first.first == n && !nodes_[kv.first.second]) {
queue.push_back(kv.first.second); queue.push_back(kv.first.second);
} }
@@ -105,7 +112,8 @@ private:
Nodes nodes_; Nodes nodes_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
BagGraph bg; BagGraph bg;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
bg.add_edges(line); bg.add_edges(line);

View File

@@ -13,8 +13,10 @@ using Edge = std::pair<Node, Node>;
using Weight = unsigned; using Weight = unsigned;
using EdgeWeights = std::map<Edge, Weight>; using EdgeWeights = std::map<Edge, Weight>;
struct BagGraph { struct BagGraph
void add_edges(std::string const &s) { {
void add_edges(std::string const& s)
{
static const auto prefix_re = std::regex("([a-z ]+) bags? contain "); static const auto prefix_re = std::regex("([a-z ]+) bags? contain ");
static const auto suffix_re = std::regex("(\\d)+ ([a-z ]+) bags?[,.]\\s*"); static const auto suffix_re = std::regex("(\\d)+ ([a-z ]+) bags?[,.]\\s*");
static const auto empty_str = std::string("no other bags."); static const auto empty_str = std::string("no other bags.");
@@ -31,7 +33,8 @@ struct BagGraph {
if (suffix == empty_str) { if (suffix == empty_str) {
std::cout << n1 << " -> none: <empty>\n"; std::cout << n1 << " -> none: <empty>\n";
suffix.clear(); suffix.clear();
} else { }
else {
std::smatch suffix_m; std::smatch suffix_m;
if (!std::regex_search(suffix, suffix_m, suffix_re)) { if (!std::regex_search(suffix, suffix_m, suffix_re)) {
std::cout << "Failed to match: " << suffix << "\n"; std::cout << "Failed to match: " << suffix << "\n";
@@ -48,17 +51,19 @@ struct BagGraph {
} }
} }
Weight num_contained(Node const &n) { Weight num_contained(Node const& n)
{
// Get the number of bags including the node we've been asked for so the // Get the number of bags including the node we've been asked for so the
// result is 1 less than the internal result // result is 1 less than the internal result
return num_contained1(n) - 1; return num_contained1(n) - 1;
} }
private: private:
Weight num_contained1(Node const &n) { Weight num_contained1(Node const& n)
{
Weight w = 0; Weight w = 0;
bool contains_something = false; bool contains_something = false;
for (auto const &kv : edges_) { for (auto const& kv : edges_) {
if (kv.first.first == n) { if (kv.first.first == n) {
w += kv.second * num_contained1(kv.first.second); w += kv.second * num_contained1(kv.first.second);
contains_something = true; contains_something = true;
@@ -70,7 +75,8 @@ private:
EdgeWeights edges_; EdgeWeights edges_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
BagGraph bg; BagGraph bg;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
bg.add_edges(line); bg.add_edges(line);

View File

@@ -9,36 +9,43 @@
enum class Opcode { Acc, Jmp, Nop }; enum class Opcode { Acc, Jmp, Nop };
using Value = int; using Value = int;
struct Instruction { struct Instruction
Instruction(std::string const &s) {
: op_(to_opcode(s.substr(0, 3))), v_(to_value(s.substr(4))) {} Instruction(std::string const& s) : op_(to_opcode(s.substr(0, 3))), v_(to_value(s.substr(4))) {}
Opcode opcode() const noexcept { return op_; } Opcode opcode() const noexcept { return op_; }
Value value() const noexcept { return v_; } Value value() const noexcept { return v_; }
private: private:
Opcode to_opcode(std::string const &s) { Opcode to_opcode(std::string const& s)
{
if (s == "acc") { if (s == "acc") {
return Opcode::Acc; return Opcode::Acc;
} else if (s == "jmp") { }
else if (s == "jmp") {
return Opcode::Jmp; return Opcode::Jmp;
} else if (s == "nop") { }
else if (s == "nop") {
return Opcode::Nop; return Opcode::Nop;
} else { }
else {
assert(false); assert(false);
return Opcode::Nop; return Opcode::Nop;
} }
} }
Value to_value(std::string const &s) { Value to_value(std::string const& s)
{
int sign = 0; int sign = 0;
int v = 0; int v = 0;
std::size_t pos = 0; std::size_t pos = 0;
if (s[0] == '+') { if (s[0] == '+') {
sign = 1; sign = 1;
} else if (s[0] == '-') { }
else if (s[0] == '-') {
sign = -1; sign = -1;
} else { }
else {
assert(false); assert(false);
} }
v = std::stoi(s.substr(1), &pos); v = std::stoi(s.substr(1), &pos);
@@ -50,7 +57,8 @@ private:
Value v_; Value v_;
}; };
std::ostream &operator<<(std::ostream &os, Instruction const &i) { std::ostream& operator<<(std::ostream& os, Instruction const& i)
{
switch (i.opcode()) { switch (i.opcode()) {
case Opcode::Acc: case Opcode::Acc:
os << "acc"; os << "acc";
@@ -74,15 +82,18 @@ std::ostream &operator<<(std::ostream &os, Instruction const &i) {
} }
using Instructions = std::vector<Instruction>; using Instructions = std::vector<Instruction>;
struct VM { struct VM
{
VM() : pc_(0), acc_(0) {} VM() : pc_(0), acc_(0) {}
void add_instruction(Instruction const &i) { void add_instruction(Instruction const& i)
{
std::cout << i << "\n"; std::cout << i << "\n";
instrs_.push_back(i); instrs_.push_back(i);
} }
void execute() { void execute()
{
std::vector<bool> seen(instrs_.size(), false); std::vector<bool> seen(instrs_.size(), false);
while (!seen[pc_]) { while (!seen[pc_]) {
assert(pc_ < instrs_.size()); assert(pc_ < instrs_.size());
@@ -96,7 +107,8 @@ struct VM {
Value acc() const noexcept { return acc_; } Value acc() const noexcept { return acc_; }
private: private:
void execute(Instruction const &i) { void execute(Instruction const& i)
{
std::cout << pc_ << ": " << i; std::cout << pc_ << ": " << i;
switch (i.opcode()) { switch (i.opcode()) {
case Opcode::Acc: case Opcode::Acc:
@@ -120,7 +132,8 @@ private:
Value acc_; Value acc_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
VM vm; VM vm;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
vm.add_instruction(Instruction(line)); vm.add_instruction(Instruction(line));

View File

@@ -9,13 +9,14 @@
enum class Opcode { Acc, Jmp, Nop }; enum class Opcode { Acc, Jmp, Nop };
using Value = int; using Value = int;
struct Instruction { struct Instruction
Instruction(std::string const &s) {
: op_(to_opcode(s.substr(0, 3))), v_(to_value(s.substr(4))) {} Instruction(std::string const& s) : op_(to_opcode(s.substr(0, 3))), v_(to_value(s.substr(4))) {}
Opcode opcode() const noexcept { return op_; } Opcode opcode() const noexcept { return op_; }
Value value() const noexcept { return v_; } Value value() const noexcept { return v_; }
bool flip_jmp() { bool flip_jmp()
{
switch (op_) { switch (op_) {
case Opcode::Acc: case Opcode::Acc:
return false; return false;
@@ -31,28 +32,35 @@ struct Instruction {
} }
private: private:
Opcode to_opcode(std::string const &s) { Opcode to_opcode(std::string const& s)
{
if (s == "acc") { if (s == "acc") {
return Opcode::Acc; return Opcode::Acc;
} else if (s == "jmp") { }
else if (s == "jmp") {
return Opcode::Jmp; return Opcode::Jmp;
} else if (s == "nop") { }
else if (s == "nop") {
return Opcode::Nop; return Opcode::Nop;
} else { }
else {
assert(false); assert(false);
return Opcode::Nop; return Opcode::Nop;
} }
} }
Value to_value(std::string const &s) { Value to_value(std::string const& s)
{
int sign = 0; int sign = 0;
int v = 0; int v = 0;
std::size_t pos = 0; std::size_t pos = 0;
if (s[0] == '+') { if (s[0] == '+') {
sign = 1; sign = 1;
} else if (s[0] == '-') { }
else if (s[0] == '-') {
sign = -1; sign = -1;
} else { }
else {
assert(false); assert(false);
} }
v = std::stoi(s.substr(1), &pos); v = std::stoi(s.substr(1), &pos);
@@ -64,7 +72,8 @@ private:
Value v_; Value v_;
}; };
std::ostream &operator<<(std::ostream &os, Instruction const &i) { std::ostream& operator<<(std::ostream& os, Instruction const& i)
{
switch (i.opcode()) { switch (i.opcode()) {
case Opcode::Acc: case Opcode::Acc:
os << "acc"; os << "acc";
@@ -88,15 +97,18 @@ std::ostream &operator<<(std::ostream &os, Instruction const &i) {
} }
using Instructions = std::vector<Instruction>; using Instructions = std::vector<Instruction>;
struct VM { struct VM
{
VM() : pc_(0), acc_(0) {} VM() : pc_(0), acc_(0) {}
void add_instruction(Instruction const &i) { void add_instruction(Instruction const& i)
{
std::cout << i << "\n"; std::cout << i << "\n";
instrs_.push_back(i); instrs_.push_back(i);
} }
bool execute() { bool execute()
{
std::vector<bool> seen(instrs_.size(), false); std::vector<bool> seen(instrs_.size(), false);
acc_ = 0; acc_ = 0;
pc_ = 0; pc_ = 0;
@@ -114,12 +126,12 @@ struct VM {
return false; return false;
} }
void find_fix() { void find_fix()
{
for (std::size_t pos = 0; pos < instrs_.size(); ++pos) { for (std::size_t pos = 0; pos < instrs_.size(); ++pos) {
if (instrs_[pos].flip_jmp()) { if (instrs_[pos].flip_jmp()) {
if (execute()) { if (execute()) {
std::cout << "Success at instruction " << pos << ": " << instrs_[pos] std::cout << "Success at instruction " << pos << ": " << instrs_[pos] << "\n";
<< "\n";
return; return;
} }
instrs_[pos].flip_jmp(); instrs_[pos].flip_jmp();
@@ -130,7 +142,8 @@ struct VM {
Value acc() const noexcept { return acc_; } Value acc() const noexcept { return acc_; }
private: private:
void execute(Instruction const &i) { void execute(Instruction const& i)
{
std::cout << pc_ << ": " << i; std::cout << pc_ << ": " << i;
switch (i.opcode()) { switch (i.opcode()) {
case Opcode::Acc: case Opcode::Acc:
@@ -154,7 +167,8 @@ private:
Value acc_; Value acc_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
VM vm; VM vm;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
vm.add_instruction(Instruction(line)); vm.add_instruction(Instruction(line));

View File

@@ -6,10 +6,13 @@
#include <regex> #include <regex>
#include <string> #include <string>
template <std::size_t L> struct Buffer { template<std::size_t L>
struct Buffer
{
Buffer() {} Buffer() {}
bool add_value(std::string const &s) { bool add_value(std::string const& s)
{
unsigned long i = std::stoul(s); unsigned long i = std::stoul(s);
auto size = buf_.size(); auto size = buf_.size();
if (size == L && !valid(i)) { if (size == L && !valid(i)) {
@@ -23,7 +26,8 @@ template <std::size_t L> struct Buffer {
} }
private: private:
bool valid(unsigned long v) const { bool valid(unsigned long v) const
{
assert(buf_.size() == L); assert(buf_.size() == L);
for (auto i = buf_.begin(); i != buf_.end(); ++i) { for (auto i = buf_.begin(); i != buf_.end(); ++i) {
auto j = i; auto j = i;
@@ -41,7 +45,8 @@ private:
std::list<unsigned long> buf_; std::list<unsigned long> buf_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Buffer<25> buf; Buffer<25> buf;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
if (!buf.add_value(line)) { if (!buf.add_value(line)) {

View File

@@ -6,10 +6,13 @@
#include <regex> #include <regex>
#include <string> #include <string>
template <std::size_t L> struct Buffer { template<std::size_t L>
struct Buffer
{
Buffer() {} Buffer() {}
bool add_value(std::string const &s) { bool add_value(std::string const& s)
{
unsigned long i = std::stoul(s); unsigned long i = std::stoul(s);
bool result = true; bool result = true;
auto size = buf_.size(); auto size = buf_.size();
@@ -20,7 +23,8 @@ template <std::size_t L> struct Buffer {
return result; return result;
} }
unsigned long get_weakness(unsigned long v) { unsigned long get_weakness(unsigned long v)
{
std::size_t sum_begin = 0; std::size_t sum_begin = 0;
std::size_t sum_end = 0; std::size_t sum_end = 0;
unsigned long sum = 0; unsigned long sum = 0;
@@ -36,16 +40,15 @@ template <std::size_t L> struct Buffer {
++sum_begin; ++sum_begin;
} }
} }
std::cout << "sum_begin = " << sum_begin << " sum_end = " << sum_end std::cout << "sum_begin = " << sum_begin << " sum_end = " << sum_end << "\n";
<< "\n"; std::vector<unsigned long> vec(buf_.begin() + sum_begin, buf_.begin() + sum_end);
std::vector<unsigned long> vec(buf_.begin() + sum_begin,
buf_.begin() + sum_end);
std::sort(vec.begin(), vec.end()); std::sort(vec.begin(), vec.end());
return vec[0] + vec[vec.size() - 1]; return vec[0] + vec[vec.size() - 1];
} }
private: private:
bool valid(unsigned long v) const { bool valid(unsigned long v) const
{
assert(buf_.size() >= L); assert(buf_.size() >= L);
for (auto i = buf_.size() - 25; i != buf_.size(); ++i) { for (auto i = buf_.size() - 25; i != buf_.size(); ++i) {
for (auto j = i + 1; j != buf_.size(); ++j) { for (auto j = i + 1; j != buf_.size(); ++j) {
@@ -60,7 +63,8 @@ private:
std::vector<unsigned long> buf_; std::vector<unsigned long> buf_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Buffer<25> buf; Buffer<25> buf;
unsigned long invalid = 0; unsigned long invalid = 0;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {

View File

@@ -9,7 +9,8 @@
using Jolt = unsigned long; using Jolt = unsigned long;
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::vector<Jolt> jolts; std::vector<Jolt> jolts;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
jolts.push_back(std::stoul(line)); jolts.push_back(std::stoul(line));
@@ -26,7 +27,6 @@ int main(int argc, char **argv) {
// and the gap to our voltage // and the gap to our voltage
++gaps[3]; ++gaps[3];
std::cout << gaps[1] << " * " << gaps[3] << " = " << gaps[1] * gaps[3] std::cout << gaps[1] << " * " << gaps[3] << " = " << gaps[1] * gaps[3] << "\n";
<< "\n";
return 0; return 0;
} }

View File

@@ -9,7 +9,8 @@
using Jolt = unsigned long; using Jolt = unsigned long;
Jolt count_valid_combinations(std::vector<Jolt> const &jolts) { Jolt count_valid_combinations(std::vector<Jolt> const& jolts)
{
std::vector<Jolt> valid(jolts.size(), 0); std::vector<Jolt> valid(jolts.size(), 0);
valid[jolts.size() - 1] = 1; valid[jolts.size() - 1] = 1;
std::size_t i = jolts.size() - 1; std::size_t i = jolts.size() - 1;
@@ -27,7 +28,8 @@ Jolt count_valid_combinations(std::vector<Jolt> const &jolts) {
return valid[0]; return valid[0];
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::vector<Jolt> jolts; std::vector<Jolt> jolts;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {
jolts.push_back(std::stoul(line)); jolts.push_back(std::stoul(line));

View File

@@ -9,7 +9,8 @@
using Array = std::vector<std::string>; using Array = std::vector<std::string>;
char next_state(Array const &a, std::size_t row, std::size_t col) { char next_state(Array const& a, std::size_t row, std::size_t col)
{
unsigned occupied = 0; unsigned occupied = 0;
if (row > 0) { if (row > 0) {
if (col > 0) { if (col > 0) {
@@ -38,16 +39,19 @@ char next_state(Array const &a, std::size_t row, std::size_t col) {
if (a[row][col] == 'L' && occupied == 0) { if (a[row][col] == 'L' && occupied == 0) {
return '#'; return '#';
} else if (a[row][col] == '#' && occupied >= 4) { }
else if (a[row][col] == '#' && occupied >= 4) {
return 'L'; return 'L';
} else { }
else {
return a[row][col]; return a[row][col];
} }
} }
unsigned long count_occupied(Array const &a) { unsigned long count_occupied(Array const& a)
{
unsigned long count = 0; unsigned long count = 0;
for (auto const &row : a) { for (auto const& row : a) {
for (auto col : row) { for (auto col : row) {
count += (col == '#'); count += (col == '#');
} }
@@ -56,7 +60,8 @@ unsigned long count_occupied(Array const &a) {
return count; return count;
} }
unsigned long run_to_steady_state(Array const &a) { unsigned long run_to_steady_state(Array const& a)
{
Array current = a; Array current = a;
bool changed = true; bool changed = true;
unsigned i = 0; unsigned i = 0;
@@ -81,7 +86,8 @@ unsigned long run_to_steady_state(Array const &a) {
return count_occupied(current); return count_occupied(current);
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Array array; Array array;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {

View File

@@ -9,8 +9,8 @@
using Array = std::vector<std::string>; using Array = std::vector<std::string>;
unsigned search(Array const &a, std::size_t row, std::size_t col, int rd, unsigned search(Array const& a, std::size_t row, std::size_t col, int rd, int cd)
int cd) { {
int cr = (int)row; int cr = (int)row;
int cc = (int)col; int cc = (int)col;
while (true) { while (true) {
@@ -36,7 +36,8 @@ unsigned search(Array const &a, std::size_t row, std::size_t col, int rd,
assert(false); assert(false);
} }
char next_state(Array const &a, std::size_t row, std::size_t col) { char next_state(Array const& a, std::size_t row, std::size_t col)
{
unsigned occupied = 0; unsigned occupied = 0;
for (int row_delta = -1; row_delta < 2; ++row_delta) { for (int row_delta = -1; row_delta < 2; ++row_delta) {
for (int col_delta = -1; col_delta < 2; ++col_delta) { for (int col_delta = -1; col_delta < 2; ++col_delta) {
@@ -46,16 +47,19 @@ char next_state(Array const &a, std::size_t row, std::size_t col) {
if (a[row][col] == 'L' && occupied == 0) { if (a[row][col] == 'L' && occupied == 0) {
return '#'; return '#';
} else if (a[row][col] == '#' && occupied >= 5) { }
else if (a[row][col] == '#' && occupied >= 5) {
return 'L'; return 'L';
} else { }
else {
return a[row][col]; return a[row][col];
} }
} }
unsigned long count_occupied(Array const &a) { unsigned long count_occupied(Array const& a)
{
unsigned long count = 0; unsigned long count = 0;
for (auto const &row : a) { for (auto const& row : a) {
for (auto col : row) { for (auto col : row) {
count += (col == '#'); count += (col == '#');
} }
@@ -64,7 +68,8 @@ unsigned long count_occupied(Array const &a) {
return count; return count;
} }
unsigned long run_to_steady_state(Array const &a) { unsigned long run_to_steady_state(Array const& a)
{
Array current = a; Array current = a;
bool changed = true; bool changed = true;
unsigned i = 0; unsigned i = 0;
@@ -89,7 +94,8 @@ unsigned long run_to_steady_state(Array const &a) {
return count_occupied(current); return count_occupied(current);
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Array array; Array array;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {

View File

@@ -9,10 +9,12 @@
enum class Heading { North = 'N', East = 'E', South = 'S', West = 'W' }; enum class Heading { North = 'N', East = 'E', South = 'S', West = 'W' };
struct Position { struct Position
{
Position() : x_(0), y_(0), head_(Heading::East) {} Position() : x_(0), y_(0), head_(Heading::East) {}
void move(std::string const &s) { void move(std::string const& s)
{
char act = s[0]; char act = s[0];
int dist = std::stoi(s.substr(1)); int dist = std::stoi(s.substr(1));
@@ -39,7 +41,8 @@ struct Position {
std::cout << s << ": (" << x_ << ", " << y_ << ")\n"; std::cout << s << ": (" << x_ << ", " << y_ << ")\n";
} }
void move(int dist, Heading head) { void move(int dist, Heading head)
{
switch (head) { switch (head) {
case Heading::North: case Heading::North:
y_ += dist; y_ += dist;
@@ -59,7 +62,8 @@ struct Position {
} }
} }
void rotate_left(int deg) { void rotate_left(int deg)
{
/* We want the rang [-180, 180]. */ /* We want the rang [-180, 180]. */
while (deg < -180) { while (deg < -180) {
deg += 360; deg += 360;
@@ -85,7 +89,8 @@ struct Position {
default: default:
assert(false); assert(false);
} }
} else if (deg == 90) { }
else if (deg == 90) {
switch (head_) { switch (head_) {
case Heading::North: case Heading::North:
head_ = Heading::West; head_ = Heading::West;
@@ -102,7 +107,8 @@ struct Position {
default: default:
assert(false); assert(false);
} }
} else if (deg == 180 || deg == -180) { }
else if (deg == 180 || deg == -180) {
switch (head_) { switch (head_) {
case Heading::North: case Heading::North:
head_ = Heading::South; head_ = Heading::South;
@@ -119,7 +125,8 @@ struct Position {
default: default:
assert(false); assert(false);
} }
} else if (deg != 0) { }
else if (deg != 0) {
assert(false); assert(false);
} }
} }
@@ -131,7 +138,8 @@ struct Position {
Heading head_; Heading head_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Position pos; Position pos;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {

View File

@@ -9,10 +9,12 @@
enum class Heading { North = 'N', East = 'E', South = 'S', West = 'W' }; enum class Heading { North = 'N', East = 'E', South = 'S', West = 'W' };
struct Position { struct Position
{
Position() : x_(0), y_(0), wx_(10), wy_(1), head_(Heading::East) {} Position() : x_(0), y_(0), wx_(10), wy_(1), head_(Heading::East) {}
void move(std::string const &s) { void move(std::string const& s)
{
char act = s[0]; char act = s[0];
int dist = std::stoi(s.substr(1)); int dist = std::stoi(s.substr(1));
@@ -37,11 +39,12 @@ struct Position {
assert(false); assert(false);
} }
std::cout << s << ": Pos = (" << x_ << ", " << y_ << "), Way = (" << wx_ std::cout << s << ": Pos = (" << x_ << ", " << y_ << "), Way = (" << wx_ << ", " << wy_
<< ", " << wy_ << ")\n"; << ")\n";
} }
void move_way(int dist, Heading head) { void move_way(int dist, Heading head)
{
switch (head) { switch (head) {
case Heading::North: case Heading::North:
wy_ += dist; wy_ += dist;
@@ -61,7 +64,8 @@ struct Position {
} }
} }
void rotate_left(int deg) { void rotate_left(int deg)
{
/* We want the rang [-180, 180]. */ /* We want the rang [-180, 180]. */
while (deg < -180) { while (deg < -180) {
deg += 360; deg += 360;
@@ -75,15 +79,18 @@ struct Position {
int py = wy_; int py = wy_;
wx_ = py; wx_ = py;
wy_ = -px; wy_ = -px;
} else if (deg == 90) { }
else if (deg == 90) {
int px = wx_; int px = wx_;
int py = wy_; int py = wy_;
wx_ = -py; wx_ = -py;
wy_ = px; wy_ = px;
} else if (deg == 180 || deg == -180) { }
else if (deg == 180 || deg == -180) {
wx_ = -wx_; wx_ = -wx_;
wy_ = -wy_; wy_ = -wy_;
} else if (deg != 0) { }
else if (deg != 0) {
assert(false); assert(false);
} }
} }
@@ -97,7 +104,8 @@ struct Position {
Heading head_; Heading head_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Position pos; Position pos;
for (std::string line; std::getline(std::cin, line);) { for (std::string line; std::getline(std::cin, line);) {

View File

@@ -10,7 +10,8 @@
using Time = unsigned long; using Time = unsigned long;
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Time arrival; Time arrival;
Time closest = ULONG_MAX; Time closest = ULONG_MAX;
Time closest_id = 0; Time closest_id = 0;
@@ -36,8 +37,7 @@ int main(int argc, char **argv) {
if (next_departure_in == depart) { if (next_departure_in == depart) {
next_departure_in = 0; next_departure_in = 0;
} }
std::cout << "Bus #" << depart std::cout << "Bus #" << depart << " previous departure: " << (arrival / depart) * depart
<< " previous departure: " << (arrival / depart) * depart
<< ", next departure in: " << next_departure_in << "\n"; << ", next departure in: " << next_departure_in << "\n";
if (next_departure_in < closest) { if (next_departure_in < closest) {
closest = next_departure_in; closest = next_departure_in;
@@ -45,8 +45,7 @@ int main(int argc, char **argv) {
} }
} }
std::cout << "Next departure # " << closest_id << " in " << closest std::cout << "Next departure # " << closest_id << " in " << closest << " minutes.\n";
<< " minutes.\n";
std::cout << "Result = " << closest * closest_id << "\n"; std::cout << "Result = " << closest * closest_id << "\n";
return 0; return 0;
} }

View File

@@ -12,7 +12,8 @@ using Time = unsigned long;
using IDPair = std::pair<Time, Time>; using IDPair = std::pair<Time, Time>;
using IDVector = std::vector<IDPair>; using IDVector = std::vector<IDPair>;
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
std::getline(std::cin, line); // Ignore first line std::getline(std::cin, line); // Ignore first line
@@ -26,7 +27,8 @@ int main(int argc, char **argv) {
if (buses[pos] == ',') { if (buses[pos] == ',') {
++pos; ++pos;
continue; continue;
} else if (buses[pos] == 'x') { }
else if (buses[pos] == 'x') {
++offset; ++offset;
++pos; ++pos;
continue; continue;
@@ -43,12 +45,11 @@ int main(int argc, char **argv) {
// Make assumption that all bus IDs are co-prime. // Make assumption that all bus IDs are co-prime.
Time t = 0; Time t = 0;
Time t_incr = 1; Time t_incr = 1;
for (auto const &bus : ids) { for (auto const& bus : ids) {
while ((t + bus.second) % bus.first != 0) { while ((t + bus.second) % bus.first != 0) {
t += t_incr; t += t_incr;
} }
std::cout << "Bus #" << bus.first << " at offset " << bus.second std::cout << "Bus #" << bus.first << " at offset " << bus.second << " t = " << t << "\n";
<< " t = " << t << "\n";
t_incr *= bus.first; t_incr *= bus.first;
} }
return 0; return 0;

View File

@@ -10,10 +10,12 @@
using Data = std::uint64_t; using Data = std::uint64_t;
using Mem = std::vector<Data>; using Mem = std::vector<Data>;
struct Computer { struct Computer
{
Computer() : set_(0), clear_(0), mem_() {} Computer() : set_(0), clear_(0), mem_() {}
void add_instruction(std::string const &s) { void add_instruction(std::string const& s)
{
static const std::regex re("mem\\[(\\d+)\\] = (\\d+)"); static const std::regex re("mem\\[(\\d+)\\] = (\\d+)");
std::smatch m; std::smatch m;
@@ -28,11 +30,12 @@ struct Computer {
} }
std::cout << "mask set: " << std::hex << set_ << "\n"; std::cout << "mask set: " << std::hex << set_ << "\n";
std::cout << "mask clear: " << std::hex << clear_ << "\n"; std::cout << "mask clear: " << std::hex << clear_ << "\n";
} else if (std::regex_search(s, m, re)) { }
else if (std::regex_search(s, m, re)) {
Data loc = std::stoul(m.str(1)); Data loc = std::stoul(m.str(1));
Data value = std::stoul(m.str(2)); Data value = std::stoul(m.str(2));
std::cout << "mem[" << std::dec << loc << " = (" << value << " | " << set_ std::cout << "mem[" << std::dec << loc << " = (" << value << " | " << set_ << ") & " << clear_
<< ") & " << clear_ << " = "; << " = ";
value = (value | set_) & clear_; value = (value | set_) & clear_;
std::cout << value << "\n"; std::cout << value << "\n";
if (mem_.size() <= loc) { if (mem_.size() <= loc) {
@@ -42,7 +45,8 @@ struct Computer {
} }
} }
Data mem_sum() const noexcept { Data mem_sum() const noexcept
{
Data r = 0; Data r = 0;
for (auto v : mem_) { for (auto v : mem_) {
r += v; r += v;
@@ -55,7 +59,8 @@ struct Computer {
Mem mem_; Mem mem_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Computer c; Computer c;
std::string line; std::string line;

View File

@@ -10,9 +10,10 @@
using Data = std::uint64_t; using Data = std::uint64_t;
using Mem = std::map<Data, Data>; using Mem = std::map<Data, Data>;
struct Computer { struct Computer
{
void add_instruction(std::string const &s) { void add_instruction(std::string const& s)
{
static const std::regex re("mem\\[(\\d+)\\] = (\\d+)"); static const std::regex re("mem\\[(\\d+)\\] = (\\d+)");
std::smatch m; std::smatch m;
@@ -26,28 +27,29 @@ struct Computer {
for (auto c : mask) { for (auto c : mask) {
if (c == '1') { if (c == '1') {
set_ |= Data(1) << bit; set_ |= Data(1) << bit;
}
} else if (c == 'X') { else if (c == 'X') {
bits_.push_back(std::size_t(1) << bit); bits_.push_back(std::size_t(1) << bit);
std::cout << bit << " (" << (std::size_t(1) << bit) << ") "; std::cout << bit << " (" << (std::size_t(1) << bit) << ") ";
}
} else { else {
assert(c == '0'); assert(c == '0');
} }
++bit; ++bit;
} }
assert(bit == mask.size()); assert(bit == mask.size());
std::cout << " set: 0x" << std::hex << set_ << std::dec << "\n"; std::cout << " set: 0x" << std::hex << set_ << std::dec << "\n";
} else if (std::regex_search(s, m, re)) { }
else if (std::regex_search(s, m, re)) {
Data loc = std::stoul(m.str(1)); Data loc = std::stoul(m.str(1));
Data value = std::stoul(m.str(2)); Data value = std::stoul(m.str(2));
set_mem(loc, value); set_mem(loc, value);
} }
} }
void set_mem(Data loc, Data value) { void set_mem(Data loc, Data value)
std::cout << "Writing: " << value << " to base loc " << std::hex << loc {
<< " which floats to:"; std::cout << "Writing: " << value << " to base loc " << std::hex << loc << " which floats to:";
for (auto b : bits_) { for (auto b : bits_) {
loc &= ~b; loc &= ~b;
} }
@@ -67,7 +69,8 @@ struct Computer {
std::cout << std::dec << "\n"; std::cout << std::dec << "\n";
} }
Data mem_sum() const noexcept { Data mem_sum() const noexcept
{
Data r = 0; Data r = 0;
for (auto v : mem_) { for (auto v : mem_) {
r += v.second; r += v.second;
@@ -80,7 +83,8 @@ struct Computer {
Mem mem_; Mem mem_;
}; };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
Computer c; Computer c;
std::string line; std::string line;

View File

@@ -9,12 +9,14 @@
using NumMap = std::map<int, int>; using NumMap = std::map<int, int>;
int add_to_map(NumMap &nums, int num, int turn) { int add_to_map(NumMap& nums, int num, int turn)
{
auto [it, success] = nums.insert({num, turn}); auto [it, success] = nums.insert({num, turn});
if (success) { if (success) {
// std::cout << "Turn " << turn << ": " << num << " (new)\n"; // std::cout << "Turn " << turn << ": " << num << " (new)\n";
return 0; return 0;
} else { }
else {
int r = turn - it->second; int r = turn - it->second;
// std::cout << "Turn " << turn << ": " << num << " (previous seen turn " // std::cout << "Turn " << turn << ": " << num << " (previous seen turn "
// << it->second << " dist = " << r << ")\n"; // << it->second << " dist = " << r << ")\n";
@@ -23,7 +25,8 @@ int add_to_map(NumMap &nums, int num, int turn) {
} }
} }
int run(std::string const &s, int num_turns) { int run(std::string const& s, int num_turns)
{
NumMap seen; NumMap seen;
std::size_t pos = 0; std::size_t pos = 0;
std::size_t len; std::size_t len;
@@ -47,7 +50,8 @@ int run(std::string const &s, int num_turns) {
return next_num; return next_num;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
int r = run(line, 2020); int r = run(line, 2020);

View File

@@ -10,12 +10,14 @@
using NumMap = std::unordered_map<int, int>; using NumMap = std::unordered_map<int, int>;
int add_to_map(NumMap &nums, int num, int turn) { int add_to_map(NumMap& nums, int num, int turn)
{
auto [it, success] = nums.insert({num, turn}); auto [it, success] = nums.insert({num, turn});
if (success) { if (success) {
// std::cout << "Turn " << turn << ": " << num << " (new)\n"; // std::cout << "Turn " << turn << ": " << num << " (new)\n";
return 0; return 0;
} else { }
else {
int r = turn - it->second; int r = turn - it->second;
// std::cout << "Turn " << turn << ": " << num << " (previous seen turn " // std::cout << "Turn " << turn << ": " << num << " (previous seen turn "
// << it->second << " dist = " << r << ")\n"; // << it->second << " dist = " << r << ")\n";
@@ -24,7 +26,8 @@ int add_to_map(NumMap &nums, int num, int turn) {
} }
} }
int run(std::string const &s, int num_turns) { int run(std::string const& s, int num_turns)
{
NumMap seen; NumMap seen;
std::size_t pos = 0; std::size_t pos = 0;
std::size_t len; std::size_t len;
@@ -48,7 +51,8 @@ int run(std::string const &s, int num_turns) {
return next_num; return next_num;
} }
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
int r = run(line, 30000000); int r = run(line, 30000000);

View File

@@ -9,8 +9,10 @@
using ValidVector = std::vector<bool>; using ValidVector = std::vector<bool>;
struct Classifier { struct Classifier
void add_ranges(std::string const &s) { {
void add_ranges(std::string const& s)
{
static const std::regex re("(\\w+): (\\d+)-(\\d+) or (\\d+)-(\\d+)"); static const std::regex re("(\\w+): (\\d+)-(\\d+) or (\\d+)-(\\d+)");
std::smatch m; std::smatch m;
if (std::regex_search(s, m, re)) { if (std::regex_search(s, m, re)) {
@@ -22,7 +24,8 @@ struct Classifier {
} }
} }
void add_range(std::string const &lows, std::string const &highs) { void add_range(std::string const& lows, std::string const& highs)
{
int low = std::stoi(lows); int low = std::stoi(lows);
int high = std::stoi(highs); int high = std::stoi(highs);
++high; ++high;
@@ -36,7 +39,8 @@ struct Classifier {
} }
} }
int count_errors(std::string const &s) { int count_errors(std::string const& s)
{
std::string::size_type pos = 0; std::string::size_type pos = 0;
int result = 0; int result = 0;
while (pos < s.size()) { while (pos < s.size()) {
@@ -59,7 +63,8 @@ struct Classifier {
enum class State { Permitted, Your, Nearby }; enum class State { Permitted, Your, Nearby };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
State s = State::Permitted; State s = State::Permitted;
@@ -68,13 +73,17 @@ int main(int argc, char **argv) {
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
if (line == "your ticket:") { if (line == "your ticket:") {
s = State::Your; s = State::Your;
} else if (line == "nearby tickets:") { }
else if (line == "nearby tickets:") {
s = State::Nearby; s = State::Nearby;
} else if (line == "") { }
else if (line == "") {
/* nothing */; /* nothing */;
} else if (s == State::Permitted) { }
else if (s == State::Permitted) {
c.add_ranges(line); c.add_ranges(line);
} else if (s == State::Nearby) { }
else if (s == State::Nearby) {
e += c.count_errors(line); e += c.count_errors(line);
} }
} }

View File

@@ -7,8 +7,10 @@
#include <regex> #include <regex>
#include <string> #include <string>
struct Classifier { struct Classifier
void add_ranges(std::string const &s) { {
void add_ranges(std::string const& s)
{
static const std::regex re("(.+): (\\d+)-(\\d+) or (\\d+)-(\\d+)"); static const std::regex re("(.+): (\\d+)-(\\d+) or (\\d+)-(\\d+)");
std::smatch m; std::smatch m;
if (std::regex_search(s, m, re)) { if (std::regex_search(s, m, re)) {
@@ -22,8 +24,8 @@ struct Classifier {
} }
} }
void add_range(std::string const &lows, std::string const &highs, void add_range(std::string const& lows, std::string const& highs, std::size_t field)
std::size_t field) { {
int low = std::stoi(lows); int low = std::stoi(lows);
int high = std::stoi(highs); int high = std::stoi(highs);
++high; ++high;
@@ -39,13 +41,14 @@ struct Classifier {
} }
} }
void close() { void close()
{
idx_to_valid_field_.resize(0); idx_to_valid_field_.resize(0);
idx_to_valid_field_.resize(field_names_.size(), idx_to_valid_field_.resize(field_names_.size(), (1 << field_names_.size()) - 1);
(1 << field_names_.size()) - 1);
} }
int count_errors(std::string const &s) const { int count_errors(std::string const& s) const
{
std::string::size_type pos = 0; std::string::size_type pos = 0;
int result = 0; int result = 0;
while (pos < s.size()) { while (pos < s.size()) {
@@ -64,14 +67,14 @@ struct Classifier {
return result; return result;
} }
void mark_valid(std::string const &s) { void mark_valid(std::string const& s)
{
std::string::size_type pos = 0; std::string::size_type pos = 0;
unsigned idx = 0; unsigned idx = 0;
while (pos < s.size()) { while (pos < s.size()) {
std::size_t len = 0; std::size_t len = 0;
int num = std::stoi(s.substr(pos), &len); int num = std::stoi(s.substr(pos), &len);
unsigned valid_fields = unsigned valid_fields = num >= num_to_valid_field_.size() ? 0 : num_to_valid_field_[num];
num >= num_to_valid_field_.size() ? 0 : num_to_valid_field_[num];
idx_to_valid_field_[idx] &= valid_fields; idx_to_valid_field_[idx] &= valid_fields;
pos += len; pos += len;
while (pos < s.size() && s[pos] == ',') { while (pos < s.size() && s[pos] == ',') {
@@ -82,12 +85,12 @@ struct Classifier {
} }
} }
void print_valid() const { void print_valid() const
{
for (std::size_t idx = 0; idx < idx_to_valid_field_.size(); ++idx) { for (std::size_t idx = 0; idx < idx_to_valid_field_.size(); ++idx) {
std::cout << "Index " << idx << " valid for fields:"; std::cout << "Index " << idx << " valid for fields:";
unsigned field = 0; unsigned field = 0;
for (auto valid_fields = idx_to_valid_field_[idx]; valid_fields != 0; for (auto valid_fields = idx_to_valid_field_[idx]; valid_fields != 0; valid_fields >>= 1) {
valid_fields >>= 1) {
if (valid_fields & 1) { if (valid_fields & 1) {
std::cout << " " << field_names_[field]; std::cout << " " << field_names_[field];
} }
@@ -97,15 +100,15 @@ struct Classifier {
} }
} }
void reduce() { void reduce()
{
bool changed = true; bool changed = true;
while (changed) { while (changed) {
changed = false; changed = false;
for (unsigned idx = 0; idx < idx_to_valid_field_.size(); ++idx) { for (unsigned idx = 0; idx < idx_to_valid_field_.size(); ++idx) {
auto valid_fields = idx_to_valid_field_[idx]; auto valid_fields = idx_to_valid_field_[idx];
if ((valid_fields & (valid_fields - 1)) == 0) { if ((valid_fields & (valid_fields - 1)) == 0) {
std::cout << "Index " << idx << " can only be field " << valid_fields std::cout << "Index " << idx << " can only be field " << valid_fields << "\n";
<< "\n";
for (unsigned idx2 = 0; idx2 < idx_to_valid_field_.size(); ++idx2) { for (unsigned idx2 = 0; idx2 < idx_to_valid_field_.size(); ++idx2) {
if (idx == idx2) { if (idx == idx2) {
continue; continue;
@@ -118,14 +121,15 @@ struct Classifier {
} }
} }
unsigned long calculate_product(std::string const &s, unsigned long calculate_product(std::string const& s, std::string const& prefix)
std::string const &prefix) { {
std::vector<unsigned> values; std::vector<unsigned> values;
std::size_t pos = 0; std::size_t pos = 0;
while (pos < s.size()) { while (pos < s.size()) {
if (s[pos] == ',') { if (s[pos] == ',') {
++pos; ++pos;
} else { }
else {
std::size_t len; std::size_t len;
values.push_back(std::stoi(s.substr(pos), &len)); values.push_back(std::stoi(s.substr(pos), &len));
pos += len; pos += len;
@@ -136,8 +140,7 @@ struct Classifier {
for (unsigned field = 0; field < field_names_.size(); ++field) { for (unsigned field = 0; field < field_names_.size(); ++field) {
if (field_names_[field].substr(0, prefix.size()) == prefix) { if (field_names_[field].substr(0, prefix.size()) == prefix) {
unsigned idx = 0; unsigned idx = 0;
while (idx < idx_to_valid_field_.size() && while (idx < idx_to_valid_field_.size() && idx_to_valid_field_[idx] != (1 << field)) {
idx_to_valid_field_[idx] != (1 << field)) {
++idx; ++idx;
} }
assert(idx < idx_to_valid_field_.size()); assert(idx < idx_to_valid_field_.size());
@@ -155,7 +158,8 @@ struct Classifier {
enum class State { Permitted, Your, Nearby }; enum class State { Permitted, Your, Nearby };
int main(int argc, char **argv) { int main(int argc, char** argv)
{
std::string line; std::string line;
State s = State::Permitted; State s = State::Permitted;
@@ -165,16 +169,21 @@ int main(int argc, char **argv) {
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
if (line == "your ticket:") { if (line == "your ticket:") {
s = State::Your; s = State::Your;
} else if (line == "nearby tickets:") { }
else if (line == "nearby tickets:") {
s = State::Nearby; s = State::Nearby;
c.close(); c.close();
} else if (line == "") { }
else if (line == "") {
/* nothing */; /* nothing */;
} else if (s == State::Permitted) { }
else if (s == State::Permitted) {
c.add_ranges(line); c.add_ranges(line);
} else if (s == State::Your) { }
else if (s == State::Your) {
our_ticket = line; our_ticket = line;
} else if (s == State::Nearby) { }
else if (s == State::Nearby) {
auto e2 = c.count_errors(line); auto e2 = c.count_errors(line);
e += e2; e += e2;
if (e2 == 0) { if (e2 == 0) {
@@ -187,7 +196,6 @@ int main(int argc, char **argv) {
c.reduce(); c.reduce();
c.print_valid(); c.print_valid();
std::cout << "Product: " << c.calculate_product(our_ticket, "departure ") std::cout << "Product: " << c.calculate_product(our_ticket, "departure ") << "\n";
<< "\n";
return 0; return 0;
} }

View File

@@ -9,13 +9,15 @@
#include <string> #include <string>
#include <tuple> #include <tuple>
struct ConwayCubeState { struct ConwayCubeState
{
using Point = std::tuple<int, int, int>; using Point = std::tuple<int, int, int>;
using PointSet = std::set<Point>; using PointSet = std::set<Point>;
using NeighbourMap = std::map<Point, unsigned>; using NeighbourMap = std::map<Point, unsigned>;
ConwayCubeState() : next_row_(0) {} ConwayCubeState() : next_row_(0) {}
void add_row(std::string const &s) { void add_row(std::string const& s)
{
for (int x = 0; x < s.size(); ++x) { for (int x = 0; x < s.size(); ++x) {
if (s[x] == '#') { if (s[x] == '#') {
set_point(x, next_row_, 0); set_point(x, next_row_, 0);
@@ -24,13 +26,15 @@ struct ConwayCubeState {
++next_row_; ++next_row_;
} }
ConwayCubeState next_state() const { ConwayCubeState next_state() const
{
ConwayCubeState next; ConwayCubeState next;
for (auto const &n : neighbours_) { for (auto const& n : neighbours_) {
bool active = points_.find(n.first) != points_.end(); bool active = points_.find(n.first) != points_.end();
if (active && (n.second == 2 || n.second == 3)) { if (active && (n.second == 2 || n.second == 3)) {
next.set_point(n.first); next.set_point(n.first);
} else if (!active && n.second == 3) { }
else if (!active && n.second == 3) {
next.set_point(n.first); next.set_point(n.first);
} }
} }
@@ -41,11 +45,10 @@ struct ConwayCubeState {
auto active() const { return points_.size(); } auto active() const { return points_.size(); }
private: private:
void set_point(Point const &pt) { void set_point(Point const& pt) { set_point(std::get<0>(pt), std::get<1>(pt), std::get<2>(pt)); }
set_point(std::get<0>(pt), std::get<1>(pt), std::get<2>(pt));
}
void set_point(int px, int py, int pz) { void set_point(int px, int py, int pz)
{
points_.insert({px, py, pz}); points_.insert({px, py, pz});
for (int x = px - 1; x < px + 2; ++x) { for (int x = px - 1; x < px + 2; ++x) {
@@ -69,7 +72,8 @@ private:
NeighbourMap neighbours_; NeighbourMap neighbours_;
}; };
int main(void) { int main(void)
{
std::string line; std::string line;
ConwayCubeState state; ConwayCubeState state;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -9,13 +9,15 @@
#include <string> #include <string>
#include <tuple> #include <tuple>
struct ConwayCubeState { struct ConwayCubeState
{
using Point = std::tuple<int, int, int, int>; using Point = std::tuple<int, int, int, int>;
using PointSet = std::set<Point>; using PointSet = std::set<Point>;
using NeighbourMap = std::map<Point, unsigned>; using NeighbourMap = std::map<Point, unsigned>;
ConwayCubeState() : next_row_(0) {} ConwayCubeState() : next_row_(0) {}
void add_row(std::string const &s) { void add_row(std::string const& s)
{
for (int x = 0; x < s.size(); ++x) { for (int x = 0; x < s.size(); ++x) {
if (s[x] == '#') { if (s[x] == '#') {
set_point(x, next_row_, 0, 0); set_point(x, next_row_, 0, 0);
@@ -24,13 +26,15 @@ struct ConwayCubeState {
++next_row_; ++next_row_;
} }
ConwayCubeState next_state() const { ConwayCubeState next_state() const
{
ConwayCubeState next; ConwayCubeState next;
for (auto const &n : neighbours_) { for (auto const& n : neighbours_) {
bool active = points_.find(n.first) != points_.end(); bool active = points_.find(n.first) != points_.end();
if (active && (n.second == 2 || n.second == 3)) { if (active && (n.second == 2 || n.second == 3)) {
next.set_point(n.first); next.set_point(n.first);
} else if (!active && n.second == 3) { }
else if (!active && n.second == 3) {
next.set_point(n.first); next.set_point(n.first);
} }
} }
@@ -41,12 +45,13 @@ struct ConwayCubeState {
auto active() const { return points_.size(); } auto active() const { return points_.size(); }
private: private:
void set_point(Point const &pt) { void set_point(Point const& pt)
set_point(std::get<0>(pt), std::get<1>(pt), std::get<2>(pt), {
std::get<3>(pt)); set_point(std::get<0>(pt), std::get<1>(pt), std::get<2>(pt), std::get<3>(pt));
} }
void set_point(int pw, int px, int py, int pz) { void set_point(int pw, int px, int py, int pz)
{
points_.insert({pw, px, py, pz}); points_.insert({pw, px, py, pz});
for (int w = pw - 1; w < pw + 2; ++w) { for (int w = pw - 1; w < pw + 2; ++w) {
@@ -72,7 +77,8 @@ private:
NeighbourMap neighbours_; NeighbourMap neighbours_;
}; };
int main(void) { int main(void)
{
std::string line; std::string line;
ConwayCubeState state; ConwayCubeState state;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -9,46 +9,46 @@
#include <string> #include <string>
#include <tuple> #include <tuple>
enum class Token : char { enum class Token : char { Eof, Number, LParens = '(', RParens = ')', Add = '+', Multiply = '*' };
Eof,
Number,
LParens = '(',
RParens = ')',
Add = '+',
Multiply = '*'
};
using Value = unsigned long; using Value = unsigned long;
struct Parser { struct Parser
Parser(std::string const &s) : expr_(s), pos_(0) { skip_whitespace(); } {
Parser(std::string const& s) : expr_(s), pos_(0) { skip_whitespace(); }
Value evaluate() { return binop(); } Value evaluate() { return binop(); }
private: private:
Value binop() { Value binop()
{
auto value = primary(); auto value = primary();
do { do {
if (peek() == Token::Add) { if (peek() == Token::Add) {
chew(Token::Add); chew(Token::Add);
value += primary(); value += primary();
} else if (peek() == Token::Multiply) { }
else if (peek() == Token::Multiply) {
chew(Token::Multiply); chew(Token::Multiply);
value *= primary(); value *= primary();
} else { }
else {
return value; return value;
} }
} while (true); } while (true);
} }
Value primary() { Value primary()
{
if (peek() == Token::LParens) { if (peek() == Token::LParens) {
chew(Token::LParens); chew(Token::LParens);
Value value = binop(); Value value = binop();
chew(Token::RParens); chew(Token::RParens);
return value; return value;
} else if (peek() == Token::Number) { }
else if (peek() == Token::Number) {
return chew_number(); return chew_number();
} else { }
else {
std::cout << "expr_ = " << expr_ << "\n"; std::cout << "expr_ = " << expr_ << "\n";
std::cout << "pos_ = " << pos_ << "\n"; std::cout << "pos_ = " << pos_ << "\n";
std::cout << "End = " << expr_.substr(pos_) << "\n"; std::cout << "End = " << expr_.substr(pos_) << "\n";
@@ -56,7 +56,8 @@ private:
} }
} }
Token peek() { Token peek()
{
if (pos_ == expr_.size()) { if (pos_ == expr_.size()) {
return Token::Eof; return Token::Eof;
} }
@@ -89,7 +90,8 @@ private:
} }
} }
void chew(Token tok) { void chew(Token tok)
{
assert(peek() == tok); assert(peek() == tok);
switch (tok) { switch (tok) {
case Token::LParens: case Token::LParens:
@@ -104,13 +106,15 @@ private:
} }
} }
void skip_whitespace() { void skip_whitespace()
{
while (pos_ < expr_.size() && expr_[pos_] == ' ') { while (pos_ < expr_.size() && expr_[pos_] == ' ') {
++pos_; ++pos_;
} }
} }
Value chew_number() { Value chew_number()
{
assert(peek() == Token::Number); assert(peek() == Token::Number);
std::size_t len = 0; std::size_t len = 0;
@@ -124,7 +128,8 @@ private:
std::string::size_type pos_; std::string::size_type pos_;
}; };
int main(void) { int main(void)
{
std::string line; std::string line;
Value result = 0; Value result = 0;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -9,55 +9,56 @@
#include <string> #include <string>
#include <tuple> #include <tuple>
enum class Token : char { enum class Token : char { Eof, Number, LParens = '(', RParens = ')', Add = '+', Multiply = '*' };
Eof,
Number,
LParens = '(',
RParens = ')',
Add = '+',
Multiply = '*'
};
using Value = unsigned long; using Value = unsigned long;
struct Parser { struct Parser
Parser(std::string const &s) : expr_(s), pos_(0) { skip_whitespace(); } {
Parser(std::string const& s) : expr_(s), pos_(0) { skip_whitespace(); }
Value evaluate() { return multop(); } Value evaluate() { return multop(); }
private: private:
Value addop() { Value addop()
{
auto value = primary(); auto value = primary();
do { do {
if (peek() == Token::Add) { if (peek() == Token::Add) {
chew(Token::Add); chew(Token::Add);
value += primary(); value += primary();
} else { }
else {
return value; return value;
} }
} while (true); } while (true);
} }
Value multop() { Value multop()
{
auto value = addop(); auto value = addop();
do { do {
if (peek() == Token::Multiply) { if (peek() == Token::Multiply) {
chew(Token::Multiply); chew(Token::Multiply);
value *= addop(); value *= addop();
} else { }
else {
return value; return value;
} }
} while (true); } while (true);
} }
Value primary() { Value primary()
{
if (peek() == Token::LParens) { if (peek() == Token::LParens) {
chew(Token::LParens); chew(Token::LParens);
Value value = evaluate(); Value value = evaluate();
chew(Token::RParens); chew(Token::RParens);
return value; return value;
} else if (peek() == Token::Number) { }
else if (peek() == Token::Number) {
return chew_number(); return chew_number();
} else { }
else {
std::cout << "expr_ = " << expr_ << "\n"; std::cout << "expr_ = " << expr_ << "\n";
std::cout << "pos_ = " << pos_ << "\n"; std::cout << "pos_ = " << pos_ << "\n";
std::cout << "End = " << expr_.substr(pos_) << "\n"; std::cout << "End = " << expr_.substr(pos_) << "\n";
@@ -65,7 +66,8 @@ private:
} }
} }
Token peek() { Token peek()
{
if (pos_ == expr_.size()) { if (pos_ == expr_.size()) {
return Token::Eof; return Token::Eof;
} }
@@ -98,7 +100,8 @@ private:
} }
} }
void chew(Token tok) { void chew(Token tok)
{
assert(peek() == tok); assert(peek() == tok);
switch (tok) { switch (tok) {
case Token::LParens: case Token::LParens:
@@ -113,13 +116,15 @@ private:
} }
} }
void skip_whitespace() { void skip_whitespace()
{
while (pos_ < expr_.size() && expr_[pos_] == ' ') { while (pos_ < expr_.size() && expr_[pos_] == ' ') {
++pos_; ++pos_;
} }
} }
Value chew_number() { Value chew_number()
{
assert(peek() == Token::Number); assert(peek() == Token::Number);
std::size_t len = 0; std::size_t len = 0;
@@ -133,7 +138,8 @@ private:
std::string::size_type pos_; std::string::size_type pos_;
}; };
int main(void) { int main(void)
{
std::string line; std::string line;
Value result = 0; Value result = 0;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -9,8 +9,10 @@
#include <string> #include <string>
#include <tuple> #include <tuple>
struct Matcher { struct Matcher
void add_rule(std::string const &s) { {
void add_rule(std::string const& s)
{
std::size_t len = 0; std::size_t len = 0;
unsigned long id = std::stoul(s, &len); unsigned long id = std::stoul(s, &len);
assert(s[len] == ':'); assert(s[len] == ':');
@@ -26,24 +28,25 @@ struct Matcher {
void calculate_regex() { re_.assign("^" + expand_rule(0) + "$"); } void calculate_regex() { re_.assign("^" + expand_rule(0) + "$"); }
bool does_match(std::string const &s) const { bool does_match(std::string const& s) const { return std::regex_match(s, re_); }
return std::regex_match(s, re_);
}
private: private:
std::string expand_rule(std::size_t id) { std::string expand_rule(std::size_t id)
{
std::string re; std::string re;
std::string const &rule = rules_[id]; std::string const& rule = rules_[id];
std::size_t pos = 0; std::size_t pos = 0;
bool needs_brackets = false; bool needs_brackets = false;
while (pos < rule.size()) { while (pos < rule.size()) {
if (rule[pos] == ' ') { if (rule[pos] == ' ') {
++pos; ++pos;
} else if (rule[pos] == '|') { }
else if (rule[pos] == '|') {
re += "|"; re += "|";
needs_brackets = true; needs_brackets = true;
++pos; ++pos;
} else if (rule[pos] == '"') { }
else if (rule[pos] == '"') {
++pos; ++pos;
while (pos < rule.size() && rule[pos] != '"') { while (pos < rule.size() && rule[pos] != '"') {
re += rule[pos]; re += rule[pos];
@@ -52,12 +55,14 @@ private:
assert(pos < rule.size()); assert(pos < rule.size());
assert(rule[pos] == '"'); assert(rule[pos] == '"');
++pos; ++pos;
} else if (std::isdigit(rule[pos])) { }
else if (std::isdigit(rule[pos])) {
std::size_t len = 0; std::size_t len = 0;
std::size_t subid = std::stoul(rule.substr(pos), &len); std::size_t subid = std::stoul(rule.substr(pos), &len);
pos += len; pos += len;
re += expand_rule(subid); re += expand_rule(subid);
} else { }
else {
assert(false); assert(false);
} }
} }
@@ -73,7 +78,8 @@ private:
std::regex re_; std::regex re_;
}; };
int main(void) { int main(void)
{
std::string line; std::string line;
Matcher matcher; Matcher matcher;
bool adding_rules = true; bool adding_rules = true;
@@ -82,9 +88,11 @@ int main(void) {
if (line.empty()) { if (line.empty()) {
adding_rules = false; adding_rules = false;
matcher.calculate_regex(); matcher.calculate_regex();
} else if (adding_rules) { }
else if (adding_rules) {
matcher.add_rule(line); matcher.add_rule(line);
} else { }
else {
bool m = matcher.does_match(line); bool m = matcher.does_match(line);
std::cout << line << ": does " << (m ? "" : "not ") << "match\n"; std::cout << line << ": does " << (m ? "" : "not ") << "match\n";
matches += m; matches += m;

View File

@@ -9,8 +9,10 @@
#include <string> #include <string>
#include <tuple> #include <tuple>
struct Matcher { struct Matcher
void add_rule(std::string const &s) { {
void add_rule(std::string const& s)
{
std::size_t len = 0; std::size_t len = 0;
unsigned long id = std::stoul(s, &len); unsigned long id = std::stoul(s, &len);
assert(s[len] == ':'); assert(s[len] == ':');
@@ -24,12 +26,14 @@ struct Matcher {
rules_[id] = s.substr(len); rules_[id] = s.substr(len);
} }
void calculate_regex() { void calculate_regex()
{
re42_ = expand_rule(42); re42_ = expand_rule(42);
re31_ = expand_rule(31); re31_ = expand_rule(31);
} }
bool does_match(std::string const &s) const { bool does_match(std::string const& s) const
{
std::smatch m; std::smatch m;
std::string begin = "^" + re42_ + re42_; std::string begin = "^" + re42_ + re42_;
unsigned repeats = 1; unsigned repeats = 1;
@@ -50,19 +54,22 @@ struct Matcher {
} }
private: private:
std::string expand_rule(std::size_t id) { std::string expand_rule(std::size_t id)
{
std::string re; std::string re;
std::string const &rule = rules_[id]; std::string const& rule = rules_[id];
std::size_t pos = 0; std::size_t pos = 0;
bool needs_brackets = false; bool needs_brackets = false;
while (pos < rule.size()) { while (pos < rule.size()) {
if (rule[pos] == ' ') { if (rule[pos] == ' ') {
++pos; ++pos;
} else if (rule[pos] == '|') { }
else if (rule[pos] == '|') {
re += "|"; re += "|";
needs_brackets = true; needs_brackets = true;
++pos; ++pos;
} else if (rule[pos] == '"') { }
else if (rule[pos] == '"') {
++pos; ++pos;
while (pos < rule.size() && rule[pos] != '"') { while (pos < rule.size() && rule[pos] != '"') {
re += rule[pos]; re += rule[pos];
@@ -71,12 +78,14 @@ private:
assert(pos < rule.size()); assert(pos < rule.size());
assert(rule[pos] == '"'); assert(rule[pos] == '"');
++pos; ++pos;
} else if (std::isdigit(rule[pos])) { }
else if (std::isdigit(rule[pos])) {
std::size_t len = 0; std::size_t len = 0;
std::size_t subid = std::stoul(rule.substr(pos), &len); std::size_t subid = std::stoul(rule.substr(pos), &len);
pos += len; pos += len;
re += expand_rule(subid); re += expand_rule(subid);
} else { }
else {
assert(false); assert(false);
} }
} }
@@ -93,7 +102,8 @@ private:
std::string re31_; std::string re31_;
}; };
int main(void) { int main(void)
{
std::string line; std::string line;
Matcher matcher; Matcher matcher;
bool adding_rules = true; bool adding_rules = true;
@@ -102,9 +112,11 @@ int main(void) {
if (line.empty()) { if (line.empty()) {
adding_rules = false; adding_rules = false;
matcher.calculate_regex(); matcher.calculate_regex();
} else if (adding_rules) { }
else if (adding_rules) {
matcher.add_rule(line); matcher.add_rule(line);
} else { }
else {
bool m = matcher.does_match(line); bool m = matcher.does_match(line);
std::cout << line << ": does " << (m ? "" : "not ") << "match\n"; std::cout << line << ": does " << (m ? "" : "not ") << "match\n";
matches += m; matches += m;

View File

@@ -14,8 +14,10 @@ using Hash = unsigned long;
enum Edge { Top, Left, Bottom, Right }; enum Edge { Top, Left, Bottom, Right };
struct Picture { struct Picture
Picture(std::string id, std::istream &is) : in_use_(false) { {
Picture(std::string id, std::istream& is) : in_use_(false)
{
assert(id.substr(0, 5) == "Tile "); assert(id.substr(0, 5) == "Tile ");
id_ = std::stoul(id.substr(5)); id_ = std::stoul(id.substr(5));
std::string line; std::string line;
@@ -27,20 +29,22 @@ struct Picture {
} }
} }
Picture(Picture const &) = delete; Picture(Picture const&) = delete;
Picture &operator=(Picture const &) = delete; Picture& operator=(Picture const&) = delete;
Picture(Picture &&) = default; Picture(Picture&&) = default;
Picture &operator=(Picture &&) = default; Picture& operator=(Picture&&) = default;
void flip() { void flip()
for (auto &r : rows_) { {
for (auto& r : rows_) {
std::reverse(r.begin(), r.end()); std::reverse(r.begin(), r.end());
} }
} }
void rotate() { void rotate()
{
std::vector<std::string> copy(rows_.size()); std::vector<std::string> copy(rows_.size());
for (auto const &r : rows_) { for (auto const& r : rows_) {
std::size_t off = copy.size(); std::size_t off = copy.size();
assert(r.size() == copy.size()); assert(r.size() == copy.size());
for (auto c : r) { for (auto c : r) {
@@ -51,7 +55,8 @@ struct Picture {
rows_ = copy; rows_ = copy;
} }
Hash hash(Edge edge) const { Hash hash(Edge edge) const
{
unsigned x = (edge == Edge::Right) ? rows_[0].size() - 1 : 0; unsigned x = (edge == Edge::Right) ? rows_[0].size() - 1 : 0;
unsigned y = (edge == Edge::Bottom) ? rows_.size() - 1 : 0; unsigned y = (edge == Edge::Bottom) ? rows_.size() - 1 : 0;
unsigned dx = (edge == Edge::Top || edge == Edge::Bottom) ? 1 : 0; unsigned dx = (edge == Edge::Top || edge == Edge::Bottom) ? 1 : 0;
@@ -70,11 +75,9 @@ struct Picture {
Id id() const noexcept { return id_; } Id id() const noexcept { return id_; }
bool operator<(Picture const &pict) const noexcept { return id_ < pict.id_; } bool operator<(Picture const& pict) const noexcept { return id_ < pict.id_; }
bool operator==(Picture const &pict) const noexcept { bool operator==(Picture const& pict) const noexcept { return id_ == pict.id_; }
return id_ == pict.id_;
}
bool in_use() const noexcept { return in_use_; } bool in_use() const noexcept { return in_use_; }
void use() noexcept { in_use_ = true; } void use() noexcept { in_use_ = true; }
@@ -90,14 +93,16 @@ using Pictures = std::map<Id, Picture>;
using HashMap = std::multimap<Hash, Id>; using HashMap = std::multimap<Hash, Id>;
using Array = std::map<std::pair<unsigned, unsigned>, Id>; using Array = std::map<std::pair<unsigned, unsigned>, Id>;
struct PictureArray { struct PictureArray
void add(Picture &&pic) { {
void add(Picture&& pic)
{
auto id = pic.id(); auto id = pic.id();
auto [it, success] = pictures_.insert(std::make_pair(id, std::move(pic))); auto [it, success] = pictures_.insert(std::make_pair(id, std::move(pic)));
assert(success); assert(success);
// Set up hash -> ID mapping // Set up hash -> ID mapping
Picture &picture = it->second; Picture& picture = it->second;
for (unsigned r = 0; r < 4; ++r) { for (unsigned r = 0; r < 4; ++r) {
for (unsigned f = 0; f < 2; ++f) { for (unsigned f = 0; f < 2; ++f) {
hash_map_.insert({picture.hash(Edge::Top), picture.id()}); hash_map_.insert({picture.hash(Edge::Top), picture.id()});
@@ -107,13 +112,13 @@ struct PictureArray {
} }
} }
Id solve() { Id solve()
{
assert(pictures_.size() == 9 || pictures_.size() == 144); assert(pictures_.size() == 9 || pictures_.size() == 144);
for (auto &kv : pictures_) { for (auto& kv : pictures_) {
if (try_position(0, 0, kv.second)) { if (try_position(0, 0, kv.second)) {
print_ids(); print_ids();
return piece(0, 0).id() * piece(width() - 1, 0).id() * return piece(0, 0).id() * piece(width() - 1, 0).id() * piece(0, height() - 1).id() *
piece(0, height() - 1).id() *
piece(width() - 1, height() - 1).id(); piece(width() - 1, height() - 1).id();
} }
} }
@@ -123,7 +128,8 @@ struct PictureArray {
} }
private: private:
bool try_position(unsigned x, unsigned y, Picture &pict) { bool try_position(unsigned x, unsigned y, Picture& pict)
{
if (pict.in_use()) { if (pict.in_use()) {
return false; return false;
} }
@@ -180,7 +186,8 @@ private:
return false; return false;
} }
void print_ids() const { void print_ids() const
{
for (unsigned y = 0; y < height(); ++y) { for (unsigned y = 0; y < height(); ++y) {
for (unsigned x = 0; x < width(); ++x) { for (unsigned x = 0; x < width(); ++x) {
std::cout << " " << piece(x, y).id(); std::cout << " " << piece(x, y).id();
@@ -189,20 +196,24 @@ private:
} }
} }
Picture const &piece(unsigned x, unsigned y) const { Picture const& piece(unsigned x, unsigned y) const
auto const &it = array_.find({x, y}); {
auto const& it = array_.find({x, y});
assert(it != array_.end()); assert(it != array_.end());
auto const &itp = pictures_.find(it->second); auto const& itp = pictures_.find(it->second);
assert(itp != pictures_.end()); assert(itp != pictures_.end());
return itp->second; return itp->second;
} }
unsigned width() const noexcept { unsigned width() const noexcept
{
if (pictures_.size() == 9) { if (pictures_.size() == 9) {
return 3; return 3;
} else if (pictures_.size() == 144) { }
else if (pictures_.size() == 144) {
return 12; return 12;
} else { }
else {
assert(false); assert(false);
} }
@@ -216,7 +227,8 @@ private:
Array array_; Array array_;
}; };
int main(void) { int main(void)
{
PictureArray pictures_; PictureArray pictures_;
std::string line; std::string line;

View File

@@ -16,8 +16,10 @@ enum Edge { Top, Left, Bottom, Right };
struct PictureArray; struct PictureArray;
struct Picture { struct Picture
Picture(std::string id, std::istream &is) : in_use_(false) { {
Picture(std::string id, std::istream& is) : in_use_(false)
{
assert(id.substr(0, 5) == "Tile "); assert(id.substr(0, 5) == "Tile ");
id_ = std::stoul(id.substr(5)); id_ = std::stoul(id.substr(5));
std::string line; std::string line;
@@ -29,22 +31,24 @@ struct Picture {
} }
} }
Picture(PictureArray const &array); Picture(PictureArray const& array);
Picture(Picture const &) = delete; Picture(Picture const&) = delete;
Picture &operator=(Picture const &) = delete; Picture& operator=(Picture const&) = delete;
Picture(Picture &&) = default; Picture(Picture&&) = default;
Picture &operator=(Picture &&) = default; Picture& operator=(Picture&&) = default;
void flip() { void flip()
for (auto &r : rows_) { {
for (auto& r : rows_) {
std::reverse(r.begin(), r.end()); std::reverse(r.begin(), r.end());
} }
} }
void rotate() { void rotate()
{
std::vector<std::string> copy(rows_.size()); std::vector<std::string> copy(rows_.size());
for (auto const &r : rows_) { for (auto const& r : rows_) {
std::size_t off = copy.size(); std::size_t off = copy.size();
assert(r.size() == copy.size()); assert(r.size() == copy.size());
for (auto c : r) { for (auto c : r) {
@@ -55,7 +59,8 @@ struct Picture {
rows_ = copy; rows_ = copy;
} }
Hash hash(Edge edge) const { Hash hash(Edge edge) const
{
unsigned x = (edge == Edge::Right) ? rows_[0].size() - 1 : 0; unsigned x = (edge == Edge::Right) ? rows_[0].size() - 1 : 0;
unsigned y = (edge == Edge::Bottom) ? rows_.size() - 1 : 0; unsigned y = (edge == Edge::Bottom) ? rows_.size() - 1 : 0;
unsigned dx = (edge == Edge::Top || edge == Edge::Bottom) ? 1 : 0; unsigned dx = (edge == Edge::Top || edge == Edge::Bottom) ? 1 : 0;
@@ -74,19 +79,18 @@ struct Picture {
Id id() const noexcept { return id_; } Id id() const noexcept { return id_; }
bool operator<(Picture const &pict) const noexcept { return id_ < pict.id_; } bool operator<(Picture const& pict) const noexcept { return id_ < pict.id_; }
bool operator==(Picture const &pict) const noexcept { bool operator==(Picture const& pict) const noexcept { return id_ == pict.id_; }
return id_ == pict.id_;
}
bool in_use() const noexcept { return in_use_; } bool in_use() const noexcept { return in_use_; }
void use() noexcept { in_use_ = true; } void use() noexcept { in_use_ = true; }
void release() noexcept { in_use_ = false; } void release() noexcept { in_use_ = false; }
friend std::ostream &operator<<(std::ostream &os, Picture const &pict); friend std::ostream& operator<<(std::ostream& os, Picture const& pict);
unsigned find_monsters() { unsigned find_monsters()
{
for (unsigned r = 0; r < 4; ++r) { for (unsigned r = 0; r < 4; ++r) {
rotate(); rotate();
for (unsigned f = 0; f < 2; ++f) { for (unsigned f = 0; f < 2; ++f) {
@@ -101,9 +105,10 @@ struct Picture {
return 0; return 0;
} }
unsigned roughness() const { unsigned roughness() const
{
unsigned rough = 0; unsigned rough = 0;
for (auto const &r : rows_) { for (auto const& r : rows_) {
for (auto c : r) { for (auto c : r) {
if (c == '#') { if (c == '#') {
++rough; ++rough;
@@ -114,7 +119,8 @@ struct Picture {
} }
private: private:
unsigned find_monsters1() { unsigned find_monsters1()
{
// 0 1 // 0 1
// 01234567890123456789 // 01234567890123456789
// # // #
@@ -146,12 +152,13 @@ private:
for (std::size_t y = 0; y <= rows_.size() - mheight; ++y) { for (std::size_t y = 0; y <= rows_.size() - mheight; ++y) {
for (std::string::size_type x = 0; x <= rows_[y].size() - mwidth; ++x) { for (std::string::size_type x = 0; x <= rows_[y].size() - mwidth; ++x) {
std::size_t cy = 0; std::size_t cy = 0;
std::string::size_type const *cx = locs; std::string::size_type const* cx = locs;
bool found = true; bool found = true;
while (cy < mheight) { while (cy < mheight) {
if (*cx == std::string::npos) { if (*cx == std::string::npos) {
++cy; ++cy;
} else if (rows_[y + cy][x + *cx] != '#') { }
else if (rows_[y + cy][x + *cx] != '#') {
found = false; found = false;
break; break;
} }
@@ -160,11 +167,12 @@ private:
if (found) { if (found) {
++monster_count; ++monster_count;
std::size_t cy = 0; std::size_t cy = 0;
std::string::size_type const *cx = locs; std::string::size_type const* cx = locs;
while (cy < mheight) { while (cy < mheight) {
if (*cx == std::string::npos) { if (*cx == std::string::npos) {
++cy; ++cy;
} else { }
else {
rows_[y + cy][x + *cx] = '*'; rows_[y + cy][x + *cx] = '*';
} }
++cx; ++cx;
@@ -182,8 +190,9 @@ private:
bool in_use_; bool in_use_;
}; };
std::ostream &operator<<(std::ostream &os, Picture const &pict) { std::ostream& operator<<(std::ostream& os, Picture const& pict)
for (auto const &r : pict.rows_) { {
for (auto const& r : pict.rows_) {
os << r << '\n'; os << r << '\n';
} }
return os; return os;
@@ -193,14 +202,16 @@ using Pictures = std::map<Id, Picture>;
using HashMap = std::multimap<Hash, Id>; using HashMap = std::multimap<Hash, Id>;
using Array = std::map<std::pair<unsigned, unsigned>, Id>; using Array = std::map<std::pair<unsigned, unsigned>, Id>;
struct PictureArray { struct PictureArray
void add(Picture &&pic) { {
void add(Picture&& pic)
{
auto id = pic.id(); auto id = pic.id();
auto [it, success] = pictures_.insert(std::make_pair(id, std::move(pic))); auto [it, success] = pictures_.insert(std::make_pair(id, std::move(pic)));
assert(success); assert(success);
// Set up hash -> ID mapping // Set up hash -> ID mapping
Picture &picture = it->second; Picture& picture = it->second;
for (unsigned r = 0; r < 4; ++r) { for (unsigned r = 0; r < 4; ++r) {
for (unsigned f = 0; f < 2; ++f) { for (unsigned f = 0; f < 2; ++f) {
hash_map_.insert({picture.hash(Edge::Top), picture.id()}); hash_map_.insert({picture.hash(Edge::Top), picture.id()});
@@ -210,13 +221,13 @@ struct PictureArray {
} }
} }
Id solve() { Id solve()
{
assert(pictures_.size() == 9 || pictures_.size() == 144); assert(pictures_.size() == 9 || pictures_.size() == 144);
for (auto &kv : pictures_) { for (auto& kv : pictures_) {
if (try_position(0, 0, kv.second)) { if (try_position(0, 0, kv.second)) {
print_ids(); print_ids();
return piece(0, 0).id() * piece(width() - 1, 0).id() * return piece(0, 0).id() * piece(width() - 1, 0).id() * piece(0, height() - 1).id() *
piece(0, height() - 1).id() *
piece(width() - 1, height() - 1).id(); piece(width() - 1, height() - 1).id();
} }
} }
@@ -224,12 +235,15 @@ struct PictureArray {
assert(false); assert(false);
return 0; return 0;
} }
unsigned width() const noexcept { unsigned width() const noexcept
{
if (pictures_.size() == 9) { if (pictures_.size() == 9) {
return 3; return 3;
} else if (pictures_.size() == 144) { }
else if (pictures_.size() == 144) {
return 12; return 12;
} else { }
else {
assert(false); assert(false);
} }
@@ -238,16 +252,18 @@ struct PictureArray {
unsigned height() const noexcept { return width(); } unsigned height() const noexcept { return width(); }
Picture const &piece(unsigned x, unsigned y) const { Picture const& piece(unsigned x, unsigned y) const
auto const &it = array_.find({x, y}); {
auto const& it = array_.find({x, y});
assert(it != array_.end()); assert(it != array_.end());
auto const &itp = pictures_.find(it->second); auto const& itp = pictures_.find(it->second);
assert(itp != pictures_.end()); assert(itp != pictures_.end());
return itp->second; return itp->second;
} }
private: private:
bool try_position(unsigned x, unsigned y, Picture &pict) { bool try_position(unsigned x, unsigned y, Picture& pict)
{
if (pict.in_use()) { if (pict.in_use()) {
return false; return false;
} }
@@ -304,7 +320,8 @@ private:
return false; return false;
} }
void print_ids() const { void print_ids() const
{
for (unsigned y = 0; y < height(); ++y) { for (unsigned y = 0; y < height(); ++y) {
for (unsigned x = 0; x < width(); ++x) { for (unsigned x = 0; x < width(); ++x) {
std::cout << " " << piece(x, y).id(); std::cout << " " << piece(x, y).id();
@@ -318,11 +335,12 @@ private:
Array array_; Array array_;
}; };
Picture::Picture(PictureArray const &array) : id_(0), in_use_(false) { Picture::Picture(PictureArray const& array) : id_(0), in_use_(false)
{
for (unsigned y = 0; y < array.height(); ++y) { for (unsigned y = 0; y < array.height(); ++y) {
auto ybase = rows_.size(); auto ybase = rows_.size();
for (unsigned x = 0; x < array.width(); ++x) { for (unsigned x = 0; x < array.width(); ++x) {
auto &pict = array.piece(x, y); auto& pict = array.piece(x, y);
for (auto py = 1; py < pict.rows_.size() - 1; ++py) { for (auto py = 1; py < pict.rows_.size() - 1; ++py) {
auto yidx = ybase + py - 1; auto yidx = ybase + py - 1;
if (rows_.size() <= yidx) { if (rows_.size() <= yidx) {
@@ -336,7 +354,8 @@ Picture::Picture(PictureArray const &array) : id_(0), in_use_(false) {
assert(rows_[0].size() == array.width() * 8); assert(rows_[0].size() == array.width() * 8);
} }
int main(void) { int main(void)
{
PictureArray pictures_; PictureArray pictures_;
std::string line; std::string line;

View File

@@ -19,9 +19,11 @@ using IngredientInfo = std::pair<unsigned, Allergens>;
using IngredientMap = std::map<Ingredient, IngredientInfo>; using IngredientMap = std::map<Ingredient, IngredientInfo>;
using AllergenMap = std::map<Allergen, Ingredients>; using AllergenMap = std::map<Allergen, Ingredients>;
class IngredientParser { class IngredientParser
{
public: public:
void add_recipe(std::string const &s) { void add_recipe(std::string const& s)
{
auto it = s.begin(); auto it = s.begin();
Ingredients i; Ingredients i;
while (it != s.end()) { while (it != s.end()) {
@@ -33,10 +35,10 @@ public:
it = ite; it = ite;
if (ingredient == "(contains") { if (ingredient == "(contains") {
break; break;
} else { }
else {
i.insert(ingredient); i.insert(ingredient);
auto [iit, success] = auto [iit, success] = ingredients_.insert({ingredient, {1, Allergens()}});
ingredients_.insert({ingredient, {1, Allergens()}});
if (!success) { if (!success) {
iit->second.first++; iit->second.first++;
} }
@@ -44,8 +46,7 @@ public:
} }
while (it != s.end()) { while (it != s.end()) {
auto ite = std::find_if( auto ite = std::find_if(it, s.end(), [](char c) -> bool { return c == ',' || c == ')'; });
it, s.end(), [](char c) -> bool { return c == ',' || c == ')'; });
auto allergen = std::string(it, ite); auto allergen = std::string(it, ite);
++ite; ++ite;
while (ite != s.end() && *ite == ' ') { while (ite != s.end() && *ite == ' ') {
@@ -56,18 +57,18 @@ public:
if (!success) { if (!success) {
Ingredients a; Ingredients a;
std::set_intersection(i.begin(), i.end(), insert_it->second.begin(), std::set_intersection(i.begin(), i.end(), insert_it->second.begin(),
insert_it->second.end(), insert_it->second.end(), std::inserter(a, a.end()));
std::inserter(a, a.end()));
insert_it->second = a; insert_it->second = a;
} }
} }
} }
unsigned clean_ingredients() { unsigned clean_ingredients()
for (auto const &kv : allergens_) { {
for (auto const& kv : allergens_) {
auto allergen = kv.first; auto allergen = kv.first;
std::cout << "Allergen " << allergen << ":"; std::cout << "Allergen " << allergen << ":";
for (auto const &i : kv.second) { for (auto const& i : kv.second) {
std::cout << " " << i; std::cout << " " << i;
auto it = ingredients_.find(i); auto it = ingredients_.find(i);
assert(it != ingredients_.end()); assert(it != ingredients_.end());
@@ -77,10 +78,9 @@ public:
} }
unsigned count = 0; unsigned count = 0;
for (auto const &i : ingredients_) { for (auto const& i : ingredients_) {
if (i.second.second.size() == 0) { if (i.second.second.size() == 0) {
std::cout << i.first << " is not an allergen, appears " std::cout << i.first << " is not an allergen, appears " << i.second.first << ".\n";
<< i.second.first << ".\n";
count += i.second.first; count += i.second.first;
} }
} }
@@ -93,7 +93,8 @@ private:
AllergenMap allergens_; AllergenMap allergens_;
}; };
int main(void) { int main(void)
{
std::string line; std::string line;
IngredientParser parser; IngredientParser parser;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -19,9 +19,11 @@ using IngredientInfo = std::pair<unsigned, Allergens>;
using IngredientMap = std::map<Ingredient, IngredientInfo>; using IngredientMap = std::map<Ingredient, IngredientInfo>;
using AllergenMap = std::map<Allergen, Ingredients>; using AllergenMap = std::map<Allergen, Ingredients>;
class IngredientParser { class IngredientParser
{
public: public:
void add_recipe(std::string const &s) { void add_recipe(std::string const& s)
{
auto it = s.begin(); auto it = s.begin();
Ingredients i; Ingredients i;
while (it != s.end()) { while (it != s.end()) {
@@ -33,10 +35,10 @@ public:
it = ite; it = ite;
if (ingredient == "(contains") { if (ingredient == "(contains") {
break; break;
} else { }
else {
i.insert(ingredient); i.insert(ingredient);
auto [iit, success] = auto [iit, success] = ingredients_.insert({ingredient, {1, Allergens()}});
ingredients_.insert({ingredient, {1, Allergens()}});
if (!success) { if (!success) {
iit->second.first++; iit->second.first++;
} }
@@ -44,8 +46,7 @@ public:
} }
while (it != s.end()) { while (it != s.end()) {
auto ite = std::find_if( auto ite = std::find_if(it, s.end(), [](char c) -> bool { return c == ',' || c == ')'; });
it, s.end(), [](char c) -> bool { return c == ',' || c == ')'; });
auto allergen = std::string(it, ite); auto allergen = std::string(it, ite);
++ite; ++ite;
while (ite != s.end() && *ite == ' ') { while (ite != s.end() && *ite == ' ') {
@@ -56,18 +57,18 @@ public:
if (!success) { if (!success) {
Ingredients a; Ingredients a;
std::set_intersection(i.begin(), i.end(), insert_it->second.begin(), std::set_intersection(i.begin(), i.end(), insert_it->second.begin(),
insert_it->second.end(), insert_it->second.end(), std::inserter(a, a.end()));
std::inserter(a, a.end()));
insert_it->second = a; insert_it->second = a;
} }
} }
} }
unsigned clean_ingredients() { unsigned clean_ingredients()
for (auto const &kv : allergens_) { {
for (auto const& kv : allergens_) {
auto allergen = kv.first; auto allergen = kv.first;
std::cout << "Allergen " << allergen << ":"; std::cout << "Allergen " << allergen << ":";
for (auto const &i : kv.second) { for (auto const& i : kv.second) {
std::cout << " " << i; std::cout << " " << i;
auto it = ingredients_.find(i); auto it = ingredients_.find(i);
assert(it != ingredients_.end()); assert(it != ingredients_.end());
@@ -77,10 +78,9 @@ public:
} }
unsigned count = 0; unsigned count = 0;
for (auto const &i : ingredients_) { for (auto const& i : ingredients_) {
if (i.second.second.size() == 0) { if (i.second.second.size() == 0) {
std::cout << i.first << " is not an allergen, appears " std::cout << i.first << " is not an allergen, appears " << i.second.first << ".\n";
<< i.second.first << ".\n";
count += i.second.first; count += i.second.first;
} }
} }
@@ -88,23 +88,23 @@ public:
return count; return count;
} }
std::string dangerous_ingredients() { std::string dangerous_ingredients()
{
bool changed = true; bool changed = true;
Ingredients i; Ingredients i;
while (changed) { while (changed) {
changed = false; changed = false;
for (auto const &kv : allergens_) { for (auto const& kv : allergens_) {
if (kv.second.size() == 1) { if (kv.second.size() == 1) {
auto it = kv.second.begin(); auto it = kv.second.begin();
Ingredient const &ing = *it; Ingredient const& ing = *it;
auto [iit, success] = i.insert(ing); auto [iit, success] = i.insert(ing);
if (!success) { if (!success) {
continue; continue;
} }
changed = true; changed = true;
std::cout << "Allergen " << kv.first << " is in ingredient " << ing std::cout << "Allergen " << kv.first << " is in ingredient " << ing << "\n";
<< "\n"; for (auto& kv2 : allergens_) {
for (auto &kv2 : allergens_) {
if (kv2.second.size() != 1) { if (kv2.second.size() != 1) {
kv2.second.erase(ing); kv2.second.erase(ing);
} }
@@ -114,7 +114,7 @@ public:
} }
std::string result; std::string result;
for (auto const &kv : allergens_) { for (auto const& kv : allergens_) {
result += ","; result += ",";
result += *kv.second.begin(); result += *kv.second.begin();
} }
@@ -127,7 +127,8 @@ private:
AllergenMap allergens_; AllergenMap allergens_;
}; };
int main(void) { int main(void)
{
std::string line; std::string line;
IngredientParser parser; IngredientParser parser;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -14,8 +14,10 @@ using Card = unsigned;
using Cards = std::list<Card>; using Cards = std::list<Card>;
using Score = unsigned long; using Score = unsigned long;
struct Player { struct Player
Player(std::istream &is) { {
Player(std::istream& is)
{
std::string line; std::string line;
if (!std::getline(is, name_)) { if (!std::getline(is, name_)) {
assert(false); assert(false);
@@ -33,7 +35,8 @@ struct Player {
void pop_front() { cards_.pop_front(); } void pop_front() { cards_.pop_front(); }
void push_back(Card c) { cards_.push_back(c); } void push_back(Card c) { cards_.push_back(c); }
Score score() const { Score score() const
{
Score r = 0; Score r = 0;
unsigned idx = 1; unsigned idx = 1;
for (auto it = cards_.rbegin(); it != cards_.rend(); ++it) { for (auto it = cards_.rbegin(); it != cards_.rend(); ++it) {
@@ -48,7 +51,8 @@ private:
Cards cards_; Cards cards_;
}; };
Score play_game(Player &p1, Player &p2) { Score play_game(Player& p1, Player& p2)
{
while (!p1.empty() && !p2.empty()) { while (!p1.empty() && !p2.empty()) {
Card c1 = p1.front(); Card c1 = p1.front();
Card c2 = p2.front(); Card c2 = p2.front();
@@ -57,7 +61,8 @@ Score play_game(Player &p1, Player &p2) {
if (c1 > c2) { if (c1 > c2) {
p1.push_back(c1); p1.push_back(c1);
p1.push_back(c2); p1.push_back(c2);
} else if (c1 < c2) { }
else if (c1 < c2) {
p2.push_back(c2); p2.push_back(c2);
p2.push_back(c1); p2.push_back(c1);
} }
@@ -66,7 +71,8 @@ Score play_game(Player &p1, Player &p2) {
return p1.score() + p2.score(); return p1.score() + p2.score();
} }
int main(void) { int main(void)
{
Player player1(std::cin); Player player1(std::cin);
Player player2(std::cin); Player player2(std::cin);

View File

@@ -15,8 +15,10 @@ using Cards = std::list<Card>;
using Score = unsigned long; using Score = unsigned long;
using Hash = std::string; using Hash = std::string;
struct Player { struct Player
Player(std::istream &is) { {
Player(std::istream& is)
{
std::string line; std::string line;
if (!std::getline(is, name_)) { if (!std::getline(is, name_)) {
assert(false); assert(false);
@@ -35,7 +37,8 @@ struct Player {
void push_back(Card c) { cards_.push_back(c); } void push_back(Card c) { cards_.push_back(c); }
std::size_t size() const { return cards_.size(); } std::size_t size() const { return cards_.size(); }
Score score() const { Score score() const
{
Score r = 0; Score r = 0;
unsigned idx = 1; unsigned idx = 1;
for (auto it = cards_.rbegin(); it != cards_.rend(); ++it) { for (auto it = cards_.rbegin(); it != cards_.rend(); ++it) {
@@ -45,7 +48,8 @@ struct Player {
return r; return r;
} }
Hash hash() const { Hash hash() const
{
std::string r = name_; std::string r = name_;
for (auto c : cards_) { for (auto c : cards_) {
assert(c > 0); assert(c > 0);
@@ -56,21 +60,23 @@ struct Player {
return r; return r;
} }
Player(Player const &prev, Card size) : name_(prev.name_ + "-") { Player(Player const& prev, Card size) : name_(prev.name_ + "-")
{
auto it = prev.cards_.begin(); auto it = prev.cards_.begin();
for (Card i = 0; i < size; ++i) { for (Card i = 0; i < size; ++i) {
cards_.push_back(*it++); cards_.push_back(*it++);
} }
} }
friend std::ostream &operator<<(std::ostream &os, Player const &p); friend std::ostream& operator<<(std::ostream& os, Player const& p);
private: private:
std::string name_; std::string name_;
Cards cards_; Cards cards_;
}; };
std::ostream &operator<<(std::ostream &os, Player const &p) { std::ostream& operator<<(std::ostream& os, Player const& p)
{
os << p.name_; os << p.name_;
for (auto c : p.cards_) { for (auto c : p.cards_) {
os << " " << c; os << " " << c;
@@ -79,7 +85,8 @@ std::ostream &operator<<(std::ostream &os, Player const &p) {
} }
// False = p1 wins, true = p2 wins. // False = p1 wins, true = p2 wins.
bool play_game(Player &p1, Player &p2) { bool play_game(Player& p1, Player& p2)
{
std::set<Hash> hashes; std::set<Hash> hashes;
while (!p1.empty() && !p2.empty()) { while (!p1.empty() && !p2.empty()) {
@@ -100,17 +107,21 @@ bool play_game(Player &p1, Player &p2) {
if (!result) { if (!result) {
p1.push_back(c1); p1.push_back(c1);
p1.push_back(c2); p1.push_back(c2);
} else { }
else {
p2.push_back(c2); p2.push_back(c2);
p2.push_back(c1); p2.push_back(c1);
} }
} else if (c1 > c2) { }
else if (c1 > c2) {
p1.push_back(c1); p1.push_back(c1);
p1.push_back(c2); p1.push_back(c2);
} else if (c1 < c2) { }
else if (c1 < c2) {
p2.push_back(c2); p2.push_back(c2);
p2.push_back(c1); p2.push_back(c1);
} else { }
else {
assert(false); assert(false);
} }
} }
@@ -118,7 +129,8 @@ bool play_game(Player &p1, Player &p2) {
return p1.empty(); return p1.empty();
} }
int main(void) { int main(void)
{
Player player1(std::cin); Player player1(std::cin);
Player player2(std::cin); Player player2(std::cin);

View File

@@ -10,12 +10,12 @@
#include <tuple> #include <tuple>
#include <vector> #include <vector>
struct Cups { struct Cups
Cups(std::string const &s) : s_(s) { {
std::cout << "Initial state: " << s_ << "\n"; Cups(std::string const& s) : s_(s) { std::cout << "Initial state: " << s_ << "\n"; }
}
void play(unsigned moves) { void play(unsigned moves)
{
// We assume the current value is always at index 0. // We assume the current value is always at index 0.
// So the values to remove are in offsets [1, 4). // So the values to remove are in offsets [1, 4).
while (moves-- > 0) { while (moves-- > 0) {
@@ -27,13 +27,13 @@ struct Cups {
d = d == '1' ? '9' : d - 1; d = d == '1' ? '9' : d - 1;
} }
s_ = s_.substr(4, dest - 3) + s_.substr(1, 3) + s_.substr(dest + 1) + s_ = s_.substr(4, dest - 3) + s_.substr(1, 3) + s_.substr(dest + 1) + s_[0];
s_[0];
std::cout << moves << ": " << s_ << "\n"; std::cout << moves << ": " << s_ << "\n";
} }
} }
std::string result() const { std::string result() const
{
auto split = s_.find('1'); auto split = s_.find('1');
return s_.substr(split + 1) + s_.substr(0, split); return s_.substr(split + 1) + s_.substr(0, split);
} }
@@ -42,7 +42,8 @@ private:
std::string s_; std::string s_;
}; };
int main(void) { int main(void)
{
std::string line; std::string line;
std::getline(std::cin, line); std::getline(std::cin, line);
Cups cups(line); Cups cups(line);

View File

@@ -11,24 +11,27 @@
#include <vector> #include <vector>
using Value = unsigned long; using Value = unsigned long;
struct Cup { struct Cup
{
Cup() : value_(0), next_(nullptr) {} Cup() : value_(0), next_(nullptr) {}
Value value() const { return value_; } Value value() const { return value_; }
void value(Value v) { value_ = v; } void value(Value v) { value_ = v; }
Cup *next() const { return next_; } Cup* next() const { return next_; }
void next(Cup *n) { next_ = n; } void next(Cup* n) { next_ = n; }
private: private:
Value value_; Value value_;
Cup *next_; Cup* next_;
}; };
struct Cups { struct Cups
{
static constexpr std::size_t num_cups_ = 1000000; static constexpr std::size_t num_cups_ = 1000000;
static constexpr std::size_t num_moves_ = 10000000; static constexpr std::size_t num_moves_ = 10000000;
Cups(std::string const &s) : cups_(new Cup[num_cups_]), current_(cups_) { Cups(std::string const& s) : cups_(new Cup[num_cups_]), current_(cups_)
{
std::size_t idx = 0; std::size_t idx = 0;
for (auto c : s) { for (auto c : s) {
cups_[idx].value(c - '0'); cups_[idx].value(c - '0');
@@ -47,17 +50,18 @@ struct Cups {
~Cups() { delete[] cups_; } ~Cups() { delete[] cups_; }
void play() { void play()
{
for (std::size_t move = 0; move < num_moves_; ++move) { for (std::size_t move = 0; move < num_moves_; ++move) {
if (move % 1000 == 0) { if (move % 1000 == 0) {
std::cout << "A" << move << " " << current_ - cups_ << " " std::cout << "A" << move << " " << current_ - cups_ << " " << current_->value() << " "
<< current_->value() << " " << result() << "\n"; << result() << "\n";
// print(); // print();
} }
// Remove first three after current. // Remove first three after current.
Cup *rb = current_->next(); Cup* rb = current_->next();
Cup *re = rb->next()->next(); Cup* re = rb->next()->next();
current_->next(re->next()); current_->next(re->next());
re->next(nullptr); re->next(nullptr);
@@ -74,14 +78,15 @@ struct Cups {
// Where do we insert? Note that we use the hack that all the values are // Where do we insert? Note that we use the hack that all the values are
// actually in an index and we know what the value is (roughly) based on // actually in an index and we know what the value is (roughly) based on
// the index. // the index.
Cup *ins = nullptr; Cup* ins = nullptr;
if (vm1 < 10) { if (vm1 < 10) {
ins = cups_; ins = cups_;
while (ins->value() != vm1) { while (ins->value() != vm1) {
assert(ins != cups_ + 10); assert(ins != cups_ + 10);
++ins; ++ins;
} }
} else { }
else {
ins = cups_ + vm1 - 1; ins = cups_ + vm1 - 1;
} }
@@ -96,8 +101,9 @@ struct Cups {
} }
} }
Value result() const { Value result() const
Cup *one = cups_; {
Cup* one = cups_;
while (one->value() != 1) { while (one->value() != 1) {
++one; ++one;
assert(one != cups_ + num_cups_); assert(one != cups_ + num_cups_);
@@ -106,9 +112,10 @@ struct Cups {
return one->next()->value() * one->next()->next()->value(); return one->next()->value() * one->next()->next()->value();
} }
void print() const { void print() const
{
std::cout << "State:"; std::cout << "State:";
Cup const *c = current_; Cup const* c = current_;
do { do {
std::cout << " " << c->value(); std::cout << " " << c->value();
c = c->next(); c = c->next();
@@ -117,11 +124,12 @@ struct Cups {
} }
private: private:
Cup *cups_; Cup* cups_;
Cup *current_; Cup* current_;
}; };
int main(void) { int main(void)
{
std::string line; std::string line;
std::getline(std::cin, line); std::getline(std::cin, line);
Cups cups(line); Cups cups(line);

View File

@@ -14,8 +14,10 @@ using Coord = long;
using Position = std::pair<Coord, Coord>; using Position = std::pair<Coord, Coord>;
using Tiles = std::set<Position>; using Tiles = std::set<Position>;
struct Tiler { struct Tiler
void flip_tile(std::string const &s) { {
void flip_tile(std::string const& s)
{
Coord x = 0; Coord x = 0;
Coord y = 0; Coord y = 0;
auto it = s.begin(); auto it = s.begin();
@@ -30,9 +32,11 @@ struct Tiler {
if (*it == 'e') { if (*it == 'e') {
x += dx; x += dx;
} else if (*it == 'w') { }
else if (*it == 'w') {
x -= dx; x -= dx;
} else { }
else {
assert(false); assert(false);
} }
++it; ++it;
@@ -51,7 +55,8 @@ private:
Tiles black_tiles_; Tiles black_tiles_;
}; };
int main(void) { int main(void)
{
Tiler tiler; Tiler tiler;
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -12,14 +12,17 @@
using Coord = long; using Coord = long;
using Position = std::pair<Coord, Coord>; using Position = std::pair<Coord, Coord>;
struct State { struct State
{
bool black_ = false; bool black_ = false;
int neighbours_ = 0; int neighbours_ = 0;
}; };
using Tiles = std::map<Position, State>; using Tiles = std::map<Position, State>;
struct Tiler { struct Tiler
void flip_tile(std::string const &s) { {
void flip_tile(std::string const& s)
{
Coord x = 0; Coord x = 0;
Coord y = 0; Coord y = 0;
auto it = s.begin(); auto it = s.begin();
@@ -34,9 +37,11 @@ struct Tiler {
if (*it == 'e') { if (*it == 'e') {
x += dx; x += dx;
} else if (*it == 'w') { }
else if (*it == 'w') {
x -= dx; x -= dx;
} else { }
else {
assert(false); assert(false);
} }
++it; ++it;
@@ -46,13 +51,14 @@ struct Tiler {
flip_tile(x, y); flip_tile(x, y);
} }
Tiler next_state() const { Tiler next_state() const
{
Tiler next(*this); Tiler next(*this);
for (auto const &kv : tiles_) { for (auto const& kv : tiles_) {
if (kv.second.black_ && if (kv.second.black_ && (kv.second.neighbours_ == 0 || kv.second.neighbours_ > 2)) {
(kv.second.neighbours_ == 0 || kv.second.neighbours_ > 2)) {
next.flip_tile(kv.first.first, kv.first.second); next.flip_tile(kv.first.first, kv.first.second);
} else if (!kv.second.black_ && kv.second.neighbours_ == 2) { }
else if (!kv.second.black_ && kv.second.neighbours_ == 2) {
next.flip_tile(kv.first.first, kv.first.second); next.flip_tile(kv.first.first, kv.first.second);
} }
} }
@@ -60,9 +66,10 @@ struct Tiler {
return next; return next;
} }
std::size_t black_count() const noexcept { std::size_t black_count() const noexcept
{
std::size_t count = 0; std::size_t count = 0;
for (auto const &kv : tiles_) { for (auto const& kv : tiles_) {
count += kv.second.black_; count += kv.second.black_;
} }
@@ -70,7 +77,8 @@ struct Tiler {
} }
private: private:
void set_neighbours(Coord x, Coord y, int delta) { void set_neighbours(Coord x, Coord y, int delta)
{
set_neighbour(x + 2, y, delta); set_neighbour(x + 2, y, delta);
set_neighbour(x + 1, y - 1, delta); set_neighbour(x + 1, y - 1, delta);
set_neighbour(x - 1, y - 1, delta); set_neighbour(x - 1, y - 1, delta);
@@ -79,7 +87,8 @@ private:
set_neighbour(x + 1, y + 1, delta); set_neighbour(x + 1, y + 1, delta);
} }
void set_neighbour(Coord x, Coord y, int delta) { void set_neighbour(Coord x, Coord y, int delta)
{
auto [it, success] = tiles_.insert({{x, y}, {false, delta}}); auto [it, success] = tiles_.insert({{x, y}, {false, delta}});
if (!success) { if (!success) {
it->second.neighbours_ += delta; it->second.neighbours_ += delta;
@@ -87,14 +96,16 @@ private:
assert(it->second.neighbours_ >= 0); assert(it->second.neighbours_ >= 0);
} }
void flip_tile(Coord x, Coord y) { void flip_tile(Coord x, Coord y)
{
auto [it, success] = tiles_.insert({{x, y}, {true, 0}}); auto [it, success] = tiles_.insert({{x, y}, {true, 0}});
if (!success) { if (!success) {
it->second.black_ = !it->second.black_; it->second.black_ = !it->second.black_;
} }
if (it->second.black_) { if (it->second.black_) {
set_neighbours(x, y, 1); set_neighbours(x, y, 1);
} else { }
else {
set_neighbours(x, y, -1); set_neighbours(x, y, -1);
} }
} }
@@ -103,7 +114,8 @@ private:
Tiles tiles_; Tiles tiles_;
}; };
int main(void) { int main(void)
{
Tiler tiler; Tiler tiler;
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {

View File

@@ -13,11 +13,13 @@
constexpr unsigned mod = 20201227; constexpr unsigned mod = 20201227;
constexpr unsigned initial_subject = 7; constexpr unsigned initial_subject = 7;
unsigned lcg(unsigned i, unsigned subject) { unsigned lcg(unsigned i, unsigned subject)
{
return ((unsigned long)i * (unsigned long)subject) % mod; return ((unsigned long)i * (unsigned long)subject) % mod;
} }
unsigned find_loop_length(unsigned pk) { unsigned find_loop_length(unsigned pk)
{
unsigned v = 1; unsigned v = 1;
unsigned loop = 0; unsigned loop = 0;
while (v != pk) { while (v != pk) {
@@ -28,7 +30,8 @@ unsigned find_loop_length(unsigned pk) {
return loop; return loop;
} }
unsigned apply(unsigned pk, unsigned loop_size) { unsigned apply(unsigned pk, unsigned loop_size)
{
unsigned v = 1; unsigned v = 1;
for (unsigned i = 0; i < loop_size; ++i) { for (unsigned i = 0; i < loop_size; ++i) {
v = lcg(v, pk); v = lcg(v, pk);
@@ -37,7 +40,8 @@ unsigned apply(unsigned pk, unsigned loop_size) {
return v; return v;
} }
int main(void) { int main(void)
{
std::string line; std::string line;
std::getline(std::cin, line); std::getline(std::cin, line);
unsigned pk1 = std::stoul(line); unsigned pk1 = std::stoul(line);

View File

@@ -3,11 +3,12 @@
// //
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <limits> #include <limits>
#include <string> #include <string>
#include <iostream>
int main(void) { int main(void)
{
unsigned long prev{std::numeric_limits<unsigned long>::max()}; unsigned long prev{std::numeric_limits<unsigned long>::max()};
unsigned incrs{0}; unsigned incrs{0};
std::string line; std::string line;

Some files were not shown because too many files have changed in this diff Show More