Refactor code style, comments, and robot implementations
Move UML PDF to doc/ and update .gitignore. Normalize includes, whitespace and function signatures across headers/sources and add concise class/function documentation. Fix RandomBot so the mine limit is computed once and simplify DigDeepBot/SortBot mining logic. Tidy World/Game initialization, error handling, and minor const/var clarifications for readability and correctness
This commit is contained in:
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
uml_diagram.tex
|
uml_diagram.tex
|
||||||
.zed/
|
.zed/
|
||||||
.idea/
|
.idea/
|
||||||
cmake-build-debug/
|
.ignore/
|
||||||
|
cmake-build-debug
|
||||||
|
|||||||
+14
-11
@@ -4,25 +4,28 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
/* Base robot implementation shared by all concrete robot types. */
|
||||||
class BaseRobot : public Robot {
|
class BaseRobot : public Robot {
|
||||||
/* A robot base class that implements functions common to all robots. */
|
|
||||||
public:
|
public:
|
||||||
BaseRobot ( std::string name, int startX, int startY );
|
BaseRobot(std::string name, int startX, int startY);
|
||||||
|
|
||||||
void move ( int direction, const World &world ) override;
|
void move(int direction, const World& world) override;
|
||||||
int decideNextMove ( const World &world ) const override;
|
int decideNextMove(const World& world) const override;
|
||||||
|
|
||||||
void setPosition ( int x, int y ) override {
|
void setPosition(int x, int y) override {
|
||||||
x_ = x;
|
x_ = x;
|
||||||
y_ = y;
|
y_ = y;
|
||||||
}
|
}
|
||||||
int getScore () const override { return score_; }
|
|
||||||
void addScore ( int points ) override { score_ += points; }
|
int getScore() const override { return score_; }
|
||||||
int getX () const override { return x_; }
|
void addScore(int points) override { score_ += points; }
|
||||||
int getY () const override { return y_; }
|
int getX() const override { return x_; }
|
||||||
std::string getName () const override { return name_; }
|
int getY() const override { return y_; }
|
||||||
|
std::string getName() const override { return name_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int x_, y_, score_;
|
int x_;
|
||||||
|
int y_;
|
||||||
|
int score_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../include/BaseRobot.h"
|
|
||||||
|
|
||||||
#include <type_traits>
|
#include "BaseRobot.h"
|
||||||
|
|
||||||
class World;
|
class World;
|
||||||
|
|
||||||
|
/* Robot that mines up to three positive blocks per turn from its current column. */
|
||||||
class DigDeepBot : public BaseRobot {
|
class DigDeepBot : public BaseRobot {
|
||||||
public:
|
public:
|
||||||
DigDeepBot ( const int startX, const int startY );
|
DigDeepBot ( int startX, int startY );
|
||||||
int mine ( World& world ) override;
|
int mine ( World &world ) override;
|
||||||
};
|
};
|
||||||
|
|||||||
+19
-20
@@ -2,30 +2,29 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "World.h"
|
|
||||||
#include "Robot.h"
|
#include "Robot.h"
|
||||||
|
#include "World.h"
|
||||||
|
|
||||||
|
/* Coordinates game setup, turn order, world updates, and final scoring output. */
|
||||||
class Game {
|
class Game {
|
||||||
public:
|
public:
|
||||||
Game ();
|
Game ();
|
||||||
void run ();
|
void run ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
World world_;
|
World world_;
|
||||||
std::unique_ptr< Robot > player_;
|
std::unique_ptr<Robot> player_;
|
||||||
std::unique_ptr < Robot > computer_;
|
std::unique_ptr<Robot> computer_;
|
||||||
bool autoMode_ = false;
|
bool autoMode_ = false;
|
||||||
int lastThreshold_ = 0;
|
int lastThreshold_ = 0;
|
||||||
|
|
||||||
void setup ();
|
void setup ();
|
||||||
void play ( Robot& robot, bool isPlayer );
|
void play ( Robot &robot, bool isPlayer );
|
||||||
void checkRearrange ( Robot& robot );
|
void checkRearrange ( Robot &robot );
|
||||||
void applyEffect ( Robot& robot, int effect );
|
void applyEffect ( Robot &robot, int effect );
|
||||||
bool isGameOver() const;
|
bool isGameOver () const;
|
||||||
void printScores() const;
|
void printScores () const;
|
||||||
void printResult() const;
|
void printResult () const;
|
||||||
|
|
||||||
std::unique_ptr < Robot > createRobot ( int choice, int x, int y ) const;
|
|
||||||
|
|
||||||
|
std::unique_ptr<Robot> createRobot ( int choice, int x, int y ) const;
|
||||||
};
|
};
|
||||||
|
|||||||
+7
-6
@@ -4,11 +4,12 @@
|
|||||||
|
|
||||||
class World;
|
class World;
|
||||||
|
|
||||||
|
/* Robot that mines a random number of positive blocks from its current column. */
|
||||||
class RandomBot : public BaseRobot {
|
class RandomBot : public BaseRobot {
|
||||||
/* A robot that digs at a random depth */
|
public:
|
||||||
public:
|
RandomBot ( int startX, int startY );
|
||||||
RandomBot ( const int startX, const int startY );
|
int mine ( World &world ) override;
|
||||||
int mine ( World& world ) override;
|
|
||||||
private:
|
private:
|
||||||
int randomNumber();
|
int randomNumber ();
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
class World;
|
class World;
|
||||||
|
|
||||||
|
/* Virtual interface implemented by all robot types. */
|
||||||
class Robot {
|
class Robot {
|
||||||
/* A virtual interface for a robot */
|
|
||||||
public:
|
public:
|
||||||
virtual ~Robot () = default;
|
virtual ~Robot () = default;
|
||||||
Robot ( const Robot & ) = default;
|
Robot ( const Robot & ) = default;
|
||||||
|
|||||||
+2
-1
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
#include "../include/BaseRobot.h"
|
#include "../include/BaseRobot.h"
|
||||||
|
|
||||||
|
/* Robot that reorders the current column so the highest value reaches the surface,
|
||||||
|
then mines that top block. */
|
||||||
class SortBot : public BaseRobot {
|
class SortBot : public BaseRobot {
|
||||||
public:
|
public:
|
||||||
SortBot ( int startX, int startY );
|
SortBot ( int startX, int startY );
|
||||||
int mine ( World &world ) override;
|
int mine ( World &world ) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+28
-6
@@ -2,33 +2,55 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
/* A 3-D grid world where robots mine positive-value blocks and trigger effects. */
|
||||||
class World {
|
class World {
|
||||||
/* A 3D grid world where robots can mine blocks.
|
|
||||||
Blocks have a value, some have special effects. */
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit World ( int x = 5, int y = 5, int z = 10 );
|
explicit World ( int x = 5, int y = 5, int z = 10 );
|
||||||
|
|
||||||
|
/* Return the value at (x, y, z).
|
||||||
|
Throws std::out_of_range for invalid coordinates.
|
||||||
|
Complexity: O(1) */
|
||||||
int getValue ( int x, int y, int z ) const;
|
int getValue ( int x, int y, int z ) const;
|
||||||
|
|
||||||
|
/* Set the value at (x, y, z).
|
||||||
|
Throws std::out_of_range for invalid coordinates.
|
||||||
|
Complexity: O(1) */
|
||||||
void setValue ( int x, int y, int z, int value );
|
void setValue ( int x, int y, int z, int value );
|
||||||
|
|
||||||
|
/* Return the highest z in column (x, y) containing a positive value.
|
||||||
|
Returns -1 if no minable block exists in the column.
|
||||||
|
Complexity: O(sizeZ) */
|
||||||
int getSurfaceLevel ( int x, int y ) const;
|
int getSurfaceLevel ( int x, int y ) const;
|
||||||
|
|
||||||
|
/* Mine the current surface block at (x, y), set it to 0, and return its value.
|
||||||
|
Returns 0 if the column has no minable surface.
|
||||||
|
Complexity: O(sizeZ) */
|
||||||
int mine ( int x, int y );
|
int mine ( int x, int y );
|
||||||
|
|
||||||
void display ( int p1x = -1, int p1y = -1, int p2x = -1, int p2y = -1 ) const; // player positions initialized to -1 -> outside of surface grid
|
/* Print a 2-D surface view of the world with optional robot markers.
|
||||||
|
Pass default coordinates (-1, -1) to omit a robot marker.
|
||||||
|
Complexity: O(sizeX * sizeY * sizeZ) */
|
||||||
|
void display ( int p1x = -1, int p1y = -1, int p2x = -1, int p2y = -1 ) const;
|
||||||
|
|
||||||
int getSizeX () const { return _sizeX; }
|
int getSizeX () const { return _sizeX; }
|
||||||
int getSizeY () const { return _sizeY; }
|
int getSizeY () const { return _sizeY; }
|
||||||
int getSizeZ () const { return _sizeZ; }
|
int getSizeZ () const { return _sizeZ; }
|
||||||
|
|
||||||
// stage 2
|
/* Rearrange each column by applying a random operation
|
||||||
|
(shuffle, ascending sort, or descending sort) to non-zero entries.
|
||||||
|
Complexity: O(sizeX * sizeY * sizeZ log sizeZ) */
|
||||||
void rearrange ();
|
void rearrange ();
|
||||||
|
|
||||||
// stage 3
|
/* Find and consume one negative effect value in column (x, y).
|
||||||
|
Returns 0 if no effect exists.
|
||||||
|
Complexity: O(sizeZ) */
|
||||||
int checkEffects ( int x, int y );
|
int checkEffects ( int x, int y );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _sizeX, _sizeY, _sizeZ;
|
int _sizeX, _sizeY, _sizeZ;
|
||||||
std::vector<std::vector<std::vector<int>>> _grid;
|
std::vector<std::vector<std::vector<int>>> _grid;
|
||||||
|
|
||||||
|
/* Initialize the grid with random positive values and occasional effects.
|
||||||
|
Complexity: O(sizeX * sizeY * sizeZ) */
|
||||||
void init ();
|
void init ();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
#include <iostream>
|
|
||||||
#include "include/Game.h"
|
#include "include/Game.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
int main () {
|
int main () {
|
||||||
try {
|
try {
|
||||||
Game game;
|
Game game;
|
||||||
game.run ();
|
game.run();
|
||||||
} catch ( const std::exception& e ) {
|
} catch ( const std::exception &e ) {
|
||||||
std::cerr << "Fatal Error: " << e.what() << "\n";
|
std::cerr << "Fatal Error: " << e.what() << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-8
@@ -7,8 +7,9 @@
|
|||||||
BaseRobot::BaseRobot ( std::string name, int startX, int startY )
|
BaseRobot::BaseRobot ( std::string name, int startX, int startY )
|
||||||
: x_ ( startX ), y_ ( startY ), score_ ( 0 ), name_ ( std::move ( name ) ) {}
|
: x_ ( startX ), y_ ( startY ), score_ ( 0 ), name_ ( std::move ( name ) ) {}
|
||||||
|
|
||||||
|
/* Move one step in the requested direction while clamping to world bounds.
|
||||||
|
Complexity: O(1) */
|
||||||
void BaseRobot::move ( int direction, const World &world ) {
|
void BaseRobot::move ( int direction, const World &world ) {
|
||||||
|
|
||||||
switch ( direction ) {
|
switch ( direction ) {
|
||||||
case 1:
|
case 1:
|
||||||
x_ = std::min ( x_ + 1, world.getSizeX() - 1 );
|
x_ = std::min ( x_ + 1, world.getSizeX() - 1 );
|
||||||
@@ -27,6 +28,10 @@ void BaseRobot::move ( int direction, const World &world ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Choose the next move by maximizing immediate surface value among
|
||||||
|
current/adjacent cells; if none are mineable nearby, step toward the
|
||||||
|
nearest non-empty column in the grid.
|
||||||
|
Complexity: O(1) for local evaluation, worst O(sizeX * sizeY) fallback scan */
|
||||||
int BaseRobot::decideNextMove ( const World &world ) const {
|
int BaseRobot::decideNextMove ( const World &world ) const {
|
||||||
struct Option {
|
struct Option {
|
||||||
int dir, val;
|
int dir, val;
|
||||||
@@ -53,21 +58,28 @@ int BaseRobot::decideNextMove ( const World &world ) const {
|
|||||||
evaluate ( 0, -1, 4 );
|
evaluate ( 0, -1, 4 );
|
||||||
|
|
||||||
if ( options.empty() ) {
|
if ( options.empty() ) {
|
||||||
// All immediate neighbours are empty – scan the whole grid for the
|
|
||||||
// nearest non-empty column and step one cell toward it.
|
|
||||||
int bestDist = INT_MAX, tx = x_, ty = y_;
|
int bestDist = INT_MAX, tx = x_, ty = y_;
|
||||||
for ( int cx = 0; cx < world.getSizeX(); ++cx ) {
|
for ( int cx = 0; cx < world.getSizeX(); ++cx ) {
|
||||||
for ( int cy = 0; cy < world.getSizeY(); ++cy ) {
|
for ( int cy = 0; cy < world.getSizeY(); ++cy ) {
|
||||||
if ( world.getSurfaceLevel ( cx, cy ) >= 0 ) {
|
if ( world.getSurfaceLevel ( cx, cy ) >= 0 ) {
|
||||||
int dist = std::abs ( cx - x_ ) + std::abs ( cy - y_ );
|
int dist = std::abs ( cx - x_ ) + std::abs ( cy - y_ );
|
||||||
if ( dist < bestDist ) { bestDist = dist; tx = cx; ty = cy; }
|
if ( dist < bestDist ) {
|
||||||
|
bestDist = dist;
|
||||||
|
tx = cx;
|
||||||
|
ty = cy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( tx == x_ && ty == y_ ) return 0; // grid is truly empty
|
|
||||||
if ( tx > x_ ) return 1;
|
if ( tx == x_ && ty == y_ )
|
||||||
if ( tx < x_ ) return 2;
|
return 0; // grid is truly empty
|
||||||
if ( ty > y_ ) return 3;
|
if ( tx > x_ )
|
||||||
|
return 1;
|
||||||
|
if ( tx < x_ )
|
||||||
|
return 2;
|
||||||
|
if ( ty > y_ )
|
||||||
|
return 3;
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-6
@@ -1,21 +1,24 @@
|
|||||||
#include "../include/DigDeepBot.h"
|
#include "../include/DigDeepBot.h"
|
||||||
#include "../include/World.h"
|
#include "../include/World.h"
|
||||||
|
|
||||||
DigDeepBot::DigDeepBot ( const int startX, const int startY ) :
|
DigDeepBot::DigDeepBot ( const int startX, const int startY ) : BaseRobot ( "DigDeepBot", startX, startY ) {}
|
||||||
BaseRobot( "DigDeepBot", startX, startY) {}
|
|
||||||
|
|
||||||
int DigDeepBot::mine ( World& world ) {
|
int DigDeepBot::mine ( World &world ) {
|
||||||
|
/* Mine up to three positive blocks from the current column, scanning
|
||||||
|
from top depth to bottom depth.
|
||||||
|
Complexity: O(z) where z = column depth */
|
||||||
int total = 0;
|
int total = 0;
|
||||||
int grabbed = 0;
|
int grabbed = 0;
|
||||||
|
|
||||||
for ( int z = world.getSizeZ() - 1; z >= 0 && grabbed < 3; --z ) {
|
for ( int z = world.getSizeZ() - 1; z >= 0 && grabbed < 3; --z ) {
|
||||||
int v = world.getValue ( x_, y_, z );
|
const int value = world.getValue ( x_, y_, z );
|
||||||
if ( v > 0 ) {
|
if ( value > 0 ) {
|
||||||
total += v;
|
total += value;
|
||||||
world.setValue ( x_, y_, z, 0 );
|
world.setValue ( x_, y_, z, 0 );
|
||||||
++grabbed;
|
++grabbed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
score_ += total;
|
score_ += total;
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|||||||
+132
-90
@@ -1,14 +1,19 @@
|
|||||||
#include "../include/Game.h"
|
#include "../include/Game.h"
|
||||||
#include "../include/SortBot.h"
|
|
||||||
#include "../include/DigDeepBot.h"
|
#include "../include/DigDeepBot.h"
|
||||||
#include "../include/RandomBot.h"
|
#include "../include/RandomBot.h"
|
||||||
|
#include "../include/SortBot.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
int validateInput ( const std::string& prompt, int min, int max );
|
int validateInput ( const std::string &prompt, int min, int max );
|
||||||
|
|
||||||
Game::Game() : world_ ( 5, 5, 10 ) {}
|
/* Initialize game state with default world dimensions.
|
||||||
|
Complexity: O(1) */
|
||||||
|
Game::Game () : world_ ( 5, 5, 10 ) {}
|
||||||
|
|
||||||
|
/* Run the full game loop: setup, alternating turns, and final result output.
|
||||||
|
Complexity: O(r * C) where r = rounds until depletion, C = per-round world/robot work */
|
||||||
void Game::run () {
|
void Game::run () {
|
||||||
std::cout << "=== DEEP MINER ===\n\n";
|
std::cout << "=== DEEP MINER ===\n\n";
|
||||||
setup();
|
setup();
|
||||||
@@ -16,145 +21,182 @@ void Game::run () {
|
|||||||
|
|
||||||
int round = 1;
|
int round = 1;
|
||||||
while ( !isGameOver() ) {
|
while ( !isGameOver() ) {
|
||||||
std::cout << "\n--- Round " << round ++ << " ---\n";
|
std::cout << "\n--- Round " << round++ << " ---\n";
|
||||||
|
|
||||||
// human player
|
std::cout << "[Player: " << player_->getName() << "]\n";
|
||||||
std::cout << "[Player: " << player_->getName () << "]\n";
|
|
||||||
play ( *player_, true );
|
play ( *player_, true );
|
||||||
|
|
||||||
// computer
|
|
||||||
std::cout << "[Computer: " << computer_->getName() << "]\n";
|
std::cout << "[Computer: " << computer_->getName() << "]\n";
|
||||||
play ( *computer_, false );
|
play ( *computer_, false );
|
||||||
|
|
||||||
world_.display ( player_->getX(), player_->getY(), computer_->getX(), computer_->getY() );
|
world_.display ( player_->getX(), player_->getY(), computer_->getX(), computer_->getY() );
|
||||||
printScores();
|
printScores();
|
||||||
}
|
}
|
||||||
|
|
||||||
printResult();
|
printResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Collect mode/robot selections and create both participants.
|
||||||
|
Complexity: O(1) plus input wait time */
|
||||||
void Game::setup () {
|
void Game::setup () {
|
||||||
autoMode_ = ( validateInput("Mode - 1: Player vs. Computer 2: Computer vs. Computer: ", 1, 2) == 2 );
|
autoMode_ = ( validateInput ( "Mode - 1: Player vs. Computer 2: Computer vs. Computer: ", 1, 2 ) == 2 );
|
||||||
|
|
||||||
std::cout << "\nRobots: \n"
|
std::cout << "\nRobots: \n"
|
||||||
<< " 1 = SortBot (sorts column and mines highest value)\n"
|
<< " 1 = SortBot (sorts column and mines highest value)\n"
|
||||||
<< " 2 = DigDeepBot (grabs the top 3 values)]\n"
|
<< " 2 = DigDeepBot (grabs the top 3 values)\n"
|
||||||
<< " 3 = RandomBot (grabs a random Number of values)\n";
|
<< " 3 = RandomBot (grabs a random number of values)\n";
|
||||||
|
|
||||||
player_ = createRobot ( validateInput(
|
player_ = createRobot ( validateInput ( "Your robot: ", 1, 3 ), 0, 0 );
|
||||||
"Your robot: ", 1, 3), 0, 0 );
|
computer_ =
|
||||||
computer_ = createRobot ( validateInput(
|
createRobot ( validateInput ( "Computer robot: ", 1, 3 ), world_.getSizeX() - 1, world_.getSizeY() - 1 );
|
||||||
"Computer robot: ", 1, 3 ), world_.getSizeX() - 1, world_.getSizeY() - 1 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr < Robot > Game::createRobot ( int choice, int x, int y ) const {
|
/* Instantiate a robot implementation from a menu choice.
|
||||||
|
Complexity: O(1) */
|
||||||
|
std::unique_ptr<Robot> Game::createRobot ( int choice, int x, int y ) const {
|
||||||
switch ( choice ) {
|
switch ( choice ) {
|
||||||
case 1:
|
case 1:
|
||||||
return std::make_unique < SortBot > ( x, y );
|
return std::make_unique<SortBot> ( x, y );
|
||||||
case 2 :
|
case 2:
|
||||||
return std::make_unique < DigDeepBot > ( x, y );
|
return std::make_unique<DigDeepBot> ( x, y );
|
||||||
case 3 :
|
case 3:
|
||||||
return std::make_unique < RandomBot > ( x, y );
|
return std::make_unique<RandomBot> ( x, y );
|
||||||
default:
|
default:
|
||||||
return std::make_unique < SortBot > ( x, y );
|
return std::make_unique<SortBot> ( x, y );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::play ( Robot& robot, bool isPlayer ) {
|
/* Execute one turn: movement, tile effects, optional mining, and rearrange checks.
|
||||||
int direction = ( !isPlayer || autoMode_ ) ? robot.decideNextMove( world_ )
|
Complexity: O(W) in the worst case due to effect handling that scans the world */
|
||||||
: validateInput ( "Direction (0 =stay 1=+x 2=-x 3=+y 4=-y): ", 0, 4);
|
void Game::play ( Robot &robot, bool isPlayer ) {
|
||||||
robot.move( direction, world_ );
|
const int direction = ( !isPlayer || autoMode_ )
|
||||||
|
? robot.decideNextMove ( world_ )
|
||||||
|
: validateInput ( "Direction (0=stay 1=+x 2=-x 3=+y 4=-y): ", 0, 4 );
|
||||||
|
|
||||||
int effect = world_.checkEffects( robot.getX(), robot.getY() );
|
robot.move ( direction, world_ );
|
||||||
|
|
||||||
|
const int effect = world_.checkEffects ( robot.getX(), robot.getY() );
|
||||||
if ( effect < 0 ) {
|
if ( effect < 0 ) {
|
||||||
applyEffect( robot, effect );
|
applyEffect ( robot, effect );
|
||||||
}
|
}
|
||||||
if ( effect != -1 ) { // -1 = blocked; all other effects still allow mining
|
|
||||||
int mined = robot.mine( world_ );
|
if ( effect != -1 ) { // -1 blocks mining for this turn
|
||||||
|
const int mined = robot.mine ( world_ );
|
||||||
std::cout << " " << robot.getName() << " mined " << mined << " points.\n";
|
std::cout << " " << robot.getName() << " mined " << mined << " points.\n";
|
||||||
}
|
}
|
||||||
checkRearrange( robot );
|
|
||||||
|
checkRearrange ( robot );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::checkRearrange(Robot& robot) {
|
/* Rearrange the world each time a robot crosses a new 50-point threshold.
|
||||||
int score = robot.getScore();
|
Complexity: O(W) where W = number of cells in the world */
|
||||||
int threshold = (score / 50) * 50;
|
void Game::checkRearrange ( Robot &robot ) {
|
||||||
if (threshold > 0 && threshold > lastThreshold_) {
|
const int score = robot.getScore();
|
||||||
|
const int threshold = ( score / 50 ) * 50;
|
||||||
|
|
||||||
|
if ( threshold > 0 && threshold > lastThreshold_ ) {
|
||||||
lastThreshold_ = threshold;
|
lastThreshold_ = threshold;
|
||||||
std::cout << "*** " << robot.getName() << " reached " << threshold
|
std::cout << "*** " << robot.getName() << " reached " << threshold << " points! World rearranged! ***\n";
|
||||||
<< " points! World rearranged! ***\n";
|
|
||||||
world_.rearrange();
|
world_.rearrange();
|
||||||
world_.display ( player_->getX(), player_->getY(), computer_->getX(), computer_->getY() );
|
world_.display ( player_->getX(), player_->getY(), computer_->getX(), computer_->getY() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::applyEffect(Robot& robot, int effect) {
|
/* Apply special tile effects:
|
||||||
switch (effect) {
|
-1 block turn, -2 teleport to lowest visible surface value, -3 lose half score.
|
||||||
case -1:
|
Complexity: O(W) worst case for teleport target search */
|
||||||
std::cout << " [EFFECT -1] " << robot.getName() << " blocked this round!\n";
|
void Game::applyEffect ( Robot &robot, int effect ) {
|
||||||
break;
|
switch ( effect ) {
|
||||||
|
case -1:
|
||||||
|
std::cout << " [EFFECT -1] " << robot.getName() << " blocked this round!\n";
|
||||||
|
break;
|
||||||
|
|
||||||
case -2: {
|
case -2: {
|
||||||
int minVal = std::numeric_limits<int>::max(), bx = 0, by = 0;
|
int minVal = std::numeric_limits<int>::max();
|
||||||
for (int x = 0; x < world_.getSizeX(); ++x)
|
int bx = 0;
|
||||||
for (int y = 0; y < world_.getSizeY(); ++y) {
|
int by = 0;
|
||||||
int surf = world_.getSurfaceLevel(x, y);
|
|
||||||
if (surf < 0) continue;
|
for ( int x = 0; x < world_.getSizeX(); ++x ) {
|
||||||
int val = world_.getValue(x, y, surf);
|
for ( int y = 0; y < world_.getSizeY(); ++y ) {
|
||||||
if (val < minVal) { minVal = val; bx = x; by = y; }
|
const int surf = world_.getSurfaceLevel ( x, y );
|
||||||
|
if ( surf < 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const int val = world_.getValue ( x, y, surf );
|
||||||
|
if ( val < minVal ) {
|
||||||
|
minVal = val;
|
||||||
|
bx = x;
|
||||||
|
by = y;
|
||||||
}
|
}
|
||||||
std::cout << " [EFFECT -2] " << robot.getName()
|
}
|
||||||
<< " teleported to (" << bx << "," << by << ")!\n";
|
|
||||||
robot.setPosition(bx, by);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case -3:
|
std::cout << " [EFFECT -2] " << robot.getName() << " teleported to (" << bx << "," << by << ")!\n";
|
||||||
std::cout << " [EFFECT -3] " << robot.getName() << " loses half score!\n";
|
robot.setPosition ( bx, by );
|
||||||
robot.addScore(-(robot.getScore() / 2));
|
break;
|
||||||
break;
|
}
|
||||||
|
|
||||||
default:
|
case -3:
|
||||||
std::cout << " [EFFECT] Unknown effect " << effect << " ignored.\n";
|
std::cout << " [EFFECT -3] " << robot.getName() << " loses half score!\n";
|
||||||
|
robot.addScore ( -( robot.getScore() / 2 ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
std::cout << " [EFFECT] Unknown effect " << effect << " ignored.\n";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true when no minable surface block remains anywhere.
|
||||||
|
Complexity: O(X * Y * Z) via repeated surface checks */
|
||||||
bool Game::isGameOver () const {
|
bool Game::isGameOver () const {
|
||||||
for ( int x = 0; x < world_.getSizeX (); ++x ) {
|
for ( int x = 0; x < world_.getSizeX(); ++x ) {
|
||||||
for ( int y = 0; y < world_.getSizeY(); ++y ){
|
for ( int y = 0; y < world_.getSizeY(); ++y ) {
|
||||||
if ( world_.getSurfaceLevel( x, y) >= 0 )
|
if ( world_.getSurfaceLevel ( x, y ) >= 0 ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::printScores() const {
|
/* Print current scores for both robots.
|
||||||
std::cout << "Score: "
|
Complexity: O(1) */
|
||||||
<< player_->getName () << " = " << player_->getScore() << " | "
|
void Game::printScores () const {
|
||||||
<< computer_->getName() << " = " << computer_->getScore() << "\n";
|
std::cout << "Score: " << player_->getName() << " = " << player_->getScore() << " | " << computer_->getName()
|
||||||
|
<< " = " << computer_->getScore() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::printResult() const {
|
/* Print final scores and winner once the world is depleted.
|
||||||
|
Complexity: O(1) */
|
||||||
|
void Game::printResult () const {
|
||||||
std::cout << "=== GAME OVER ===\n";
|
std::cout << "=== GAME OVER ===\n";
|
||||||
printScores();
|
printScores();
|
||||||
int scorePlayer = player_->getScore(), scoreComputer = computer_->getScore();
|
|
||||||
if ( scorePlayer > scoreComputer )
|
|
||||||
std::cout << player_->getName() << " WINS!\n";
|
|
||||||
else if ( scoreComputer > scorePlayer )
|
|
||||||
std::cout << computer_->getName() << " WINS!\n";
|
|
||||||
else
|
|
||||||
std::cout << "DRAW!\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
int validateInput (const std::string& prompt, int min, int max) {
|
const int scorePlayer = player_->getScore();
|
||||||
int val;
|
const int scoreComputer = computer_->getScore();
|
||||||
while (true) {
|
|
||||||
std::cout << prompt;
|
if ( scorePlayer > scoreComputer ) {
|
||||||
if (std::cin >> val && val >= min && val <= max)
|
std::cout << player_->getName() << " WINS!\n";
|
||||||
return val;
|
} else if ( scoreComputer > scorePlayer ) {
|
||||||
std::cin.clear();
|
std::cout << computer_->getName() << " WINS!\n";
|
||||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
} else {
|
||||||
std::cout << " Invalid. Enter a number between "
|
std::cout << "DRAW!\n";
|
||||||
<< min << " and " << max << ": ";
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read and validate bounded integer input from stdin.
|
||||||
|
Complexity: O(1) per successful read attempt */
|
||||||
|
int validateInput ( const std::string &prompt, int min, int max ) {
|
||||||
|
int val;
|
||||||
|
while ( true ) {
|
||||||
|
std::cout << prompt;
|
||||||
|
if ( std::cin >> val && val >= min && val <= max ) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cin.clear();
|
||||||
|
std::cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
|
||||||
|
std::cout << " Invalid. Enter a number between " << min << " and " << max << ": ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-9
@@ -3,28 +3,33 @@
|
|||||||
|
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
RandomBot::RandomBot ( const int startX, const int startY ):
|
RandomBot::RandomBot ( const int startX, const int startY ) : BaseRobot ( "RandomBot", startX, startY ) {}
|
||||||
BaseRobot ( "RandomBot", startX, startY ) {}
|
|
||||||
|
|
||||||
int RandomBot::mine ( World& world ) {
|
int RandomBot::mine ( World &world ) {
|
||||||
|
/* Mine up to a random number of positive blocks from the current column,
|
||||||
|
scanning from top to bottom and stopping once the random limit is reached.
|
||||||
|
Complexity: O(z) where z = world height */
|
||||||
int total = 0;
|
int total = 0;
|
||||||
int grabbed = 0;
|
int grabbed = 0;
|
||||||
const int limit = randomNumber(); // computed once; calling it every iteration re-rolls the limit
|
const int limit = randomNumber();
|
||||||
|
|
||||||
for ( int z = world.getSizeZ() -1; z >= 0 && grabbed < limit; --z ) {
|
for ( int z = world.getSizeZ() - 1; z >= 0 && grabbed < limit; --z ) {
|
||||||
int value = world.getValue ( x_, y_, z );
|
const int value = world.getValue ( x_, y_, z );
|
||||||
if ( value > 0 ) {
|
if ( value > 0 ) {
|
||||||
total += value;
|
total += value;
|
||||||
world.setValue ( x_, y_, z, 0 );
|
world.setValue ( x_, y_, z, 0 );
|
||||||
++grabbed;
|
++grabbed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
score_ += total;
|
score_ += total;
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RandomBot::randomNumber () {
|
int RandomBot::randomNumber () {
|
||||||
static std ::mt19937 rng ( std::random_device{}());
|
/* Return a uniformly distributed mining limit in [0, 9].
|
||||||
std::uniform_int_distribution < int > distr ( 0, 9 );
|
Complexity: O(1) */
|
||||||
|
static std::mt19937 rng ( std::random_device {}() );
|
||||||
|
std::uniform_int_distribution<int> distr ( 0, 9 );
|
||||||
return distr ( rng );
|
return distr ( rng );
|
||||||
};
|
}
|
||||||
|
|||||||
+32
-17
@@ -4,28 +4,43 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
SortBot::SortBot ( const int startX, const int startY ) : BaseRobot ( "SortBot", startX, startY ) {}
|
SortBot::SortBot ( int startX, int startY ) : BaseRobot ( "SortBot", startX, startY ) {}
|
||||||
|
|
||||||
int SortBot::mine ( World &world ) {
|
int SortBot::mine ( World &world ) {
|
||||||
// create ( value, z ) pairs for positive values ( exclude mined blocks and effects )
|
/* Collect positive blocks in the current column, sort them so the
|
||||||
|
highest value becomes the surface block, then mine that block.
|
||||||
|
Complexity: O(z log z) where z = world depth at this column */
|
||||||
std::vector<std::pair<int, int>> values;
|
std::vector<std::pair<int, int>> values;
|
||||||
for ( int z = 0; z < world.getSizeZ(); ++z ) {
|
values.reserve ( static_cast<std::size_t> ( world.getSizeZ() ) );
|
||||||
int v = world.getValue(x_, y_, z );
|
|
||||||
if ( v > 0 ) values.emplace_back(v, z );
|
|
||||||
}
|
|
||||||
if ( values.empty()) return 0;
|
|
||||||
// sort ascending so highest value ends up at top (surface) and gets mined
|
|
||||||
std::sort ( values.begin(), values.end(), [] ( const auto& a, const auto& b ) { return a.first < b.first;} );
|
|
||||||
|
|
||||||
for ( auto& [x, z] : values ) {
|
for ( int z = 0; z < world.getSizeZ(); ++z ) {
|
||||||
world.setValue ( x_, y_, z, 0);
|
const int value = world.getValue ( x_, y_, z );
|
||||||
}
|
if ( value > 0 ) {
|
||||||
for ( std::size_t i = 0; i < values.size(); ++i ) {
|
values.emplace_back ( value, z );
|
||||||
world.setValue( x_, y_, static_cast<int>(i), values[i].first );
|
}
|
||||||
}
|
}
|
||||||
int surface = world.getSurfaceLevel(x_, y_);
|
|
||||||
if ( surface < 0 ) return 0;
|
if ( values.empty() ) {
|
||||||
int mined = world.getValue ( x_, y_, surface );
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort ( values.begin(), values.end(), [] ( const auto &a, const auto &b ) { return a.first < b.first; } );
|
||||||
|
|
||||||
|
for ( const auto &[ value, z ] : values ) {
|
||||||
|
( void )value;
|
||||||
|
world.setValue ( x_, y_, z, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( std::size_t i = 0; i < values.size(); ++i ) {
|
||||||
|
world.setValue ( x_, y_, static_cast<int> ( i ), values[ i ].first );
|
||||||
|
}
|
||||||
|
|
||||||
|
const int surface = world.getSurfaceLevel ( x_, y_ );
|
||||||
|
if ( surface < 0 ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int mined = world.getValue ( x_, y_, surface );
|
||||||
world.setValue ( x_, y_, surface, 0 );
|
world.setValue ( x_, y_, surface, 0 );
|
||||||
score_ += mined;
|
score_ += mined;
|
||||||
return mined;
|
return mined;
|
||||||
|
|||||||
+64
-32
@@ -1,33 +1,39 @@
|
|||||||
#include "../include/World.h"
|
#include "../include/World.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <algorithm>
|
/* Construct a 3D grid world and initialize all cells.
|
||||||
|
Complexity: O(x × y × z) */
|
||||||
World::World ( int x, int y, int z )
|
World::World ( int x, int y, int z )
|
||||||
: _sizeX ( x ), _sizeY ( y ), _sizeZ ( z ),
|
: _sizeX ( x ), _sizeY ( y ), _sizeZ ( z ),
|
||||||
_grid ( x, std::vector<std::vector<int>> ( y, std::vector<int> ( z, 0 ) ) ) {
|
_grid ( x, std::vector<std::vector<int>> ( y, std::vector<int> ( z, 0 ) ) ) {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fill the world with random positive values and occasional effect cells.
|
||||||
|
Effects are encoded as negative values in [-3, -1].
|
||||||
|
Complexity: O(x × y × z) */
|
||||||
void World::init () {
|
void World::init () {
|
||||||
std::mt19937 rng ( std::random_device {}() ); // random number generator (RNG)
|
std::mt19937 rng ( std::random_device {}() );
|
||||||
std::uniform_int_distribution<int> distribution ( 1, 9 );
|
std::uniform_int_distribution<int> valueDist ( 1, 9 );
|
||||||
std::uniform_int_distribution<int> effectProbability ( 0, 9 ); // 10% chance for an effect
|
std::uniform_int_distribution<int> effectChance ( 0, 9 );
|
||||||
std::uniform_int_distribution<int> effectType ( -3, -1 ); // 3 types of effects (negative flags)
|
std::uniform_int_distribution<int> effectType ( -3, -1 );
|
||||||
|
|
||||||
for ( int x = 0; x < _sizeX; ++x ) {
|
for ( int x = 0; x < _sizeX; ++x ) {
|
||||||
for ( int y = 0; y < _sizeY; ++y ) {
|
for ( int y = 0; y < _sizeY; ++y ) {
|
||||||
for ( int z = 0; z < _sizeZ; ++z ) {
|
for ( int z = 0; z < _sizeZ; ++z ) {
|
||||||
_grid[ x ][ y ][ z ] = ( effectProbability ( rng ) == 1 )
|
_grid[ x ][ y ][ z ] = ( effectChance ( rng ) == 1 ) ? effectType ( rng ) : valueDist ( rng );
|
||||||
? effectType ( rng )
|
|
||||||
: distribution ( rng ); // 10% chance for effect
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // init
|
}
|
||||||
|
|
||||||
|
/* Return the value at (x, y, z), throwing on invalid coordinates.
|
||||||
|
Complexity: O(1) */
|
||||||
int World::getValue ( int x, int y, int z ) const {
|
int World::getValue ( int x, int y, int z ) const {
|
||||||
if ( x < 0 || x >= _sizeX || y < 0 || y >= _sizeY || z < 0 || z >= _sizeZ ) {
|
if ( x < 0 || x >= _sizeX || y < 0 || y >= _sizeY || z < 0 || z >= _sizeZ ) {
|
||||||
throw std::out_of_range ( "Coordinates out of bounds" );
|
throw std::out_of_range ( "Coordinates out of bounds" );
|
||||||
@@ -35,6 +41,8 @@ int World::getValue ( int x, int y, int z ) const {
|
|||||||
return _grid[ x ][ y ][ z ];
|
return _grid[ x ][ y ][ z ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set the value at (x, y, z), throwing on invalid coordinates.
|
||||||
|
Complexity: O(1) */
|
||||||
void World::setValue ( int x, int y, int z, int value ) {
|
void World::setValue ( int x, int y, int z, int value ) {
|
||||||
if ( x < 0 || x >= _sizeX || y < 0 || y >= _sizeY || z < 0 || z >= _sizeZ ) {
|
if ( x < 0 || x >= _sizeX || y < 0 || y >= _sizeY || z < 0 || z >= _sizeZ ) {
|
||||||
throw std::out_of_range ( "Coordinates out of bounds" );
|
throw std::out_of_range ( "Coordinates out of bounds" );
|
||||||
@@ -42,61 +50,77 @@ void World::setValue ( int x, int y, int z, int value ) {
|
|||||||
_grid[ x ][ y ][ z ] = value;
|
_grid[ x ][ y ][ z ] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the highest z with a positive value in column (x, y).
|
||||||
|
Negative effect cells are ignored for mining surface purposes.
|
||||||
|
Complexity: O(z) */
|
||||||
int World::getSurfaceLevel ( int x, int y ) const {
|
int World::getSurfaceLevel ( int x, int y ) const {
|
||||||
for ( int z = _sizeZ - 1; z >= 0; --z ) {
|
for ( int z = _sizeZ - 1; z >= 0; --z ) {
|
||||||
if ( _grid[ x ][ y ][ z ] > 0 ) { // effects (negative) are not part of the minable surface
|
if ( _grid[ x ][ y ][ z ] > 0 ) {
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1; // no surface found
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mine one topmost positive block from column (x, y) and return its value.
|
||||||
|
Returns 0 when the column has no mineable block.
|
||||||
|
Complexity: O(z) */
|
||||||
int World::mine ( int x, int y ) {
|
int World::mine ( int x, int y ) {
|
||||||
int z = getSurfaceLevel ( x, y );
|
const int z = getSurfaceLevel ( x, y );
|
||||||
if ( z == -1 )
|
if ( z == -1 ) {
|
||||||
return 0;
|
return 0;
|
||||||
int value = _grid[ x ][ y ][ z ];
|
}
|
||||||
|
|
||||||
|
const int value = _grid[ x ][ y ][ z ];
|
||||||
if ( value > 0 ) {
|
if ( value > 0 ) {
|
||||||
_grid[ x ][ y ][ z ] = 0; // mine the block
|
_grid[ x ][ y ][ z ] = 0;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Print a 2D surface view with optional player/computer markers.
|
||||||
|
Marker legend is shown when at least one robot position is provided.
|
||||||
|
Complexity: O(x × y × z) due to per-cell surface lookup */
|
||||||
void World::display ( int p1x, int p1y, int p2x, int p2y ) const {
|
void World::display ( int p1x, int p1y, int p2x, int p2y ) const {
|
||||||
std::cout << "=== SURFACE VIEW ===\n";
|
std::cout << "=== SURFACE VIEW ===\n";
|
||||||
|
|
||||||
// legend – only shown when at least one robot position is valid
|
if ( p1x >= 0 || p2x >= 0 ) {
|
||||||
if ( p1x >= 0 || p2x >= 0 )
|
|
||||||
std::cout << " P = Player C = Computer ! = both\n";
|
std::cout << " P = Player C = Computer ! = both\n";
|
||||||
|
}
|
||||||
|
|
||||||
// column-index header
|
|
||||||
std::cout << " ";
|
std::cout << " ";
|
||||||
for ( int y = 0; y < _sizeY; ++y )
|
for ( int y = 0; y < _sizeY; ++y ) {
|
||||||
std::cout << std::setw ( 4 ) << y;
|
std::cout << std::setw ( 4 ) << y;
|
||||||
|
}
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
|
|
||||||
for ( int x = 0; x < _sizeX; ++x ) {
|
for ( int x = 0; x < _sizeX; ++x ) {
|
||||||
std::cout << std::setw ( 2 ) << x << " ";
|
std::cout << std::setw ( 2 ) << x << " ";
|
||||||
for ( int y = 0; y < _sizeY; ++y ) {
|
for ( int y = 0; y < _sizeY; ++y ) {
|
||||||
int surface = getSurfaceLevel ( x, y );
|
const int surface = getSurfaceLevel ( x, y );
|
||||||
int val = ( surface >= 0 ? _grid[ x ][ y ][ surface ] : 0 );
|
const int val = ( surface >= 0 ? _grid[ x ][ y ][ surface ] : 0 );
|
||||||
bool hasP1 = ( x == p1x && y == p1y );
|
const bool hasP1 = ( x == p1x && y == p1y );
|
||||||
bool hasP2 = ( x == p2x && y == p2y );
|
const bool hasP2 = ( x == p2x && y == p2y );
|
||||||
|
|
||||||
if ( hasP1 && hasP2 )
|
if ( hasP1 && hasP2 ) {
|
||||||
std::cout << std::setw ( 3 ) << val << '!';
|
std::cout << std::setw ( 3 ) << val << '!';
|
||||||
else if ( hasP1 )
|
} else if ( hasP1 ) {
|
||||||
std::cout << std::setw ( 3 ) << val << 'P';
|
std::cout << std::setw ( 3 ) << val << 'P';
|
||||||
else if ( hasP2 )
|
} else if ( hasP2 ) {
|
||||||
std::cout << std::setw ( 3 ) << val << 'C';
|
std::cout << std::setw ( 3 ) << val << 'C';
|
||||||
else
|
} else {
|
||||||
std::cout << std::setw ( 4 ) << val;
|
std::cout << std::setw ( 4 ) << val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
std::cout << "=========================\n";
|
std::cout << "=========================\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Rearrange each column by applying one random operation:
|
||||||
|
shuffle, ascending sort, or descending sort.
|
||||||
|
Zero cells remain untouched; only non-zero entries are rearranged in place.
|
||||||
|
Complexity: O(x × y × z log z) in the worst case */
|
||||||
void World::rearrange () {
|
void World::rearrange () {
|
||||||
std::mt19937 rng ( std::random_device {}() );
|
std::mt19937 rng ( std::random_device {}() );
|
||||||
std::uniform_int_distribution<int> opDist ( 0, 2 );
|
std::uniform_int_distribution<int> opDist ( 0, 2 );
|
||||||
@@ -105,6 +129,7 @@ void World::rearrange () {
|
|||||||
for ( int y = 0; y < _sizeY; ++y ) {
|
for ( int y = 0; y < _sizeY; ++y ) {
|
||||||
std::vector<int> values;
|
std::vector<int> values;
|
||||||
std::vector<int> positions;
|
std::vector<int> positions;
|
||||||
|
|
||||||
for ( int z = 0; z < _sizeZ; ++z ) {
|
for ( int z = 0; z < _sizeZ; ++z ) {
|
||||||
if ( _grid[ x ][ y ][ z ] != 0 ) {
|
if ( _grid[ x ][ y ][ z ] != 0 ) {
|
||||||
values.push_back ( _grid[ x ][ y ][ z ] );
|
values.push_back ( _grid[ x ][ y ][ z ] );
|
||||||
@@ -124,18 +149,25 @@ void World::rearrange () {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( std::size_t i = 0; i < positions.size(); ++i )
|
for ( std::size_t i = 0; i < positions.size(); ++i ) {
|
||||||
_grid[ x ][ y ][ positions[ i ] ] = values[ i ];
|
_grid[ x ][ y ][ positions[ i ] ] = values[ i ];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find and consume the first negative effect value in column (x, y).
|
||||||
|
Returns 0 when no effect exists in that column.
|
||||||
|
Complexity: O(z) */
|
||||||
int World::checkEffects ( int x, int y ) {
|
int World::checkEffects ( int x, int y ) {
|
||||||
auto &col = _grid[ x ][ y ];
|
auto &col = _grid[ x ][ y ];
|
||||||
auto it = std::find_if ( col.begin(), col.end(), [] ( int v ) { return v < 0; } );
|
auto it = std::find_if ( col.begin(), col.end(), [] ( int v ) { return v < 0; } );
|
||||||
if ( it == col.end() )
|
|
||||||
|
if ( it == col.end() ) {
|
||||||
return 0;
|
return 0;
|
||||||
int effect = *it;
|
}
|
||||||
*it = 0; // consume
|
|
||||||
|
const int effect = *it;
|
||||||
|
*it = 0;
|
||||||
return effect;
|
return effect;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user