在本次作业中,将代写游戏Left-Center-Right( [ LCR ](https://dicegames.com/products/the-
original-lcr-left-center-right-dice-game “LCR”)
)。LCR是一种骰子游戏,玩家掷三个骰子,并根据掷骰的结果分配筹码。
![LCR](https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Dice.jpg/180px-
Dice.jpg)
Requirement
In this assignment, we are going to explore variants of the game Left-Center-
Right (LCR). LCR is a dice game. Traditionally, players roll three dice and
distribute chips based on the outcome of the roll. We will specify the chip
distribution in the form of a table:
Die | Roll Result |
---|---|
1 | Hold |
2 | Hold |
3 | Hold |
4 | Pass 1 Chip to the Right |
5 | Place 1 Chip in the Center |
6 | Pass 1 Chip to the Left |
The game is played until only one player still holds chips (or, in our case, | |
until a certain number of rounds has been played if more than one player holds | |
chips). If there is a winner (only 1 player left with chips), that player | |
collects all the chips in the center. | |
Each player starts with a certain number of chips. This is an input parameter. | |
The starting player is chosen randomly and then play continues to the left as | |
with many card games. | |
A player rolls a maximum of 3 dice. If the player has 3 or fewer chips, the | |
player rolls that many dice. | |
If the player has no chips, she sits out the round. In our simulation, the | |
player is passed three dice values and must decide how many values to use. | |
Once the dice are rolled, the player follows the distribution table, which is | |
also an input parameter. | |
For example, assume a player has 10 chips and is using the distribution table | |
above. She rolls 3 dice with values of 2, 4, 5. She then passes one chip to | |
the player to her right (because of the 4) and places on chip in the center | |
(because of the 5). She does nothing for her 2 roll because that is a ‘hold’. |
Step 1
Create a class called ‘Player’ which will handle the play of a single player.
It is ok to make all the methods in Player public.
a. Create a constructor for Player which takes the following parameters:
Player(const int* chipDistribution)
Where chipDistribution is an array that represents the distribution rules. The
0th offset of the array represents a die roll of 1, 1st offset represents 2,
etc.
The values in the chipDistribution have the following meaning:
0: hold
1: pass left
2: put in center
3: pass right
chipDistribution should be stored in a property.
b. Create a method called setLeftPlayer(Player* p) which will be used to set
the player to the object’s left. You should store this value in a class
property. You should also create a method Player* getLeftPlayer()which returns
the value of this property.
c. Create a method called setRightPlayer(Player* p) which will be used to set
the player to the object’s right You should store this value in a class
property. You should also create a method Player* getRightPlayer()which
returns the value of this property.
d. Create a getter and a setter for the number of chips the player holds: int
getNumChips(), void setNumChips(int nc) numChips should be stored in a
property.
e. Create a method called int addChips(int nc)which adds nc chips to the
player’s stack. nc may be negative. Hint: you may want to do something like:
this->setNumChips(this->getNumChips() + nc); addChips() should return the
number of chips the player holds after the addition.
f. Create a method called: int play(int d1, int d2, int d3) which plays a
round of the game for the player. d1, d2 and d3 represent dice rolls. It is up
to the player to decide how many of the dice to use (based on the number of
chips the player holds) and how to interpret the dice values (based on the
player’s distribution table). It is also up to the player to remove chips from
her own stack when distributing them to other players or to the center.
To give chips to a player, the method should call the addChips() method of the
left or right player, depending on which player the distribution is going to.
play() should return the number of chips placed in the center during the
player’s round
Note: you may find it useful to create a method that handles a single die roll
and then call it up to 3 times from play()
Step 2
Create a class called ‘Game’ which will manage game play. It is ok to make all
the methods in
Game public.
a. Create a constructor for Game:
Game(int numPlayers, const int* chipDistribution, long seed)
The constructor should create a property which is a dynamically allocated
array of pointers to Player objects of size numPlayers.
The constructor should populate the array by creating new Player objects and
use chipDistribution as the distribution table (each Player gets passed the
same chipDistribution value).
Once the array is populated, the constructor should loop through the array of
Players and call setLeftPlayer() and setRightPlayer() for each array entry. If
off represents the index of the player in the array, then the left player will
be the player at index off-1 off+1 and the right player will be the player at
index off+1 off-1.
BE CAREFUL TO HANDLE off==0 and off==numPlayers-1 propertly. If off==0, then
the left right player will be at index numPlayers-1. If off==numPlayers-1,
then the right left player will be at index 0. The modulo operator (%) can
help with this index arithmetic.
The seed parameter should be used to create a Mersenne Twister that is a
property of the class and will be used to select the first player and to roll
dice.
b. Create a destructor for Game that loops through and deletes each player and
then delete[]’s the player array.
c. Create a method int countPlayersWithChips() which returns the number of
players that hold chips. The game is over when only one player holds chips.
d. Create a method int playRound(int startingPlayer) that loops through the
players, in order with the starting point defined defined by the
startingPlayer parameter, and rolls dice and then calls the Player’s play()
method. You will need to create 3 random rolls of a die (values in [1,6])
using the Mersenne Twister you created in the Game’s constructor. playRound()
should return the number of chips that were placed in the center during the
round (that is, it should sum the values returned by Player’s play() method
for the round).
For example, if there are 10 players and startingPlayer is 4, then the round
will start with the Player at index 4 in the Player array. Assume you’ve named
your Player array players, then you’ll call players[4]->play(d1, d2, d3) then
play() of players[5], players[6], players[7], players[8], players[9],
players[0], players[1], players[2], players[3].
Remember the modulo operator (%) can help you with this:
for (int i = 0; i < numPlayers; i++) {
int index = (i + startingPlayer) % numPlayers;
// do stuff with index
}
—|—
e. Create a method const int playGame(const int startingChips, int
maxRounds) that plays the game until it is completed or the maximum number of
rounds has been reached.
Before play begins, the starting player should be chosen randomly (using the
object’s Mersenne Twister). The same starting player should be used throughout
the game.
Also before play begins, treat startingChips as an array and call each
Player’s setNumChips() method to set the initial number of chips each player
holds (these may not be the same).
For up to maxRounds iterations, call the playRound() method and keep track of
the number of chips in the center. If there is only one player with chips
after the round, the game is concluded.
When the game is concluded (only one player has chips or maxRounds has been
reached), then populate and return an array with the number of chips each
player holds. i. If only one player holds chips, then give that player the
chips in the center. ii. If the maximum number of rounds has been reached,
then ignore the chips in the center.
Note: you should create the chip count array in the class constructor and
delete[] it in the destructor. We are going to call playGame repeatedly and
want to reuse the same chip count array.
The output of the program is a file called lcr_output.csv. The first columns
in the output are a description of the game, the number of simulations run for
which the analysis is being output (100,
1000, 10000, 100000) and the percentage of time the game ended with a winner
(one player has all the chips). These columns are followed by the expected
number of chips each player has after the simulated runs.
Add your code to the program and run it.
- Q1: Which game (standard, standard-tilted, nocenter, nocenter-tilted, nohold, nohold-tilted) resulted in the most single-player winners? Why do you think that is?
- Q2: How quickly do the simulated runs converge into stable expected values? Which game, if any, converges the quickest? Which game, if any, converges the slowest? If you see a difference, why do you think the convergence times differ?
In a single Word or PDF file, include the answers to the two questions, your
code and lcr_output.csv.