The game of Mancala is played with pebbles and a board with indentations (depres
ID: 3700082 • Letter: T
Question
The game of Mancala is played with pebbles and a board with indentations (depressions).
Four-player boards also exist. Through the magic of computers, your program for this assignment will allow any number of players. (Even ridiculously high numbers.)
Each player has a side of the board. As you can see above, there are six depressions per side plus a larger depression at each end. Each depression is called a "pit". The larger depression at the right end of your side of the board is your "end" pit, and you want to get as many pebbles into it as you can.
Each player begins with four pebbles in each regular pit, and an empty end pit.
On your turn, you choose any non-empty pit on your side of the board (not including the end pit), and pick up all of the pebbles from that pit and distribute them to the right: one pebble in the next pit to the right, another pebble into the next pit to the right after that; and so on until you've distributed all of them. You might manage to put a pebble into your end pit. If you go beyond your end pit, that's fine, you put pebbles into other player's pits. However, you skip other player's end pits.
If you end your turn by putting a pebble into your own end pit (i.e. if it works out exactly), then you get another turn. There is no limit to how many consecutive turns you can get by this method.
After that, it's another player's turn. The game ends when any one player's side is empty. At the end of the game, each player's score is all of the pebbles remaining on their side (which will consist mostly of the end pit, and will consist exclusively of the end pit for the player who emptied their side).
(If you end your turn by putting a pebble into a non-end pit on your own side which was formerly empty, there's another rule which gets you some of your opponent's pebbles at that point, but this is trickier to generalize to an arbitrary number of players, and doesn't add anything as far as this assignment is concerned, so we're going to ignore that rule for this assignment.)
You can learn your way around this game further by playing it at http://play-mancala.com
The assignment
For assignment four, you will write a Mancala server. Players will connect using nc or similar. The '?p' option specifies a port number to listen on, which otherwise defaults to 3000. Please use the supplied starter code to parse the command-line options.
When a player connects, the server will send them "Welcome to Mancala. What is your name?". After they input an acceptable name which is not equal to any existing player's name and is not the empty string, they are added to the game, and all existing players (if any) are alerted to the addition.
With your server, players can join or leave the game at any time. A player joining the game has their pits initialized as follows. If they are the first player (or all other players have quit), they get the usual four pebbles per non-end pit. Otherwise, each non-end pit gets the average number of pebbles of all current players' non-end pits, rounded up. (See compute_average_pebbles() in the starter code).
You will store the list of connected players as a linked list. New players are added at the top of the linked list (it's easiest to implement this way). Adding a new player must not change whose turn it is, unless this is the first player to join the game. Also, when someone leaves, if it is their turn, the turn has to pass to the next player, not to the top of the list.
For each turn, or to newcomers joining the game, you display the game state in a simple text format. The display looks like this:
That is, one user per line, saying the number of pebbles in each pit (e.g. mine are 5, 1, 6, 7, 6, and 5, respectively), and identifying the pits by index numbers (starting from zero) for the use of players in making their moves.
Then, prompt the player whose turn it is with the query "Your move?", and tell everyone else (for example) "It is ajr's move."
The user is expected to type a single digit, followed by the network newline. Be permissive about other newline conventions; one way to implement this is to accept either or as indicating a newline, and to ignore blank lines. Also, ignore all spaces (e.g. the user might type space, 3, newline; and this is a valid way to specify pit #3).
Then tell everyone what move that player made.
Be prepared for the possibility that the user drops the connection when it is their move. Furthermore, you must notice user input or dropped connections even when it isn't that user's move. If the user types something other than a blank line when it is not their move, tell them "It is not your move." (For a blank line, you can say "It is not your move" or you can ignore it, whichever makes your code simpler.)
As players connect, disconnect, enter their names, and make moves, output a brief statement of each activity to stdout.
Remember to use the network newline in your network communication throughout, but not in messages printed on stdout.
You are allowed to assume that the user does not "type ahead" -- if you receive multiple lines in a single read(), for this assignment you do not need to do what is usually required in working with sockets of storing the excess data for a future input.
However, you can't assume that you get the entire player name in a single read(). For the input of the player name only, if the data you read does not include a newline, you must loop to get the rest of the name. Please see testing notes in the Q&A web page.
Please see supplied starter code in /cmsfaculty/ajr/b09/a4/starter.c; you don't actually have to implement quite all of the above.
Other notes
Call your program "mancsrv.c". Your program must be in standard C. It must compile on the UTSC linux machines with "gcc ?Wall mancsrv.c" with no errors or warning messages, and may not use linux-specific or GNU-specific features.
starter code is here:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int port = 3000;
int listenfd;
#define MAXNAME 80 /* maximum permitted name size, not including */
#define NPITS 6 /* number of pits on a side, not including the end pit */
struct player {
int fd;
int pits[NPITS+1];
other stuff undoubtedly needed here
struct player *next;
} *playerlist = NULL;
extern void parseargs(int argc, char **argv);
extern void makelistener();
extern int compute_average_pebbles();
extern int game_is_over(); /* boolean */
extern void broadcast(char *s);
int main(int argc, char **argv)
{
struct player *p;
char msg[MAXNAME + 50];
parseargs(argc, argv);
makelistener();
while (!game_is_over()) {
}
broadcast("Game over! ");
printf("Game over! ");
for (p = playerlist; p; p = p->next) {
int points, i;
for (points = i = 0; i <= NPITS; i++)
points += p->pits[i];
printf("%s has %d points ", p->name, points);
snprintf(msg, sizeof msg, "%s has %d points ", p->name, points);
broadcast(msg);
}
return(0);
}
void parseargs(int argc, char **argv)
{
int c, status = 0;
while ((c = getopt(argc, argv, "p:")) != EOF) {
switch (c) {
case 'p':
port = atoi(optarg);
break;
default:
status++;
}
}
if (status || optind != argc) {
fprintf(stderr, "usage: %s [-p port] ", argv[0]);
exit(1);
}
}
void makelistener()
{
struct sockaddr_in r;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
memset(&r, '', sizeof r);
r.sin_family = AF_INET;
r.sin_addr.s_addr = INADDR_ANY;
r.sin_port = htons(port);
if (bind(listenfd, (struct sockaddr *)&r, sizeof r)) {
perror("bind");
exit(1);
};
if (listen(listenfd, 5)) {
perror("listen");
exit(1);
}
}
int compute_average_pebbles() /* call this BEFORE linking the new player in to the list */
{
struct player *p;
int i;
if (playerlist == NULL)
return(4);
int nplayers = 0, npebbles = 0;
for (p = playerlist; p; p = p->next) {
nplayers++;
for (i = 0; i < NPITS; i++)
npebbles += p->pits[i];
}
return((npebbles - 1) / nplayers / NPITS + 1); /* round up */
}
int game_is_over() /* boolean */
{
struct player *p;
int i;
if (!playerlist)
return(0); /* we haven't even started yet! */
for (p = playerlist; p; p = p->next) {
int is_all_empty = 1;
for (i = 0; i < NPITS; i++)
if (p->pits[i])
is_all_empty = 0;
if (is_all_empty)
return(1);
}
return(0);
}
Explanation / Answer
Here is the working code for your requirements
#include
#include
#include
void clockwise_move(int b[], int pos, int player_1);
void count_clock_move(int b[], int pos, int player_1);
void mancala_board(int b[]);
int main(void)
{
int player_1, sum, pos, dir, b[30]={4,4,4,4,4,4,0,4,4,4,4,4,4,0}; //pos-position, dir- direction
printf("Welcome to Mancala ");
printf(" 5 4 3 2 1 0 ");
printf("BLUE ");
printf("===[%d] [%d] [%d] [%d] [%d] [%d]--- ", b[5], b[4], b[3], b[2], b[1], b[0]);
printf("|%d| |%d| ", b[6], b[13]);
printf("---[%d] [%d] [%d] [%d] [%d] [%d]=== ", b[7], b[8], b[9], b[10], b[11], b[12]);
printf(" RED ");
printf(" 6 7 8 9 10 11 ");
sum=b[6]+b[13];
player_1=first_player();
while(sum!=48)
{
mancala_board(b);
while (player_1 == 1)
{
mancala_board(b);
printf("Player RED ");
printf("Pick a pos corresponding to the integer: ");
scanf("%d", pos);
while (pos!=6 && pos!=7 && pos!=8 && pos!=9 && pos!=10 && pos!=11)
{
printf(" Invalid input, you have to select a bowl from your side. Please select another pos");
scanf("%d",&pos);
}
printf("Would you like to move clockwise or counter-clockwise?");
printf(" 1. Clockwise 2. Counter-Clockwise");
scanf("%d",&dir);
while(dir!=1 && dir!=2)
{
printf(" Invalid input, you have to select an integer corresponding to the given options. ");
printf(" 1. Clockwise 2. Counter-Clockwise");
scanf("%d",&dir);
}
if (dir==1)
{
pos+=1
clockwise_move(b, pos, turnNum);
}
if(dir==2)
{
pos=+1;
count_clock_move(b, pos, turnNum);
}
player_1-=1;
}
if (player_1 == 0)
{
mancala_board(b);
printf("Player BLUE ");
printf("Pick a pos corresponding to the integer: ");
scanf("%d", pos);
while (pos!=0 && pos!=1 && pos!=2 && pos!=3 && pos!=4 && pos!=5)
{
printf(" Invalid input, you have to select a bowl from your side. Please select another pos");
scanf("%d",&pos);
}
printf("Would you like to move clockwise or counter-clockwise?");
printf(" 1. Clockwise 2. Counter-Clockwise");
scanf("%d",&dir);
while(dir!=1 && dir!=2)
{
printf(" Invalid input, you have to select an integer corresponding to the given options. ");
printf(" 1. Clockwise 2. Counter-Clockwise");
scanf("%d",&dir);
}
if (dir==1)
{
pos+=1
clockwise_move(b, pos, turnNum);
}
if(dir==2)
{
pos=+1;
count_clock_move(b, pos, turnNum);
}
player_1+=1;
}
sum=b[6]+b[13];
}
}
int first_player(int)
{
play=rand()%2;
return (play);
}
void mancala_board(int b[])
{
printf(" 5 4 3 2 1 0 ");
printf("BLUE ");
printf("===[%d] [%d] [%d] [%d] [%d] [%d]--- ", b[5], b[4], b[3], b[2], b[1], b[0]);
printf("|%d| |%d| ", b[6], b[13]);
printf("---[%d] [%d] [%d] [%d] [%d] [%d]=== ", b[7], b[8], b[9], b[10], b[11], b[12]);
printf(" RED ");
printf(" 6 7 8 9 10 11 ");
}
void clockwise_move(int b[], int pos, int player_1)
{
int initPos = pos;
for (int i = 0; i < b[pos] + 1; i++)
{
int curPos = pos + i;
b[i]+=b[i];
if (curPos == 0)
curPos = 13;
else if (curPos >= 28)
curPos -= 28;
if (player_1 == 0)
{
int * current1 = &(b[curPos]);
if (current1 == &(b[6]))
current1 = &(b[7]);
*current1 += 1;
}
else if (player_1 == 1)
{
int * current2 = &(b[curPos]);
if (current2 == &(b[13]))
current2 = &(b[0]);
*current2 += 1;
}
}
b[initPos] = 0;
}
void count_clock_move(int b[], int pos, int player_1)
{
int initPos = pos;
for (int i = 0; i < b[pos] + 1; i++)
{
int curPos = pos + i;
if (curPos == 14)
curPos = 0;
else if (curPos >= 28)
curPos -= 28;
if (player_1 == 0)
{
int * current1 = &(b[curPos]);
if (current1 == &(b[6]))
current1 = &(b[7]);
*current1 += 1;
}
else if (player_1 == 1)
{
int * current2 = &(b[curPos]);
if (current2 == &(b[13]))
current2 = &(b[0]);
*current2 += 1;
}
}
b[initPos] = 0;
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.