2
\$\begingroup\$

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()
\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.