Untitled

mail@pastecode.io avatar
unknown
plain_text
7 months ago
24 kB
3
Indexable
Never
#include <iostream>
#include <vector>
#include <cmath>
#include <string> 
#include <cstdlib> 
#include <stdexcept>
#include <set>
#include <random>
#include <map>

using namespace std;

class Map;
class Team;
class Obstacle;
class Team;

class InvalidInputException : public runtime_error {
public:
    InvalidInputException(const string& message) : runtime_error(message) {}
};

class OccupiedCellException : public runtime_error {
public:
    OccupiedCellException(const string& message) : runtime_error(message) {}
};

class OutOfBoundsException : public runtime_error {
public:
    OutOfBoundsException(const string& message) : runtime_error(message) {}
};

set<int> generateUniqueRandomNumbers(int min, int max, int count) {
    std::random_device rd;  // 用於獲得種子
    std::mt19937 gen(rd()); // 標準 mersenne_twister_engine
    std::uniform_int_distribution<> distrib(min, max);

    std::set<int> uniqueNumbers;
    while (uniqueNumbers.size() < count) {
        uniqueNumbers.insert(distrib(gen));
    }

    return uniqueNumbers;
}

class character {
protected:
    //名字、血量、攻擊、防禦、速度
    char symbol;
    string name;
    int origin_healthPoints;
    int current_healthPoints;
    //int healthPoints;
    int attackPoints;
    int defensePoints;
    int speedPoints;
    int x;  // 角色在方格地圖上的x、y座標 
    int y;
    vector<size_t> canAttackIndex;


public:
    //Constructor
    character() : symbol('N'), name("None"), origin_healthPoints(0),current_healthPoints(0), attackPoints(0), defensePoints(0), speedPoints(0), x(0), y(0) {}
    character(const char charSymbol, const string& charName, int origin_HP, int current_HP, int charAttack,int charDefense, int charSpeed, int x, int y) : symbol(charSymbol), name(charName), origin_healthPoints(origin_HP),current_healthPoints(current_HP),attackPoints(charAttack), defensePoints(charDefense), speedPoints(charSpeed), x(x), y(y) {}

    //取得基本資料函數
    char getSymbol() const { return symbol; }
    string getName() const { return name; }
    int get_current_HP() const { return current_healthPoints; }
    int get_origin_HP() const { return origin_healthPoints; }
    int getAttackPoints() const { return attackPoints; }
    int getDefensePoints() const { return defensePoints; }
    int getSpeedPoints() const { return speedPoints; }
    int getX() const { return x; }
    int getY() const { return y; }

    // 顯示基本資料
    void displayInfo(const vector<character*>& team, int index);
    // 傷害
    void takeDamage(Map& chessBoard, int damage, int index, Team& temp);
    
	// 攻擊
    void attack(int index, Team& temp, Map& chessBoard);
    // 移動角色
    void move(Map& chessBoard, Team& otherTeam);
    // 確認是否在攻擊範圍內
    bool checkCharacter(character& character) const;
    
    void checkObstacle(vector<Obstacle>& allObstacles ,Map& chessBoard);

    void obstacleHeal(int amount);
    
    void obstaclePlus(int amount);
    
    // 發送可供attack的對象的prompt
    void chooseToAttack(const vector<character*>& team); 

};

class Wizard : public character {
private:

public:
    Wizard(int x, int y): character('W', "Wizard", 80, 80, 25, 5, 8, x, y) {}

};

class Knight : public character {
private:

public:
    Knight(int x, int y): character('K', "Knight", 100, 100, 15, 3, 5, x, y){}
};

class Archer : public character {
private:

public:
	Archer(int x, int y): character('A', "Archer", 50,50, 40, 1, 7, x, y){}
};

class Tank : public character {
private:

public:
	Tank(int x, int y): character('T', "Tank", 300 ,300, 5, 10, 10, x, y){}
};


class Map {
private:
    int rows;   // 地圖的行數
    int cols;   // 地圖的列數
    vector<vector<char> > map;  // 地圖的表示

public:
    Map() {}
    Map(int rows, int cols) : rows(rows), cols(cols), map(rows, vector<char>(cols, '.')) {}

    void draw() const;
    void cleanCharacter(character& character);
    void cleanObstacle(Obstacle& obstacle);
    void placeCharacter(const character* character);
    void placeObstacle(const Obstacle& obstacle  ) ;
    
    bool isCellOccupied(int x, int y) const {
        return (map[x][y] != '.');
    }
};

class Obstacle{
	private:
		char symbol;
		string name;
		int x;
		int y;
	public:
		Obstacle(const char symbol ,const string& name, int X , int Y) :  symbol(symbol), name(name), x(X), y(Y) {}; 
		char getSymbol() const { return symbol; }
		int getX() const {return x; }
		int getY() const {return y; }
		void applyEffect(character& someone,Map& chessBoard);
};

class Team{
private:
    vector<character*> members;
    bool teamMark;
public:
    Team(){
        teamMark = false;
    };
    ~Team(){

        for (character* member : members) {
            delete member;
        }

    }
    // 獲得隊伍的大小
    size_t getSize() const {
        return members.size();
    }

    character& operator[](size_t index) const {
        if (index < members.size()) {
            return *members[index];
        } else {
            //越界處理,待修
            return *members[0];
        }
    }

    // 提供 const vector<character*> 的方法
    const vector<character*>& getMembers() const {
        return members;
    }
    
	void setTeamMark(){teamMark = true; return;}
	
    void addClassWizard(int x, int y) {
	    character* newWizard = new Wizard(x, y);  // 假設 Wizard 類別有符合的建構函式
	    members.push_back(newWizard);
	}

    void addClassArcher(int x, int y){
	    character* newArcher = new Archer(x, y);
	    members.push_back(newArcher);
}
	
    void addClassTank(int x, int y){
	    character* newTank = new Tank(x, y);
	    members.push_back(newTank);
	}
    
    void addClassKnight(int x, int y){
	    character* newKnight = new Knight(x, y);
	    members.push_back(newKnight);
}
    
	// 確認是否為第一隊 
    bool getteamMark(){return teamMark;}

    bool allMembersDead() const{
	    for (const character* member : members) {
	        if (member->get_current_HP() > 0) {
	            return false;  // 如果有任何一個成員血量不為 0,返回 false
	        }
	    }
	    return true; 
	}
};


// 地圖函數 
void Map::cleanCharacter(character& character){
    int row = character.getY();
    int col = character.getX();

    // 檢查座標是否合法
    if (row >= 0 && row < rows && col >= 0 && col < cols) {
        map[row][col] = '.';
    }
}

void Map::cleanObstacle(Obstacle& obstacle){
    int row = obstacle.getY();
    int col = obstacle.getX();

    // 檢查座標是否合法
    if (row >= 0 && row < rows && col >= 0 && col < cols) {
        map[row][col] = '.';
    }
}

void Map::placeCharacter(const character* character) {
    int row = character->getY();
    int col = character->getX();

    // 檢查座標是否合法
    if (row >= 0 && row < rows && col >= 0 && col < cols) {
        map[row][col] = character->getSymbol();
    }
}

void Map::placeObstacle(const Obstacle& obstacle){
	int row = obstacle.getY();
    int col = obstacle.getX();

    // 檢查座標是否合法
    if (row >= 0 && row < rows && col >= 0 && col < cols) {
        map[row][col] = obstacle.getSymbol();
    }
}

void Map::draw() const{
    for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                cout << map[i][j] << ' ';
            }
            cout << endl;
        }
}


//character函數 

void character::displayInfo(const vector<character*>& team, int index){
    cout << "member_number " << index << ','<<"Name: " << name << endl;
    cout << "HP: " << current_healthPoints << "/" << origin_healthPoints << endl;
    cout << "Attack: " << attackPoints << endl;
    cout << "Defence: " << defensePoints << endl;
}


void character::move(Map& chessBoard, Team& otherTeam) {
    const int MAX_DIMENSION = 15;
    const int MAX_MOVE_SUM = 5;
    bool moveCompleted = false;

    while (!moveCompleted) {
        try {
            string input;
            cout << "Your Move (attack or move): ";
            cin >> input;
            chessBoard.cleanCharacter(*this);

            if(input == "attack") {
                int attackIndex;
                cout << "Enter attack index: ";
                cin >> attackIndex;
                attack(attackIndex, otherTeam, chessBoard);
                chessBoard.placeCharacter(this);
                moveCompleted = true;
            }
            
            else if(input == "move") {
                int moveX = 0, moveY = 0;
                cout << "Enter move coordinates (x y): ";
                cin >> moveX >> moveY;

                if (abs(moveX) + abs(moveY) > MAX_MOVE_SUM) {
                    throw OutOfBoundsException("Move exceeds maximum allowed distance of 5.");
                }

                int targetX = x + moveX;
                int targetY = y + moveY;

                if (targetX < 0 || targetX >= MAX_DIMENSION || targetY < 0 || targetY >= MAX_DIMENSION) {
                    throw OutOfBoundsException("Target position is out of bounds.");
                }

                if (chessBoard.isCellOccupied(targetX, targetY)) {
                    throw OccupiedCellException("Cell is occupied!");
                }

                x = targetX;
                y = targetY;
                chessBoard.placeCharacter(this);
                cout << "New position: " << x << " " << y << endl;
                moveCompleted = true;
            }
            else {
                throw InvalidInputException("Invalid action input!");
            }
        } catch (const InvalidInputException& e) {
            cout << "Error: " << e.what() << " Please try again." << endl;
        } catch (const OccupiedCellException& e) {
            cout << "Error: " << e.what() << " Please try again." << endl;
        } catch (const OutOfBoundsException& e) {
            cout << "Error: " << e.what() << " Please try again." << endl;
        }
    }
}

// 確認傳入之角色是否於九宮格內
bool character::checkCharacter(character& character) const{
    
	if(abs(x - character.getX()) == 1 && abs(y - character.getY()) == 0 || abs(y - character.getY()) == 1 && abs(x - character.getX()) == 0 || (abs(x - character.getX()) == 1 && abs(y - character.getY()) == 1)){
        return true;
    }
    return false;
    
}

void character::chooseToAttack(const vector<character*>& team){
    vector<size_t> tempAttackIndex;
    for(size_t i = 0; i < team.size(); i++){
        if(checkCharacter(*(team[i])) == true){
            if(team[i]->get_current_HP() == 0){
                continue;
            }
            else{
                tempAttackIndex.push_back(i);
            }
        }
    }
    // 如果此vector為空(沒人可以打)
    if(tempAttackIndex.empty() == true){
        return;
    }
    else{
        cout << "You can attack: ";
        canAttackIndex = tempAttackIndex;
        for(size_t i = 0; i < tempAttackIndex.size(); i++){
            cout << tempAttackIndex[i] << ',' << team[tempAttackIndex[i]]->getName() << " ";
        }
        cout << '\n';
        return;
    }
}

void character::attack(int index, Team& temp, Map& chessBoard){
    temp[index].takeDamage(chessBoard, attackPoints, index, temp);
}

void character::takeDamage(Map& chessBoard, int damage, int index, Team& temp) {
    current_healthPoints -= damage;
    if (current_healthPoints <= 0) {
        current_healthPoints = 0;
        chessBoard.cleanCharacter(*this);
        cout << index << ',' << name << " is DEAD! " << endl;
    }
    else {
        cout << index << ',' << name << " received damage points: " << damage << " Current Health Point: " << current_healthPoints << endl;
    }
}


void character::obstacleHeal(int amount) {
		
		int old_healthPoints = current_healthPoints;
	    int new_healthPoints = current_healthPoints + amount;
	    // 确保生命值不超過最大值
	    current_healthPoints = min(new_healthPoints,origin_healthPoints);
	    cout << name << " restored health points: " << current_healthPoints-old_healthPoints << " Current Health Point:" << current_healthPoints << endl;
	}
	
void character::obstaclePlus(int amount) {
		
	    this->attackPoints += amount;

	    cout << name << " gain an power up, increase " << amount << " attack points, Current attack points is:" << attackPoints << endl;
	}
	
void character::checkObstacle(vector<Obstacle>& allObstacles , Map& chessBoard){
	for (auto& obstacle : allObstacles) {
		
        int obstacleX = obstacle.getX();
        int obstacleY = obstacle.getY();

            // 檢查障礙物是否在九宮格
        if (x >= obstacleX - 1 && x <= obstacleX + 1 && y >= obstacleY - 1 && y <= obstacleY + 1){
                // 如果找到,調用障礙物的 applyEffect 方法
                obstacle.applyEffect(*this,chessBoard);
        }
    }
}


//Obstacle函數 
void Obstacle::applyEffect(character& someone, Map& chessBoard){

    if (name == "supplement") {
        // 回血
        int healAmount = 30; 
        someone.obstacleHeal(healAmount);

        chessBoard.cleanObstacle(*this);
    }
    
    if(name == "plus"){
    	
		//攻擊力加成 
    	int plusAmount = 20;
    	someone.obstaclePlus(plusAmount);

    	chessBoard.cleanObstacle(*this);
	}
	
}





//global function
class InvalidCharacterException : public runtime_error {
public:
    InvalidCharacterException(const string& message) : runtime_error(message) {}
};

class InvalidQuantityException : public runtime_error {
public:
    InvalidQuantityException(const string& message) : runtime_error(message) {}
};

class InvalidLocationException : public runtime_error {
public:
    InvalidLocationException(const string& message) : runtime_error(message) {}
};

void addToTeam(Team& temp, int& teamCnt) {
    map<string, int> characterAddCount;
    while (temp.getSize() < 3) {
        string characterName;
        int quantity = 0;
        int x, y;
        int space = 3 - temp.getSize();

        if (teamCnt == 0) {
            cout << "Which character do you want to add in team1? ( Wizard, Knight, Archer, Tank )" << endl;
        } else if (teamCnt == 1) {
            cout << "Which character do you want to add in team2? ( Wizard, Knight, Archer, Tank )" << endl;
        }

        bool validInput = false;
        while (!validInput) {
            try {
                cin >> characterName;
                if (characterName != "Wizard" && characterName != "Knight" && characterName != "Archer" && characterName != "Tank") {
                    throw InvalidCharacterException("Invalid character type.");
                }

                cout << "You can at most add " << space << " characters." << endl;
                cout << "Quantity: ";
                cin >> quantity;

                if (quantity < 1 || quantity > space) {
                    throw InvalidQuantityException("Invalid quantity. It must be between 1 and " + to_string(space) + ".");
                }

                if (characterAddCount[characterName] + quantity > 2) {
                    throw InvalidQuantityException("Cannot add " + characterName + " more than twice.");
                }

                for (int i = 0; i < quantity; i++) {
                    cout << "Location: ";
                    cin >> x >> y;

                    if (x < 0 || y < 0 || x > 15 || y > 15) {
                        throw InvalidLocationException("Invalid location coordinates.");
                    }
                

                    // 根據角色類型添加角色
                    if (characterName == "Wizard") {
                        temp.addClassWizard(x, y);
                    } else if (characterName == "Knight") {
                        temp.addClassKnight(x, y);
                    } else if (characterName == "Archer") {
                        temp.addClassArcher(x, y);
                    } else if (characterName == "Tank") {
                        temp.addClassTank(x, y);
                    }
                }

                characterAddCount[characterName] += quantity;
                validInput = true;
            } catch (const runtime_error& e) {
                cout << "Error: " << e.what() << " Please try again." << endl;
                cin.clear();
                cin.ignore(numeric_limits<streamsize>::max(), '\n');
            }
        }
    }

    teamCnt++;
}

void message1()
{
    cout << "In an era of warlords, in a fantastical realm devoid of a fiend, people still strive for their individual ideals, forging alliances, forming factions, and harboring enmity towards specific individuals or regions." << endl;
    return;
}

void message2()
{
    cout << "Amidst this tumultuous world, it's a minuscule tale, yet it narrates the joys and sorrows, the comings and goings, of a group of people." << endl;
    return;
}

void message3()
{
    cout << "They vie not for riches or glory but simply for resources enough to sustain their existence. It's a struggle for survival in a world that demands their utmost efforts merely to endure." << endl;
    return;
}

void message4()
{
    cout << "(wizard 1):(to wizard 2)I mourn the necessity for my brother and me to compete for the right to survive. Yet, ever since we chose diverging paths, we've sealed the fate of our current circumstances." << endl;
    cout << "(wizard 2): I don't see it that way. From childhood to now, you've always drawn everyone's attention, praised for all you do. I've merely been a backdrop, compared to you. I'm tired of this life. For whatever reason, I want to give my all to bring you down." << endl;
    return;
}

void message5()
{
    cout << "(tank 1):Now's not the time for you twin brothers to feud. Sharpen your blades; this is a battlefield, not a petty game of play house." << endl;
    return;
}

void message6()
{
    cout << "(archer 2):Let's partake in this bloody party of sorts, and offer our all to each other!" << endl;
    return;
}

void message7()
{
    cout << "(knight 1&2):Exactly to my liking." << endl;
    return;
}

void message8()
{
    cout << "\"Dust to dust, soil to soil. In this battle, someone emerges victorious, yet it doesn't ensure smooth days ahead. Resources remain scarce; we're still in an era of warlords. The current mission remains giving our all to survive in this world.\"" << endl;
    return;
}

int main() {
    // 初始化地圖
    Map chessBoard(15, 15);
    int teamCnt = 0;
    
    set<int> randomNumbers = generateUniqueRandomNumbers(1, 15, 14);
    vector<int> randomNumbersVec(randomNumbers.begin(), randomNumbers.end());

    // 分配到具體變量
	// 分配到具體變量
	int random_x1 = randomNumbersVec[0];
	int random_y1 = randomNumbersVec[1];
	int random_x2 = randomNumbersVec[2];
	int random_y2 = randomNumbersVec[3];
	int random_x3 = randomNumbersVec[4];
	int random_y3 = randomNumbersVec[5];
	int random_x4 = randomNumbersVec[6];
	int random_y4 = randomNumbersVec[7];
	int random_x5 = randomNumbersVec[8];
	int random_y5 = randomNumbersVec[9];
	int random_x6 = randomNumbersVec[10];
	int random_y6 = randomNumbersVec[11];
	int random_x7 = randomNumbersVec[12];
	int random_y7 = randomNumbersVec[13];

vector<Obstacle> All_obstacles = {
    Obstacle('+', "supplement", random_x1, random_y1),
    Obstacle('*', "plus", random_x2, random_y2),
    Obstacle('+', "supplement", random_x3, random_y3),
    Obstacle('+', "supplement", random_x4, random_y4),
    Obstacle('+', "supplement", random_x5, random_y5),
    Obstacle('*', "plus", random_x6, random_y6),
    Obstacle('*', "plus", random_x7, random_y7)
};

    // 丟入Team中之vector<character*> members
    Team team1;
    team1.setTeamMark();
    addToTeam(team1, teamCnt);
    // 丟入Team中之vector<character*> members  
    Team team2;
    cout << "You cannot use team1's members' locations!!!!!!!" << endl;
    addToTeam(team2, teamCnt);


    // 放置隊伍進地圖
    for(size_t i = 0; i < team1.getSize(); i++) {
        chessBoard.placeCharacter(&team1[i]);
    }

    for(size_t i = 0; i < team2.getSize(); i++){
        chessBoard.placeCharacter(&team2[i]);
    }
    
    //放置道具進地圖 
    for (const auto&  Obstacle : All_obstacles ) {
        chessBoard.placeObstacle(Obstacle);
    }

    //遊戲剛開始時地圖
    cout << "Initial Chess Board:" << endl;
    chessBoard.draw();

    //製作一個counter
    int turnCnt = 0;

    if(turnCnt == 0)
        {
            message1();
            message2();
            message3();
            cout << endl;
        }
    
	// Team loop
    while(!team1.allMembersDead() && !team2.allMembersDead()) {
    	
        string check;
        
        for(size_t i = 0 ; i < team1.getSize(); i++) { 
            
			if(team1[i].get_current_HP() == 0) {continue;}
			
            else{
                cout << "Your team : Team1" << endl;
                
                // 顯示角色基本資料
                team1[i].displayInfo(team1.getMembers(), i);
                
                // 顯示可攻擊誰
                team1[i].chooseToAttack(team2.getMembers());


                // 移動角色
                team1[i].move(chessBoard, team2);
                
                //檢查周圍的 Obstacle
				team1[i].checkObstacle(All_obstacles ,chessBoard) ;

                cout << "\n\n\n\n\n\n\n\n\n\n";
                cout << "Chess Board after moving player:" << endl;
                chessBoard.draw();
            }
                        if(turnCnt == 0)
            {
                message4();
                cout << endl;
            }
            else if(turnCnt == 1)
            {
                message5();
                cout << endl;
            }
            else if(turnCnt == 2)
            {
                message6();
                cout << endl;
            }
            else if(turnCnt == 3)
            {
                message7();
                cout << endl;
            }

            turnCnt++;
        }



        for(size_t i = 0 ; i < team2.getSize(); i++) { 
            if(team2[i].get_current_HP() == 0){
                continue;
            }
            else{
                cout << "Your team : Team2" << endl;
                // 顯示角色基本資料
                team2[i].displayInfo(team1.getMembers(), i);

                // 可攻擊誰 如果有敵方的人在周圍即可選擇
                team2[i].chooseToAttack(team1.getMembers());

                // 移動角色
                team2[i].move(chessBoard, team1);

                //toContinue();
                team2[i].checkObstacle(All_obstacles,chessBoard) ;

                cout << "\n\n\n\n\n\n\n\n\n\n";
                cout << "Chess Board after moving player:" << endl;
                chessBoard.draw();
            }
        }
    }
    message8();
    cout << endl;
    
    return 0;
}


Leave a Comment