Lets play some Pong! 

![pong](http://gifimage.net/wp-content/uploads/2017/08/pong-gif-3.gif)

For those who don't know what Pong is, it is a simple arcade game where two players can move their paddles to hit a ball towards the opponent's side of the screen, gaining a point for each opponent's miss. You can read more about it [here](https://en.wikipedia.org/wiki/Pong).

___

# Task:

You must finish the `Pong` class. It has a constructor which accepts the `maximum score` a player can get throughout the game, and a method called `play`. This method determines whether the current player hit the ball or not, i.e. if the paddle is at the sufficient height to hit it back. There're 4 possible outcomes: player successfully hits the ball back, player misses the ball, player misses the ball **and his opponent reaches the maximum score winning the game**, either player tries to hit a ball despite the game being over. You can see the input and output description in detail below.

### "Play" method input:

* ball position - The Y coordinate of the ball
* player position - The Y coordinate of the centre(!) of the current player's paddle

### "Play" method output:

One of the following strings:

* `"Player X has hit the ball!"` - If the ball "hits" the paddle
* `"Player X has missed the ball!"` - If the ball is above/below the paddle
* `"Player X has won the game!"` - If one of the players has reached the maximum score
* `"Game Over!"` - If the game has ended but either player still hits the ball

### Important notes:

* Players take turns hitting the ball, always starting the game with the Player 1.
* The paddles are `7` pixels in height.
* The ball is `1` pixel in height.

___

## Example

Source: codewars | Difficulty: EASY
Tags: Fundamentals

Game theory

Starter code: def __init__(self, max_score):
	

Solutions:
from itertools import cycle

class Pong:

	def __init__(self, max_score):
		self.max_score = max_score
		self.scores = {1: 0, 2: 0}
		self.players = cycle((1, 2))

	def game_over(self):
		return any((score >= self.max_score for score in list(self.scores.values())))

	def play(self, ball_pos, player_pos):
		if self.game_over():
			return 'Game Over!'
		player = next(self.players)
		if abs(ball_pos - player_pos) <= 3:
			return 'Player {} has hit the ball!'.format(player)
		else:
			self.scores[player] += 1
			if self.scores[player] == self.max_score:
				return 'Player {} has won the game!'.format(next(self.players))
			else:
				return 'Player {} has missed the ball!'.format(player)


class Pong:

	def __init__(self, max_score):
		self.max_score = max_score
		self.score = [0, 0]
		self.player = 0

	def play(self, ball_pos, player_pos):
		if self.max_score in self.score:
			return 'Game Over!'
		if player_pos - 3 <= ball_pos <= player_pos + 3:
			self.player ^= 1
			return 'Player {} has hit the ball!'.format((self.player ^ 1) + 1)
		self.player ^= 1
		self.score[self.player] += 1
		if self.score[self.player] == self.max_score:
			return 'Player {} has won the game!'.format(self.player + 1)
		return 'Player {} has missed the ball!'.format((self.player ^ 1) + 1)


class Pong:

	def __init__(self, max_score):
		self.max_score = max_score
		self.next = 1
		self.score = {1: 0, 2: 0}

	def play(self, ball, paddle):
		if max(self.score.values()) >= self.max_score:
			return 'Game Over!'
		(current, self.next) = (self.next, 3 - self.next)
		if paddle - 4 < ball < paddle + 4:
			return f'Player {current} has hit the ball!'
		else:
			self.score[current] += 1
			if self.score[current] == self.max_score:
				return f'Player {self.next} has won the game!'
			return f'Player {current} has missed the ball!'


class Pong:

	def __init__(self, win):
		self.win = win
		self.turn = -1
		self.scores = [0, 0]

	def play(self, ball, player):
		if max(self.scores) == self.win:
			return 'Game Over!'
		self.turn = (self.turn + 1) % 2
		if abs(ball - player) < 4:
			return 'Player ' + str(self.turn + 1) + ' has hit the ball!'
		self.scores[(self.turn + 1) % 2] += 1
		return 'Player ' + (str(1 if self.turn else 2) + ' has won the game!' if max(self.scores) == self.win else str(self.turn + 1) + ' has missed the ball!')


class Pong:

	def __init__(self, max_score):
		self.max_score = max_score
		self.scores = [0, 0]
		self.turn = 0

	def play(self, ball_pos, player_pos):
		try:
			if max(self.scores) == self.max_score:
				return 'Game Over!'
			if abs(ball_pos - player_pos) <= 3:
				return f'Player {self.turn + 1} has hit the ball!'
			self.scores[1 - self.turn] += 1
			if self.scores[1 - self.turn] == self.max_score:
				return f'Player {2 - self.turn} has won the game!'
			else:
				return f'Player {self.turn + 1} has missed the ball!'
		finally:
			self.turn = (self.turn + 1) % 2


class Pong:

	def __init__(self, m):
		(self.m, self.w) = (m, [0, 0])
		self.o = self.p = 0

	def play(self, b, a):
		if self.o:
			return 'Game Over!'
		self.p += 1
		if abs(b - a) < 3.5:
			return 'Player %d has hit the ball!' % (2 - self.p % 2)
		self.w[self.p % 2] += 1
		if any((self.m <= x for x in self.w)):
			self.o = 1
		return 'Player %d has %s!' % (2 - (self.o + self.p) % 2, ('missed the ball', 'won the game')[self.o])


PADDLE_SIZE = 7

class Pong:

	def __init__(self, max_score):
		self.max_score = max_score
		self.player_scores = {0: 0, 1: 0}
		self.current_player = 0
		self.game_state = None

	def play(self, ball_pos, player_pos):
		if self.game_state is not None:
			return self.game_state
		paddle_range = (player_pos - PADDLE_SIZE / 2, player_pos + PADDLE_SIZE / 2)
		if ball_pos > max(paddle_range) or ball_pos < min(paddle_range):
			self.player_scores[self.current_player ^ 1] += 1
			if self.player_scores[self.current_player ^ 1] >= self.max_score:
				self.game_state = 'Game Over!'
				string = 'Player {} has won the game!'.format(self.current_player ^ 1 + 1)
			else:
				string = 'Player {} has missed the ball!'.format(self.current_player + 1)
		else:
			string = 'Player {} has hit the ball!'.format(self.current_player + 1)
		self.switch_player()
		return string

	def switch_player(self):
		self.current_player ^= 1


class Pong:

	def __init__(self, max_score):
		self.max_score = max_score
		self.player = [0, 0]
		self.index = 0
		self.win = False

	def play(self, ball_pos, player_pos):
		if self.win:
			return 'Game Over!'
		self.index += 1
		if abs(ball_pos - player_pos) > 3:
			self.player[self.index % 2] += 1
			if self.player[self.index % 2] >= self.max_score:
				self.win = True
				return 'Player 2 has won the game!' if self.index % 2 == 1 else 'Player 1 has won the game!'
			return 'Player 1 has missed the ball!' if (self.index - 1) % 2 == 0 else 'Player 2 has missed the ball!'
		return 'Player 1 has hit the ball!' if (self.index - 1) % 2 == 0 else 'Player 2 has hit the ball!'


class Pong:

	def __init__(self, max_score):
		self.max_score = max_score
		self.i = -1
		self.event = 'Player {} has {} the ball!'
		self.score = {1: 0, 2: 0}

	def play(self, ball, player):
		if self.event:
			self.i += 1
		if not self.event:
			return 'Game Over!'
		hit = abs(player - ball)
		if hit > 3:
			winer = (1, 2)[not self.i % 2]
			self.score[winer] += 1
			if self.score[winer] == self.max_score:
				self.event = None
				return f'Player {winer} has won the game!'
		return self.event.format((1, 2)[self.i % 2], ('hit', 'missed')[hit > 3])