I have made this pong game as a 1 player game, versus the computer. however it is impossible to beat the ai. Any ideas to make the code better would be appreciated.
import pygame
from pygame.locals import *
pointcounter = 0
class Pong(object):
def __init__(self, screensize):
self.screensize = screensize
self.centerx = int(screensize[0]*0.5)
self.centery = int(screensize[1]*0.5)
self.radius = 8
self.rect = pygame.Rect(self.centerx-self.radius,
self.centery-self.radius,
self.radius*2, self.radius*2)
self.color = (255,255,255)
self.direction = [1,1]
#speed of ball
self.speedx = 5
self.speedy = 5
self.hit_edge_left = False
self.hit_edge_right = False
def update(self, player_paddle, ai_paddle):
global pointcounter
self.centerx += self.direction[0]*self.speedx
self.centery += self.direction[1]*self.speedy
self.rect.center = (self.centerx, self.centery)
if self.rect.top <= 0:
self.direction[1] = 1
elif self.rect.bottom >= self.screensize[1]-1:
self.direction[1] = -1
if self.rect.right >= self.screensize[0]-1:
self.hit_edge_right = True
elif self.rect.left <= 0:
self.hit_edge_left = True
if self.rect.colliderect(player_paddle.rect):
self.direction[0] = -1
pointcounter += 1
if self.rect.colliderect(ai_paddle.rect):
self.direction[0] = 1
def render(self, screen):
pygame.draw.circle(screen, self.color, self.rect.center, self.radius, 0)
pygame.draw.circle(screen, (0,0,0), self.rect.center, self.radius, 1)
#creates the AI paddle
class AIPaddle(object):
def __init__(self, screensize):
self.screensize = screensize
self.centerx = 5
self.centery = int(screensize[1]*0.5)
#ai paddle dimensions
self.height = 100
self.width = 10
self.rect = pygame.Rect(0, self.centery-int(self.height*0.5), self.width, self.height)
self.color = (255,255,255)
#ai paddle speed
self.speed = 6
def update(self, pong):
if pong.rect.top < self.rect.top:
self.centery -= self.speed
elif pong.rect.bottom > self.rect.bottom:
self.centery += self.speed
self.rect.center = (self.centerx, self.centery)
def render(self, screen):
pygame.draw.rect(screen, self.color, self.rect, 0)
pygame.draw.rect(screen, (0,0,0), self.rect, 1)
#creates the player paddle
class PlayerPaddle(object):
def __init__(self, screensize):
self.screensize = screensize
self.centerx = screensize[0]-5
self.centery = int(screensize[1]*0.5)
#player paddle dimensions
self.height = 100
self.width = 10
self.rect = pygame.Rect(0, self.centery-int(self.height*0.5), self.width, self.height)
self.color = (255,255,255)
#player paddle speed
self.speed = 10
self.direction = 0
def update(self):
self.centery += self.direction*self.speed
self.rect.center = (self.centerx, self.centery)
if self.rect.top < 0:
self.rect.top = 0
if self.rect.bottom > self.screensize[1]-1:
self.rect.bottom = self.screensize[1]-1
def render(self, screen):
pygame.draw.rect(screen, self.color, self.rect, 0)
pygame.draw.rect(screen, (0,0,0), self.rect, 1)
def main():
pygame.init()
global pointcounter
screensize = (640,480)
screen = pygame.display.set_mode(screensize)
clock = pygame.time.Clock()
pong = Pong(screensize)
ai_paddle = AIPaddle(screensize)
player_paddle = PlayerPaddle(screensize)
running = True
while running:
clock.tick(64)
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if event.key == K_UP:
player_paddle.direction = -1
elif event.key == K_DOWN:
player_paddle.direction = 1
if event.type == KEYUP:
if event.key == K_UP and player_paddle.direction == -1:
player_paddle.direction = 0
elif event.key == K_DOWN and player_paddle.direction == 1:
player_paddle.direction = 0
ai_paddle.update(pong)
player_paddle.update()
pong.update(player_paddle, ai_paddle)
if pong.hit_edge_left:
print ('You Won')
running = False
elif pong.hit_edge_right:
print ('Your Score')
print (pointcounter)
running = False
screen.fill((0,0,0))
ai_paddle.render(screen)
player_paddle.render(screen)
pong.render(screen)
pygame.display.flip()
pygame.quit()
main()
1 Answer 1
The AI needs some random loss of concentration. The AIPaddle.update
method needs to start pretending that self.speed
is zero and continue to do so for a while (about a second).
To the player it will appear that the game will lose concentration every now and then and give the human player a chance to score. You could also try to make the AI look at a previous position of the ball to cause some human-like decision making lag, but I doubt it's worth it.
An alternative approach would be to simply increase the speed of the ball but not the paddles. The AI looks defensive, so it might not be able to score, and increasing the speed of the ball would give the human player a chance to score more often by intentionally positioning the paddle in advantageous ways.
This is what I would do differently
import time
import random
class AIPaddle(object):
def __init__(self, screensize):
# ...
# If time.time() > self.AI_time: the AI will work
self.AI_on_after = time.time()
# Probability of AI failing each second: 0 <= P <= 1
self.P_AI_fail = 0.1
# Duration in which AI won't do anything when it has failed
self.T_AI_fail = 1.0
self.next_fail_decision_T = time.time()
def update(self, pong):
# Each second: Decide if it's time to fail
if time.time() > self.next_fail_decision_T:
if random.random() <= self.P_AI_fail:
self.AI_on_after = time.time() + self.T_AI_fail
self.next_fail_decision_T = time.time() + 1.0
# Random loss of concentration
if time.time() > self.AI_on_afer:
speed = 0
else:
speed = self.speed
if pong.rect.top < self.rect.top:
self.centery -= speed
elif pong.rect.bottom > self.rect.bottom:
self.centery += speed