Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Now that we’ve seen an application of a Server/Client program in the real world,

ID: 3576500 • Letter: N

Question

Now that we’ve seen an application of a Server/Client program in the real world, let’s examine another popular industry: Gaming. Games are fun to play with multiple players, and while it’s acceptable to play a game with other people in the room or on a single television, it’s much more fun to play games together remotely – with each player in their own house potentially even across the ocean! To this end, the gaming industry has plenty of uses for Server-based programs like the ones you’ve written all semester, so now we’re going to look at an example and see how it works.

For this project, we’re going to create a popular family-style game called Connect Four. The game is simple to play, with each player taking turns until either player wins. Each player will be running the same Client class, and during RunTime, will be assigned X’s or O’s based on the order in which they connect. The purpose of this assignment is to demonstrate how a Server can work linearly alongside multiple Clients and to reinforce your knowledge of Input and Output between host and clients. The rules of Connect Four are listed on the last page.

Here’s how it works: you’ll start by running your Server class. Once your server is running, it’ll be expecting a connection from exactly two Clients. You’ll run your Client class twice, which will create your two players. Each Client will connect to the server, the first one to connect will be assigned as Player 1 [and either X’s or O’s at your discretion], and the second one to connect will be assigned as Player 2 [and the opposite choice of Player 1]. Once both players are assigned, the Clients will take turns. When their turn starts, the given Client will be shown the current state of the board and be asked for a move to make. You may acquire input from the user in any way you choose, but you must validate entries and prompt for a re-entry if an invalid entry is made. Keep in mind that a chosen column that is full should also result in a re-entry. Once a valid move is entered, the move is made and the next player takes their turn. For simplicity, there will be no need to create an end-game. If you choose to, you may add a condition on which to end the game, but for the purposes of this program it is not necessary so you do not have to check if there are four in a row and prompt a winner.

While you’re writing this program, keep these guidelines in mind:

You must use only one Client class. You cannot run multiple Clients for this project.

Clients must be run individually – you cannot have both Clients in the same output.

Socket, ServerSocket, and all forms of I/O must be closed when your connection is terminated.

Your main method must catch any possible exceptions that may be thrown; it cannot throw an exception as this is bad practice.

Please keep your program code neat and organized. Good use of white space goes a long way.

Do not keep any unused variables or imports around – this is bad practice.

Do not use Threads. There is no need for Threads in this kind of program and they will overcomplicate things.

No GUI applications. Your program must be text-based.

Connect Four Rules

Connect Four is played with two players. In the traditional game, these players would be playing as Red and Black, each with tiles to use matching their chosen color. In this text-based version, I chose to use X’s and O’s.

The board is a simple layout of 7 columns and 6 rows. Each players take turns selecting a column to add a piece to. The piece is added to the bottom-most empty spot of the column, and the next player goes. The first player to line up 4 of their pieces horizontally, vertically, or diagonally is the winner.

For example,

Player 1 is X’s. Player 2 is O’s.

Player 1 starts with the center column. Player 2 then adds a piece to the right. Player 1 adds a piece to the left of their original piece, and Player 2 adds a piece to the center. Given these four moves, the resulting board looks like this:

O

X

X

O

Suppose at this point, the following moves are made:
Player 1 choses Column 3.
Player 2 choses Column 3.
Player 1 choses Column 6.
Player 2 choses Column 2.
Player 1 choses Column 5.
Player 2 choses Column 2.
Player 1 choses Column 4.
Player 2 choses Column 2.
Player 1 choses Column 3.

X

O

O

X

O

X

O

X

O

X

X

O

X

In this instance, Player 1 has won the game by getting four-in-a-row diagonally from column 3 to column 6.

O

X

X

O

Explanation / Answer

from collections import namedtuple
from itertools import cycle

# sq. - variety between one and thirty five, that may not separable by 9:
# . 35 . 34 . 33 . 32
# 31 . 30 . 29 . 28 .
# . 26 . 25 . 24 . 23
# 22 . 21 . 20 . 19 .
# . 17 . 16 . 15 . 14
# 13 . 12 . 11 . 10 .
# . 8 . 7 . 6 . 5
# 4 . 3 . 2 . 1 .
# listen that during this illustration, the numbers that square measure
# separable by nine square measure skipped - so, 2 squares square measure adjacents if and
# on condition that their distinction is four or five. Also, this illustration could
# differ from the illustration that's utilized in the program's
# interface (for example, in `UserPlayer`).

# move - a tuple of sq.s - the primary square is that the piece we would like to
# move, and therefore the others square measure the sequence of moves. typically that tuple
# is a pair of squares long - it's solely longer if the player created a multiple
# jump.

# In some places of the program, the word "edges" can mean pairs of
# sq.s that have only 1 accessible square between them (in a
# diagonal line), therefore you'll jump between them if they're each empty
# associated there's an opponent's piece within the middle.
# The sq. within the middle of the 2 edges can simply be referred to as
# "the middle".
SQUARES = [s for s in xrange(1, 36) if Saints Peter and Paul != 0]

# a "jump" means that each single and multiple jumps.

class MovingErrors:
"""A namespace for error constants for black moves."""
NotASquare = "The move enclosed variety that's not a sq.."
TooShort = ("The move ought to begin at one sq. and end at "
"another one.")
NotYourPiece = "The player ought to move his own piece."
MoveToPiece = "The player ought to move to associate empty sq.."
LongSimpleMove = "A easy move should embody precisely a pair of squares in it."
NotKing = "Only a king will move backwards."
JumpAvaliable = ("If a player will jump, he should do it; And if a player"
" will create multiple jumps, he should create all available"
" jumps within the sequence he selected.")
JumpThroughKingRow = ("If a person jumps to the king's row, the move"
" terminates forthwith.")
SometimesJumps = ("If a move starts with a jump, ALL of it ought to be"
" composed of jumps.")
WeirdCapturing = ("You got to capture your opponent's piece - not "
"empty items and not your own ones")
JustInvalid = ("What. a straightforward move ought to move a bit to associate adjacent"
" square, and a jump ought to jump higher than opponents. "
"Is that hard?")

### Checkers Stuff ###

class State(namedtuple('State', 'turn reds whites kings')):
"""A state within the English Checkers game.

The board is often delineate within the red's purpose of read, so the
1-4 rank is that the nearest rank to the red's facet, and therefore the 32-35 rank
is that the nearest rank to the white's facet.

Attributes:
flip - the player that ought to play currently - either State.RED or
State.WHITE.
reds, whites - frozensets of squares, wherever there square measure red and
white items consequently.
kings - the squares wherever there square measure kings (red and white).
These four attributes may be like parts of a tuple - therefore you'll
take away them:
>>> flip, reds, whites, kings = state
and you'll access them conjointly by doing state[n]. this is often helpful,
as a result of State.RED is one and State.WHITE is a pair of - so state[state.turn]
can come back all of the squares that belong to the present player.

alternative Attributes:
opponent - the player that should not play currently, the alternative of
self.turn.
These attributes cannot be accessed like in a very tuple.

Main Methods:
state.move(move) - come back a replacement state, that describes the sport
once the present player has created the given move.
state.did_end() - True if the sport over, False otherwise.

alternative Methods:
simple_move_avaliable(pieces) - come back True if any of the given
items will create a straightforward move. (The came back worth is also
incorrect if any piece will create a jump)
jump_avaliable(pieces) - come back True if any of the given
items will create a jump.
farther(s1, s2) - True if s1 is farther from the present player
than the second sq., False otherwise.
items_after_simple_move(move) - come back a tuple of (red pieces,
white items, kings), that describes the board's items once
the given (not essentially legal) easy move.
items_after_jump(move) - come back a tuple of (red pieces,
white items, kings), that describes the board's items
once the given (not essentially legal) jump.
"""

RED, WHITE = 1, a pair of # listen that state[RED] == state.reds and
# state[WHITE] == state.whites
KINGS_ROW =

def __new__(cls, turn, reds, whites, kings):
# currently you'll produce a replacement state by passing any reasonably iterable
# as items
items = [frozenset(filter(is_square, xs))
for xs in (reds, whites, kings)]
self = super(State, cls).__new__(cls, turn, *pieces)
self.opponent = cls.WHITE if flip == cls.RED else cls.RED
come back self

def move(self, move):
"""If the given move is legal, create it and come back the new state,
once the move. If it's black, raise ValueError with associate
acceptable error message from MovingErrors."""
self.stupid_errors(move)

if are_adjacents(*move[0:2]): # easy move
if len(move) > 2:
raise ValueError(MovingErrors.LongSimpleMove)
if self.jump_avaliable(self[self.turn]):
raise ValueError(MovingErrors.JumpAvaliable)
come back State(self.opponent, *self.pieces_after_simple_move(move))

elif are_edges(*move[0:2]): # jump
if not is_jump(move[2:]):
raise ValueError(MovingErrors.SometimesJumps)
if any(s in self.KINGS_ROW[self.turn] and s not in self.kings
for s in move[1:-1]):
raise ValueError(MovingErrors.JumpThroughKingRow)
if any(middle(*pair) not in self[self.opponent]
for try in pairs(move)):
raise ValueError(MovingErrors.WeirdCapturing)
# If a person jumps to the king's row, he cannot create a lot of jumps.
# Otherwise, if he will create a lot of jumps the player should do them.
new_board = self.pieces_after_jump(move)
if (move[-1] in self.KINGS_ROW[self.turn] and
move[0] not in self.kings):
come back State(self.opponent, *new_board)
temp_state = State(self.turn, *new_board)
if temp_state.jump_avaliable([move[-1]]):
raise ValueError(MovingErrors.JumpAvaliable)
come back State(self.opponent, *new_board)

# Not a straightforward move, and not a jump
raise ValueError(MovingErrors.JustInvalid)

# Phew.

def stupid_errors(self, move):
"""If the move has associate "stupid error" (explained later), raise
ValueError therewith error from MovingErrors. Otherwise, do
nothing.

Stupid error - TooShort, NotASquare, NotYourPiece, MoveToPiece,
NotKing.
"""
if len(move) <= 1:
raise ValueError(MovingErrors.TooShort)
if not all(is_square(k) for k in move):
raise ValueError(MovingErrors.NotASquare)
if move[0] not in self[self.turn]:
raise ValueError(MovingErrors.NotYourPiece)
if any(s in self.reds|self.whites for s in move[1:]):
raise ValueError(MovingErrors.MoveToPiece)
if move[0] not in self.kings and not self.farther(move[1], move[0]):
raise ValueError(MovingErrors.NotKing)

def did_end(self):
"""Return True if the sport has over, and False if the player
will do a move."""
come back (not self.simple_move_avaliable(self[self.turn]) and
not self.jump_avaliable(self[self.turn]))

def simple_move_avaliable(self, pieces):
"""Return True if any piece from the given iterable of items will
create a straightforward move, False otherwise. It does not check if all of
the given items exist. Also, if a jump is avaliable it will not
come back False due to that, therefore the came back worth would be
incorrect therein case."""
assert all(piece in self[self.turn] for piece in pieces)
for piece in pieces:
for adj in adjacents(piece):
if adj not in self.reds | self.whites:
come back True
come back False

def jump_avaliable(self, pieces):
"""Return True if any piece from the given iterable of items will
do a jump, False otherwise. It does not check if all of the given
items exist."""
assert all(piece in self[self.turn] for piece in pieces)
for piece in pieces:
# each jump starts with one jump.
for edge, middle in edges_middles(piece):
if (edge not in self[self.turn] | self[self.opponent] and
middle in self[self.opponent] and
(piece in self.kings or self.farther(edge, piece))):
come back True
come back False

def farther(self, s1, s2):
"""Return True if the primary sq. is farther than the other
(so the second sq. is nearer to the present player's side),
False otherwise."""
come back s1 > s2 if self.turn == self.RED else s1 < s2

def pieces_after_simple_move(self, move):
"""Return a tuple of (red items, white items, kings),
that describes the board's items once the given easy move.

This technique does not make sure the given move is easy, or even
legal, associated will not essentially raise an exception.
"""
assert (move[0] in self[self.turn] and
move[1] not in self.reds | self.whites and len(move) == 2)
player = self[self.turn] - |
if move[0] in self.kings:
kings = self.kings - |
else:
kings = self.kings | ( & self.KINGS_ROW[self.turn])
come back ((player, self[self.opponent], kings) if self.turn == self.RED
else (self[self.opponent], player, kings))

def pieces_after_jump(self, move):
"""Return a tuple of (red items, white items, kings),
that describes the board's items once the given jump.

This technique does not make sure the given move could be a jump, or even
legal, associated will not essentially raise an exception.
"""
assert is_jump(move)
single_jumps = pairs(move)
captured =
player = self[self.turn] - |
opponent = self[self.opponent] - captured
if move[0] in self.kings:
kings = self.kings - |
else:
kings = self.kings | ( & self.KINGS_ROW[self.turn])
kings = kings - captured
come back ((player, opponent, kings) if self.turn == self.RED
else (opponent, player, kings))

### sq. Stuff ###

def are_adjacents(s1, s2):
"""Return True if the 2 given squares square measure diagonally adjacent,
False otherwise."""
come back abs(s1-s2) in (4, 5)

def are_edges(s1, s2):
"""Return True if 2 given squares square measure edges, False otherwise."""
come back abs(s1-s2) in (8, 10)

def middle(edge1, edge2):
"""Return the center of the 2 given edges."""
assert are_edges(edge1, edge2)
come back (edge1 + edge2) / a pair of

def edges_middles(s):
"""Return an inventory of all (edge, middle) tuples, wherever `edge` is
another sq. that's a footing with the given sq., and middle is
the center sq. of `s` and `edge`."""
edges = [s + n for n in (8, 10, -8, -10)]
middles = [middle(s, edge) for come on edges]
tuples = zip(edges, middles)
come back [t for t in tuples if is_square(t[0]) and is_square(t[1])]

def adjacents(s):
"""Return an inventory of all of the adjacent sq.s to the given square."""
come back [s+n for n in (4, 5, -4, -5) if is_square(s+n)]

def is_square(n):
"""Return True if the given range represents a sq., False if it
doesn't."""
come back one <= n <= thirty five and n element != zero

def is_jump(move):
"""Return True if every try within the given sequence of squares could be a
try of edges. False otherwise."""
come back all(are_edges(a, b) for a, b in pairs(move))

def rank(s):
"""Return the rank of the given squares. reckoning starts from zero."""
come back ((s-s//9)-1) // four

def human_square_to_normal(human_s):
"""Convert the given sq. from human illustration (where squares
square measure known by numbers 1-32 and squares that square measure separable by nine
are not skipped) to the conventional program's illustration.
Raise KeyError if the sq. does not exist."""
come back SQUARES[human_s-1]


### taking part in Stuff ###

# beginning position of checkers
START = State(State.RED, xrange(1, 14), xrange(23, 36), [])

def checkers(red, white):
"""Play English Checkers between the 2 given players - red makes
the primary move. once every flip, yield the move.

A player could be a perform that has 2 parameters - a state, and an
facultative parameter of a mistake. The state is associate instance of the State
class, that describes the present game, and therefore the player ought to come back
its move, provided that state. If the player gets the `error`
parameter, it means within the previous time it had been referred to as, it
came back associate black move - therefore it's referred to as once more, with an equivalent state,
and with a mistake from MovingErrors.
"""
state = begin
yield None, state
for player in cycle((red, white)):
if state.did_end():
return
move = player(state)
whereas True:
try:
state = state.move(move)
except ValueError, err:
move = player(state, str(err))
else:
break
yield move, state

def display_checkers(game, upper_color=State.RED):
"""Display every state within the given game, from the primary one to the
last. The "game" is associate iterable of (move, state) pairs (the state is
the state of the sport once the move), for instance the one that's
came back by the perform `checkers`.

`upper_color` is that the color that its player's facet seems at the
high of the displayed boards. It will get one in all 2 values:
State.RED or State.WHITE.
"""
for _, state in game:
print_board(state, upper_color)

def play_display_checkers(red, white, upper_color=State.RED):
"""Play a game of checkers with the given players `red` and `white`,
and show each new board.
`upper_color` is that the color that seems at the highest of the displayed
boards. (color = either State.RED or State.WHITE)
See the docstring of `checkers` for a lot of data concerning players.
"""
display_checkers(checkers(red, white), upper_color)

def UserPlayer(dummy_state, error=None):
"""A player perform that uses the protocol of the `checkers` perform.
It does not show the board to the user, however if there's a mistake, it
can print it.
It asks the user for a move in a very human notation (where the squares square measure
known by numbers 1-32, rather than 1-35, and squares that square measure
separable by nine are not skipped). It returns the move within the program's
notation.
"""
if error isn't None:
print error
inp = raw_input("What's your move? Seperate the squares by dashes (-). ")
whereas True:
try:
human_squares = map(int, inp.split('-'))
move = map(human_square_to_normal, human_squares)
except ValueError:
inp = raw_input('Invalid input. attempt again: ')
except KeyError: # due to human_square_to_normal
print MovingErrors.NotASquare
inp = raw_input('Try again: ')
else:
break
come back tuple(move)


### Utilities ###

def pairs(seq):
"""Return an inventory of all of the consecutive pairs within the sequence.
every component (except the primary and therefore the last ones) seems in precisely
2 pairs: one wherever it's the primary component, and another one wherever
it's the other."""
come back [(seq[i], seq[i+1]) for i in xrange(len(seq)-1)]

def print_board(state, upper_color=State.RED):
"""Print the given state to the user as a board."""
line = []
# the primary squares ought to be the higher ones.
squares = SQUARES if upper_color == State.RED else SQUARES[::-1]
# zip(*[iterator]*n) clusters the iterator parts into n-length teams.
rows = zip(*[iter(squares)]*4)
for row in rows:
for sq. in row:
player_ch = ('x' if sq. in state.reds
else 'y' if sq. in state.whites else '.')
char = player_ch.upper() if sq. in state.kings else player_ch
# == is employed as associate XNOR operator here
if (rank(square) they two == 1) == (upper_color == State.WHITE):
line.append(' '.format(char))
else:
line.append(' '.format(char))
print ''.join(line)
line = []

###############

if __name__ == '__main__':
play_display_checkers(UserPlayer, UserPlayer, upper_color=State.WHITE)

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at drjack9650@gmail.com
Chat Now And Get Quote