我正在尝试构建一个 2 人游戏,其中程序掷骰子,玩家必须从 12 列中选择要玩的列。
我的问题是当骰子滚动(例如:5(并且玩家 1 选择他们的列时。它工作正常,直到玩家 2 选择同一列并覆盖玩家 1 在该列中的内容,而不是在其上方的可用空间中播放。
这是我的代码:
#include <iostream>
#include <windows.h>
#include <ctime>
#include <iomanip>
#include <algorithm>
#include "TheRebuild.h"
using namespace std;
int k = 0;
auto dice = 0;
int col_in = 0;
int col_space = 0;
int x = 0;
int y = 0;
int counter = 0;
char space = '-';
char board[gridrow][gridcol];
//accessors
string Players::getname(Users play[], int k) const {
return play[k].name;
}
char Players::gettoken(Users play[], int k) const {
return play[k].token;
}
int Players::getscore(Users play[], int k) const {
return play[k].score;
}
//mutator
void Players::RecInfo(Users play[], int k, string id, char piece, int scr) {
play[k].name = id;
play[k].token = piece;
play[k].score = scr;
}
Players::Players() {
for (int k = 0; k < arrsize; k++) {
play[k].name = "";
play[k].token = ' ';
play[k].score = 0;
}
}
void Players::askUser(Players::Users *play)
{
string id = " ";
char piece = ' ';
int scr = 0;
//cin.get();
for (int k = 0; k <= arrsize; k++) {
cout << "Player " << k + 1 << "! Enter your Name: ";
getline(cin, id);
cout << "Player " << k + 1 << " Enter a character to play with: ";
cin >> piece;
cout << endl;
system("pause");
RecInfo(play, k, id, piece, scr);
system("cls");
cin.get();
}
}
int Players::DiceRoll()
{
int dice = 0;
srand(time(nullptr));
dice = (rand() % 6) + 1;
return dice;
}
void Players::Player1() {
dice = DiceRoll();
cout << "Dice stopped rolling at: " << dice << endl;
cout << play[0].name <<" Enter column to play in: ";
cin >> col_in;
if ((col_in < 1) && (col_in > 12)) // failsafe - player does not play anything out of 1-12 range
{
cin.get();
cout << "Turn lost!";
return;
}
else
{
col_space = col_in-1;
}
if (board[x][gridcol] != space)
{
x++;
for (x = gridcol; x > gridcol - (dice +1); x--) // this loop allows player pieces to start at "11" of the board rather than at the "0"
{
board[x][col_space] = play[0].token;
Sleep(50);
}
}
else
{
for (x = gridcol; x > gridcol - (dice +1); x--) // this loop allows player pieces to start at "11" of the board rather than at the "0"
{
board[x][col_space] = play[0].token;
Sleep(50);
}
}
}
void Players::Player2() {
dice = DiceRoll();
cout << "Dice stopped rolling at: " << dice << endl;
cout << play[1].name <<" Enter column to play in: ";
cin >> col_in;
if ((col_in < 1) && (col_in > 12)) // failsafe - player does not play anything out of 1-12 range
{
cin.get();
cout << "Turn lost!";
return;
}
else
{
col_space = col_in - 1;
}
for (x = gridcol; x > gridcol-(dice +1); x--) // this loop allows player pieces to start at the bottom of the board rather than at the top
{
board[x][col_space] = play[1].token;
Sleep(50);
}
}
void Players::Header() {
//---------------------------- Print --------------------------------
// this prints the board with all the changes made by the player... this is OK
string border(48, '-');
system("cls");
cout << border << endl
<< "| Fill 'Em Up | n"
<< border << endl
<< " 1 2 3 4 5 6 7 8 9 10 11 12 n"
<< border << endl; // header for the board
}
void Players::Sub_UI() {
//Basic UI elements - Displays Player Name, Their Score (number of tokens on the board), and the token they chose
// I plan to add colors for player 1 and player 2 tokens, but the gameplay is more important
string sub(15, '^');
cout << endl << sub << "ttt " << sub << endl; // top boarder for player information
cout << "Player: " << play[0].name << "ttt" << " Player: " << play[1].name << endl; // names of players
}
bool Players::endgame() {
return false;
}
void Players::mainStage(Players::Users *play) {
for(x = 0; x <gridrow; x++){
for (y = 0; y < gridcol; y++){
board[x][y] = space;
}
}
do // loop for the whole game - see "while" at the end
{
Header();
for (x = 0; x < gridrow; x++) // actual grid being printed x is row, y is col, just like a normal x and y axis
{
for (y = 0; y < gridcol; y++) {
cout << " " << board[x][y] << " ";
}
cout << endl;
}
//Token Counter
int count1 = count(*board, *board+144, play[0].token); // used to count how many tokens on the board belong to Player 1
int count2 = count(*board, *board+144, play[1].token); // used to count how many tokens on the board belong to Player 2
//Small UI elements
Sub_UI();
cout << "Score: " << count1 << " -> " << play[0].token << "ttt" << " Score: " << count2 << " -> " << play[1].token << endl << endl; // scores and tokens respectively
//Player1
if (counter % 2 == 0)
{
Player1();
}
else //Player2
{
Player2();
}counter++;
}while(!endgame());
}
有人对纠正这一点有任何想法吗?
完成后应该看起来像这样
------------------------------------------------
| Game Title |
------------------------------------------------
1 2 3 4 5 6 7 8 9 10 11 12
------------------------------------------------
- - - - - - - - - - - -
- - - - - - - - - - - -
- - - - - - - - - - - -
- - - - - - - - - - - -
- - - - - - - - - - - -
- - - - - - - - - - - -
- - - - - - - - - - - -
- $ - - - - - - $ - - -
- $ - - - - - - $ - - -
- $ - - - - - - $ - - -
- $ - - - - - - @ - - @
- $ - - - - - - @ - - @
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
Player: Player1 Player: Player2
Score: 4 -> @ Score: 8 -> $
Dice stopped rolling at: 2
Player1 Enter column to play in:
请注意玩家 2 如何在玩家 1 的令牌上方输入 3 个令牌,而不是覆盖它们
首先,我注意到代码中的一个错误:
if ((col_in < 1) && (col_in > 12))
数字不能小于 1且不能大于 12。您需要在那里使用||
。
代码重构成更小的函数,这很好,但你把所有这些函数都放到一个巨大的类中。我用更多的类重新做了代码。每个人都有自己的工作。以下是我使用的类:
game_board
管理董事会die
掷骰子的简单类(使用较新的随机函数(player
保留玩家数据。将有 2 个此类对象 - 每个玩家 1 个game
处理所有游戏逻辑的主类
其他一些注意事项:
- 创建了一个帮助程序函数以从
cin
读取int
或char
。它将确保用户输入正确的类型并消耗任何额外的字符 - 包括换行符 - 我使用
std::vector
而不是数组
这是我的代码。请注意,这并不是最好的或唯一的方法。但希望它能显示出将代码分解成更小部分的优势。
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <random>
#include <limits>
#include <stdexcept>
#include <sstream>
using std::cout;
using std::endl;
using std::string;
using std::vector;
// Helper function to get user inputs. Keeps trying until the right type is entered
// Also clears any extra chars
template<typename T>
T get_input()
{
T i{};
while (!(std::cin >> i)) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
}
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
return i;
}
class column
{
protected:
vector<char> data;
public:
static const char SPACE_CHAR = '-';
column(int rows) :
data(rows, SPACE_CHAR)
{}
bool is_full() const
{
return data[0] != SPACE_CHAR;
}
void add(char token)
{
auto result = std::find_if(data.rbegin(), data.rend(), [this](char c) { return c == SPACE_CHAR; });
if (data.rend() == result) {
cout << "ERROR";
return;
}
*result = token;
}
int free_spaces() const
{
auto result = std::find_if(data.begin(), data.end(), [this](char c) { return c != SPACE_CHAR; });
return std::distance(data.begin(), result);
}
int count_tokens(char token) const
{
return std::count(data.begin(), data.end(), token);
}
int num_rows() const { return data.size(); }
// Needed for std::max_element
bool operator<(const column& other) const { return data.size() < other.data.size(); }
// Index operator. Does not throw on index out of bounds.
char operator[](int i) const { return i < data.size() ? data[i] : ' '; }
};
class game_board
{
protected:
vector<column> board;
public:
game_board(int rows, int cols)
{
for (int c = 0; c < cols; c++) {
board.push_back(column(rows));
}
}
void print() const
{
::system("CLS");
for (int c = 1; c <= board.size(); c++) {
cout << std::right << std::setw(3) << c << ' ';
}
cout << endl;
static char c1 = 0;
// The game currently supports columns with different sizes
// For printing, need to know max number of rows
int rows = (*std::max_element(board.begin(), board.end())).num_rows();
for (int r = 0; r < rows; r++) {
for (auto c : board) {
cout << " " << c[r] << ' ';
}
cout << endl;
}
}
bool column_is_full(int col) const
{
return board[col].is_full();
}
// Adds a token to the vector in the column given
void add_to_col(int col, char token)
{
board[col].add(token);
}
bool is_full()
{
auto result = std::find_if(board.begin(), board.end(), [this](column& c) { return !c.is_full(); });
return result == board.end();
}
int free_spaces(int col) const
{
return board[col].free_spaces();
}
// Get a complete count of all tokens on the board
int get_count(char token) const
{
int count = 0;
for (auto c : board) {
count += c.count_tokens(token);
}
return count;
}
int get_num_rows(int col) const { return board[col].num_rows(); }
int get_num_cols() const { return board.size(); }
};
class die {
protected:
std::random_device rd;
std::mt19937 mt;
std::uniform_real_distribution<double> dist;
public:
die(int num_sides) :
mt(rd()), dist(1, num_sides + 1)
{
}
int roll() {
return (int)dist(mt);
}
};
class player
{
protected:
string name;
char token;
public:
player(int id)
{
cout << "Player " << id << "! Enter your Name: ";
std::getline(std::cin, name);
cout << "Player " << id << " Enter a character to play with: ";
token = get_input<char>();
}
string get_name() const { return name; }
char get_token() const { return token; }
};
class game
{
protected:
player player1, player2;
game_board board;
die the_die;
// Take one players turn
void player_turn(player& p)
{
int dice = the_die.roll();
cout << "Dice stopped rolling at: " << dice << endl;
// Keep trying until the player selects a column that is not full
while (true) {
cout << p.get_name() << " Enter column to play in: ";
int col_in = get_input<int>() - 1;
// If the choose a column outside of the board, end turn
if ((col_in < 0) || (col_in >= board.get_num_cols()))
{
cout << "Turn lost!" << endl;
return;
}
// Only play if column is not full
//if (!board.column_is_full(col_in)) {
if (board.free_spaces(col_in) >= dice) {
// Fill in the column with the player's token
// Note: this allows to use a column with less than dice number of free spaces
// Ex: column has 3 open spaces, but dice roll is 5. Will fill column to top
for (int i = 0; !board.column_is_full(col_in) && i < dice; i++) {
board.add_to_col(col_in, p.get_token());
}
return;
}
cout << "Not enough space. Try again..." << endl;
}
}
void print_score() const
{
const player players[] = { player1, player2 };
for (int i = 0; i < 2; i++) {
cout << "Player: " << std::left << std::setw(12) << players[i].get_name();
}
cout << endl;
for (int i = 0; i < 2; i++) {
std::stringstream ss;
ss << "Score: " << players[i].get_token() << " -> " << board.get_count(players[i].get_token());
cout << std::left << std::setw(20) << ss.str();
}
cout << endl;
}
public:
game(int rows, int cols) :
player1(1), player2(2), board(rows, cols), the_die(6)
{
}
void play_game()
{
// Keep playing until board is full
while (!board.is_full()) {
board.print();
print_score();
player_turn(player1);
if (!board.is_full()) {
board.print();
print_score();
player_turn(player2);
}
}
cout << endl << "Final Score:" << endl;
print_score();
}
};
int main() {
game g(12, 12);
g.play_game();
return 0;
}