Untitled

 avatar
unknown
plain_text
2 years ago
20 kB
11
Indexable
#include <iostream>
#include <vector>
#include <cmath>
#include <string> 
#include <cstdlib> 
#include <stdexcept>
#include <set>
#include <random>
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) {
    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) + ".");
                }

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

                    if (x < 0 || y < 0 ) {  // 或者添加更多座標的檢查條件
                        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);
                    }
                }

                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++;
}

int main() {
    // 初始化地圖
    Map chessBoard(15, 15);
    int teamCnt = 0;
    
    set<int> randomNumbers = generateUniqueRandomNumbers(2, 10, 4);
    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];
    
    vector<Obstacle> All_obstacles = {
		Obstacle('+',"supplement",random_x1, random_y1),
		Obstacle('*',"plus",random_x2 , random_y2),
	};

    // 丟入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();

    
	// 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();
            }
        }

        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();
            }
        }
    }
    
    return 0;
}









Editor is loading...
Leave a Comment