|
@@ -0,0 +1,188 @@
|
|
|
+#include "starfield.h"
|
|
|
+
|
|
|
+starfield::starfield(door::Door &Door, std::mt19937 &Rng)
|
|
|
+ : door{Door}, rng{Rng} {
|
|
|
+ regenerate();
|
|
|
+}
|
|
|
+
|
|
|
+void starfield::regenerate(void) {
|
|
|
+ int mx = door.width;
|
|
|
+ int my = door.height;
|
|
|
+
|
|
|
+ // Make uniform random distribution between 1 and MAX screen size X/Y
|
|
|
+ std::uniform_int_distribution<int> uni_x(1, mx);
|
|
|
+ std::uniform_int_distribution<int> uni_y(1, my);
|
|
|
+
|
|
|
+ // 10 is too many, 100 is too few. 40 looks ok.
|
|
|
+ int MAX_STARS = ((mx * my) / 40);
|
|
|
+ // door.log() << "Generating starmap using " << mx << "," << my << " : "
|
|
|
+ // << MAX_STARS << " stars." << std::endl;
|
|
|
+
|
|
|
+ for (int i = 0; i < MAX_STARS; i++) {
|
|
|
+ star_pos pos;
|
|
|
+ bool valid;
|
|
|
+ do {
|
|
|
+ pos.x = uni_x(rng);
|
|
|
+ pos.y = uni_y(rng);
|
|
|
+ auto ret = sky.insert(pos);
|
|
|
+ // was insert a success? (not a duplicate)
|
|
|
+ valid = ret.second;
|
|
|
+ } while (!valid);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void starfield::display(void) {
|
|
|
+ door << door::reset << door::cls;
|
|
|
+
|
|
|
+ door::ANSIColor white(door::COLOR::WHITE);
|
|
|
+ door::ANSIColor dark(door::COLOR::BLACK, door::ATTR::BRIGHT);
|
|
|
+
|
|
|
+ // display starfield
|
|
|
+ const char *stars[2];
|
|
|
+
|
|
|
+ stars[0] = ".";
|
|
|
+ if (door::unicode) {
|
|
|
+ stars[1] = "\u2219"; // "\u00b7";
|
|
|
+
|
|
|
+ } else {
|
|
|
+ stars[1] = "\xf9"; // "\xfa";
|
|
|
+ };
|
|
|
+
|
|
|
+ int i = 0;
|
|
|
+ star_pos last_pos;
|
|
|
+
|
|
|
+ for (auto &pos : sky) {
|
|
|
+ bool use_goto = true;
|
|
|
+
|
|
|
+ if (i != 0) {
|
|
|
+ // check last_pos to current position
|
|
|
+ if (pos.y == last_pos.y) {
|
|
|
+ // Ok, same row -- try some optimizations
|
|
|
+ int dx = pos.x - last_pos.x;
|
|
|
+ if (dx == 0) {
|
|
|
+ use_goto = false;
|
|
|
+ } else {
|
|
|
+ if (dx < 5) {
|
|
|
+ door << std::string(dx, ' ');
|
|
|
+ use_goto = false;
|
|
|
+ } else {
|
|
|
+ // Use ANSI Cursor Forward
|
|
|
+ door << "\x1b[" << dx << "C";
|
|
|
+ use_goto = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (use_goto) {
|
|
|
+ door::Goto star_at(pos.x, pos.y);
|
|
|
+ door << star_at;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i % 5 < 2)
|
|
|
+ door << dark;
|
|
|
+ else
|
|
|
+ door << white;
|
|
|
+
|
|
|
+ if (i % 2 == 0)
|
|
|
+ door << stars[0];
|
|
|
+ else
|
|
|
+ door << stars[1];
|
|
|
+
|
|
|
+ ++i;
|
|
|
+ last_pos = pos;
|
|
|
+ last_pos.x++; // star output moves us by one.
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void display___starfield(door::Door &door, std::mt19937 &rng) {
|
|
|
+ door << door::reset << door::cls;
|
|
|
+
|
|
|
+ int mx = door.width;
|
|
|
+ int my = door.height;
|
|
|
+
|
|
|
+ // display starfield
|
|
|
+ const char *stars[2];
|
|
|
+
|
|
|
+ stars[0] = ".";
|
|
|
+ if (door::unicode) {
|
|
|
+ stars[1] = "\u2219"; // "\u00b7";
|
|
|
+
|
|
|
+ } else {
|
|
|
+ stars[1] = "\xf9"; // "\xfa";
|
|
|
+ };
|
|
|
+
|
|
|
+ {
|
|
|
+ // Make uniform random distribution between 1 and MAX screen size X/Y
|
|
|
+ std::uniform_int_distribution<int> uni_x(1, mx);
|
|
|
+ std::uniform_int_distribution<int> uni_y(1, my);
|
|
|
+
|
|
|
+ door::ANSIColor white(door::COLOR::WHITE);
|
|
|
+ door::ANSIColor dark(door::COLOR::BLACK, door::ATTR::BRIGHT);
|
|
|
+
|
|
|
+ // 10 is too many, 100 is too few. 40 looks ok.
|
|
|
+ int MAX_STARS = ((mx * my) / 40);
|
|
|
+ // door.log() << "Generating starmap using " << mx << "," << my << " : "
|
|
|
+ // << MAX_STARS << " stars." << std::endl;
|
|
|
+
|
|
|
+ std::set<star_pos> sky;
|
|
|
+
|
|
|
+ for (int i = 0; i < MAX_STARS; i++) {
|
|
|
+ star_pos pos;
|
|
|
+ bool valid;
|
|
|
+ do {
|
|
|
+ pos.x = uni_x(rng);
|
|
|
+ pos.y = uni_y(rng);
|
|
|
+ auto ret = sky.insert(pos);
|
|
|
+ // was insert a success? (not a duplicate)
|
|
|
+ valid = ret.second;
|
|
|
+ } while (!valid);
|
|
|
+ }
|
|
|
+
|
|
|
+ int i = 0;
|
|
|
+ star_pos last_pos;
|
|
|
+
|
|
|
+ for (auto &pos : sky) {
|
|
|
+ bool use_goto = true;
|
|
|
+
|
|
|
+ if (i != 0) {
|
|
|
+ // check last_pos to current position
|
|
|
+ if (pos.y == last_pos.y) {
|
|
|
+ // Ok, same row -- try some optimizations
|
|
|
+ int dx = pos.x - last_pos.x;
|
|
|
+ if (dx == 0) {
|
|
|
+ use_goto = false;
|
|
|
+ } else {
|
|
|
+ if (dx < 5) {
|
|
|
+ door << std::string(dx, ' ');
|
|
|
+ use_goto = false;
|
|
|
+ } else {
|
|
|
+ // Use ANSI Cursor Forward
|
|
|
+ door << "\x1b[" << dx << "C";
|
|
|
+ use_goto = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (use_goto) {
|
|
|
+ door::Goto star_at(pos.x, pos.y);
|
|
|
+ door << star_at;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i % 5 < 2)
|
|
|
+ door << dark;
|
|
|
+ else
|
|
|
+ door << white;
|
|
|
+
|
|
|
+ if (i % 2 == 0)
|
|
|
+ door << stars[0];
|
|
|
+ else
|
|
|
+ door << stars[1];
|
|
|
+
|
|
|
+ ++i;
|
|
|
+ last_pos = pos;
|
|
|
+ last_pos.x++; // star output moves us by one.
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|