And a bit more to the point...
Love Ed's writing. Naturally, he had a "premium subscriber sale" on, about two days after I paid full price for it. Still worth every penny, tho.
And a bit more to the point...
Love Ed's writing. Naturally, he had a "premium subscriber sale" on, about two days after I paid full price for it. Still worth every penny, tho.
There's times when I want to find "exact matches and nothing but" - searching for error messages, for instance - and that's made much harder than it should be by AI bullshit search engines that don't want you to switch off their "helpful" features. Considering moving to Kagi instead.
Well, look at you, still got vodka by the afternoon of the first day.
Mine was my local Forgejo server, NAS server, DHCP -> DNS server for ad blocking on devices connected to the network, torrent server, syncthing server for mobile phone backup, and Arch Linux proxy, since I've a couple of machines that basically pull the same updates as each other.
I've retired it in favour of a mini PC, so it's back to being a RetroPie server, have loads of old games available in the spare room for when we have a party, amuses children of all ages.
They're quite capable machines. If they weren't so I/O limited, they'd be amazing. They tend to max out at 10 megabyte/second on SD card or over USB / ethernet. If you don't need a faster disk than that, they're likely to be ideal in the role.
Got the most actual quoted lines from the book of any film version, plus you've got all of Dicken's direct-to-reader moralising delivered by Gonzo. And as well as being very faithful to the book, it is a superb film as well.
Michael Caine excels as Scrooge, too. I wouldn't say that he was better than Alastair Sim was in his version - that's a performance that would take some beating - but there's not much in it.
Yeah. The OpenXCom makes troop movement incredibly fast, by colouring every square you can move to with whether you'll still be able to do an aimed shot / snap shot / auto shot. It makes most missions quick, a mystery why it wasn't implemented that way in the first place. Very similar in effect to XCOM's move-and-shoot or dash highlighting.
I think @ChicoSuave@lemmy.world has a very good point - the Firaxis changes do make the decisions a lot more consequential. In UFO, you'd still want to have your highly-ranked, psionic and sniper troops out on missions - just those guys get decent armour and they stay at the back, since they're too valuable to take point. Certainly too valuable to go prowling the corridors with a cattle prod in hand, and that's essential for overall victory. I do very much like the Firaxis games in general - I finished XCOM1 on classic+ironman - but the decisions are borderline 'too consequential'. It's difficult to get a decent stock of high-ranking troops, so losing any of them hurts a lot. And PP just goes much too far.
Even a 'good' mission in UFO can have as many troop casualties as an entire XCOM campaign. Good tactics help, but it's a brutal war against a terrible foe.
In the original UFO: Enemy Unknown, your rookie troops are eminently replaceable and you can send them out 14 at a time to get some experience. Sending complete rookies first in first to breach UFOs is completely viable. If they survive, they'll get some kills and level up. If not, well, bad luck. A total team kill and loss of the plane is a bit of a set back, but you're humanity's last hope and there's plenty more where that came from.
The XCom remakes have a very ungenerous deployment limit, plus the skills your troops earn cause the game to get a bit unbalanced; if you're good at not losing anyone then it gets really quite easy. Training up rookies is an ordeal, because they take up a very valuable slot and you need the skills that come with experience.
Pheonix Point is incredibly random, and getting extra troops is an unbelievable ordeal. You might as well have quicksave and quickload bound to mouse buttons, since one bad roll of the dice could be a campaign loss. Incredibly conservative and boring strategies are essential. It's not fun to play.
I've always seen it as a "take turns at being the guesser, and whoever does best wins" kind of game. If you take six goes and your opponent takes seven, then taste that sweet victory.
A digression, but the "viking chess" game Hnefatfl basically guarantees a win for white as written. So you need to mix it up - play two games, see who wins fastest; or constrain it like backgammon, roll dice and that's the moves you must make.
For the test cases (ironically, the only difficult ones) it finds the solution for 1 basically instantly, 2 in 0.2 seconds, and checks all possibilities for 3 in about 18 seconds before rejecting it.
For the thousand 'puzzle' cases, about half are rejected since the area is simply too small for the presents in an instant. A possible solution is found for all of them in about 80 seconds, so about five per second.
I was concerned that the puzzle cases were about four times the area, and some of them had 255 presents (which might be the maximum stack depth in some languages - not C++, though). So maybe some of them would find a solution quickly, and excluding the worst might take ~ 4 times the size * 30 times the presents * 20 seconds = the best part of an hour. Multithreading it and hoping not too many of them were 'worst case', and I could leave my computer on overnight number-crunching it. Box packing is NP-complete and we need a 'true' answer rather than an approximation, so I couldn't see any better way of doing it than checking every possibility. Sorting the list didn't really show any evidence of puzzles that could be 'pruned' - areas that were the same but with increasing numbers of presents, say, so that you could reject the larger ones after the first failure.
Was kicking myself when it ran so quickly.
Hah, got me good too Mr Wastl. Was wondering how long this could possibly take to run - the worst-case is very bad indeed. This prints out the first "fit" it finds, for verification purposes, and keeps the successful ones in case they're needed for "part 2".
Merry Xmas, everyone.
#include <boost/describe.hpp>
#include <boost/describe/operators.hpp>
#include <boost/log/trivial.hpp>
#include <boost/unordered/unordered_flat_set.hpp>
#include <fstream>
#include <iostream>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>
namespace {
struct Point {
int x, y;
};
BOOST_DESCRIBE_STRUCT(Point, (), (x, y))
using boost::describe::operators::operator==;
using Present = boost::unordered::unordered_flat_set<Point>;
using PresentList = std::vector<size_t>;
struct Tree {
int width;
int height;
PresentList presents;
};
auto operator<<(std::ostream &o, const Tree &t) -> std::ostream & {
o << t.width << 'x' << t.height << ": ";
auto total = size_t{};
for (auto &p : t.presents) {
o << p << ' ';
total += p;
}
return o << "(" << total << ")";
}
auto copy_if(const Present &in, Present &out, const Point &a, const Point &b) {
if (in.contains(a))
out.insert(b);
}
auto rotate(const Present &in) {
auto out = Present{};
copy_if(in, out, {0, 0}, {2, 0});
copy_if(in, out, {1, 0}, {2, 1});
copy_if(in, out, {2, 0}, {2, 2});
copy_if(in, out, {0, 1}, {1, 0});
copy_if(in, out, {1, 1}, {1, 1});
copy_if(in, out, {2, 1}, {1, 2});
copy_if(in, out, {0, 2}, {0, 0});
copy_if(in, out, {1, 2}, {0, 1});
copy_if(in, out, {2, 2}, {0, 2});
return out;
}
auto hflip(const Present &in) {
auto out = Present{};
for (auto x = 0; x < 3; ++x)
for (auto y = 0; y < 3; ++y)
copy_if(in, out, {x, y}, {2 - x, y});
return out;
}
auto vflip(const Present &in) {
auto out = Present{};
for (auto x = 0; x < 3; ++x)
for (auto y = 0; y < 3; ++y)
copy_if(in, out, {x, y}, {x, 2 - y});
return out;
}
struct Puzzle {
std::vector<Present> presents;
std::vector<Tree> trees;
};
auto read() {
auto rval = Puzzle{};
auto ih = std::ifstream{"12.txt"};
auto line = std::string{};
for (auto i = 0; i < 6; ++i) {
std::getline(ih, line); // number
auto present = Present{};
for (auto y = size_t{}; y < 3; ++y) {
std::getline(ih, line);
for (auto x = size_t{}; x < 3; ++x) {
if (line.at(x) == '#')
present.emplace(x, y);
}
}
std::getline(ih, line); // following space
rval.presents.push_back(std::move(present));
}
while (std::getline(ih, line)) {
auto tree = Tree{};
auto times = line.find('x');
auto colon = line.find(':');
tree.width = std::stoi(line.substr(0, times));
tree.height = std::stoi(line.substr(times + 1, colon - times - 1));
auto count = size_t{};
auto ss = std::istringstream{line.substr(colon + 1)};
while (ss >> count)
tree.presents.push_back(count);
rval.trees.push_back(std::move(tree));
}
return rval;
}
using Occupied = boost::unordered::unordered_flat_set<Point>;
using PresentFlips = boost::unordered::unordered_flat_set<Present>;
using PresentFlipsList = std::vector<PresentFlips>;
auto place_present(
Occupied occupied,
const Present &present,
const Point &origin
) -> std::optional<Occupied> {
for (const auto &point : present) {
auto px = origin.x + point.x;
auto py = origin.y + point.y;
if (occupied.contains({px, py}))
return {};
occupied.insert({px, py});
}
return {occupied};
}
auto draw_occupied(const Tree &t, const Occupied &occupied) {
for (auto x = 0; x < t.width; ++x) {
for (auto y = 0; y < t.height; ++y) {
if (occupied.contains({x, y}))
std::cout << '#';
else
std::cout << '.';
}
std::cout << '\n';
}
}
auto can_place(
const Tree &tree,
const PresentFlipsList &flips,
Occupied occupied,
PresentList list
) -> bool {
auto j = size_t{};
for (; j < list.size(); ++j) {
if (list.at(j) > 0)
break;
}
if (j == list.size()) {
draw_occupied(tree, occupied);
return true; // yeah!
}
list[j]--;
for (auto x = 0; x < tree.width - 2; ++x)
for (auto y = 0; y < tree.height - 2; ++y) {
for (auto &flip : flips.at(j)) {
auto test = place_present(occupied, flip, {x, y});
if (!test.has_value())
continue;
auto works = can_place(tree, flips, test.value(), list);
if (works)
return true;
}
}
return false;
}
auto part1(const Puzzle &puzzle) {
auto possible = std::vector<Tree>{};
for (const auto &tree : puzzle.trees) {
auto area = size_t(tree.width * tree.height);
auto used = size_t{};
for (auto present = size_t{}; present < puzzle.presents.size(); ++present) {
used += tree.presents.at(present) * puzzle.presents.at(present).size();
}
if (used > area)
continue;
possible.push_back(tree);
}
auto flips = PresentFlipsList{};
for (auto j = size_t{}; j < puzzle.presents.size(); ++j) {
auto flip = PresentFlips{};
auto rotation = puzzle.presents.at(j);
for (auto i = 0; i < 4; ++i) {
flip.insert(rotation);
flip.insert(hflip(rotation));
flip.insert(vflip(rotation));
flip.insert(hflip(vflip(rotation)));
rotation = rotate(rotation);
}
BOOST_LOG_TRIVIAL(debug) << j << " has " << flip.size() << " flips";
flips.push_back(std::move(flip));
}
auto confirmed = std::vector<Tree>{};
for (auto &tree : possible)
if (can_place(tree, flips, Occupied{}, tree.presents)) {
BOOST_LOG_TRIVIAL(debug) << tree << " can be placed";
confirmed.push_back(std::move(tree));
} else {
BOOST_LOG_TRIVIAL(debug) << tree << " can't be placed";
}
return confirmed.size();
}
} // namespace
auto main() -> int {
auto puzzle = read();
BOOST_LOG_TRIVIAL(info) << "Day 12: read " << puzzle.presents.size() << " / "
<< puzzle.trees.size();
BOOST_LOG_TRIVIAL(info) << "1:" << part1(puzzle);
}
Zelda 3? You get fast travel quite early and the world is packed with stuff, it's not absurdly huge. Doesn't have that bloody owl in it either, telling you the obvious at great length.
Certainly not Wind Waker, anyway. Now there is a slow game.
Data centre GPUs tend not to have video outputs, and have power (and active cooling!) requirements in the "several kW" range. You might be able to snag one for work, if you work at a university or at somewhere that does a lot of 3D rendering - I'm thinking someone like Pixar. They are not the most convenient or useful things for a home build.
When the bubble bursts, they will mostly be used for creating a small mountain of e-waste, since the infrastructure to even switch them on costs more than the value they could ever bring.