Python Turtle based Pong game
First - You have numeric constants scattered all over the code.

Try to change the board width to 500 and you will immediately understand. Numeric constants like board width shall appear exactly once when assigned to a constant which is used throughout the code lateron. This applies to board size, pong size and player size.

define

board_width = 600
board_height = 600


and use it to draw the border like

for side in range(2):
    border_pen.fd(board_width)
    border_pen.lt(90)
    border_pen.fd(board_height)
    border_pen.lt(90)


Second - you have calculated dependent numeric constants

If constants depend on others you shall not evaluate these. Try to change the bong size and you will have a hell of a work to find all depending values. You are hiding the dependencies and again make your code unmaintainable. All constants that have dependencies shall be initialized not by numeric values, but by expressions using the first class constants.

replace

score_pen.setposition(-290, 310)


with

score_pen.setposition(-board_width/2 + 10, board_height/2 + 10)


Third - structure your code

Whenever you feel you need a comment to explain what a block of code is doing you probably found a function (or a class). if you chose nice function names comments may be obsolete. Also you have less name collisions on local variables leading to better names.

# set up border
border_pen = turtle.Turtle()
#[...]
border_pen.hideturtle()


should be

def set_up_border():
    pen = turtle.Turtle()
    #[...]
    pen.hideturtle()


also

#Draw score
score_pen = turtle.Turtle()
#[...]
score_pen.hideturtle()


should be

def create_score():
    pen = turtle.Turtle()
    #[...]
    pen.hideturtle()
    return pen

score_pen = create_score()


Fourth - reuse code and do not repeat yourself

When you now look at your new functions create_score() and create_timer() you will notice they are nearly identical. They only differ in position and the string displayed. But they share font, color and so on. So we add some parameters and unify these 

def create_text(pos, txt):
    pen = turtle.Turtle()
    pen.speed(0)
    pen.color("white")
    pen.penup()
    pen.setposition(pos)
    pen.write(txt, False, align="left", font= ("Arial", 14, "normal"))
    pen.hideturtle()
    return pen


which we use like

score_pen = create_text(score_position, "Score %s" % score)
time_pen = create_text(time_position, "Time %s" % time)


the same way we can unify player and AIplayer. If you want to change player size there is now a single line of code to change. Actually these players, text fields and the bong should be classes but for now we leave it like that.

All the points up to now are valid for any programming language and absolutely important. Maintainability, readability and testability count.

Some algorithmic issues

Bouncing

An object bouncing on another one may not penetrate it. so it is not sufficient to reverse the direction when a collision is detected, but you also have to exit the foreign object immediately. this is done by "mirroring" the entered object to the outside again. So instead of

#move pong ball
pong.sety(pong.ycor() +pong.dy)
#[...]

#check for bounce and redirect it
if pong.ycor() &lt; -300:
    pong.dy *= -1
#[...]


we do not draw immediately but fix penetration before updating the screen

#move pong ball
y = pong.ycor() + pong.dy
#[...]

#check for bounce and redirect it
if y &lt; -board_height/2:
    pong.dy *= -1
    y = -board_height - y
#[...]

pong.sety(y)
#[...]


BTW: Game over is not recognised if the AI player would miss the bong.

Tower running

Setting x and y coordinates ii separate calls where the pen is down results in the pong performing tower running instead of smooth angular movement.

AIplayerspeed

Your AI player does not move with its own speed but with bong speed as it directly takes bong y position. AIplayerspeed acts as an offset to bong y position. This should be fixed to


either rename and calculated this offset from bong and player size to be center aligned
or implemented as a max speed to approach bong y position (again centeraligned)


math.sqrt

square root is an expensive function which in game design is avoided wherever possible. In your case you coud simply square the max distance

distance = math.sqrt(math.pow(t1.xcor()-    t2.xcor(),2)+math.pow(t1.ycor()-t2.ycor(),2))
if distance &lt; 20:
    #[...]


becomes

sq_distance = math.pow(t1.xcor() - t2.xcor(), 2) + math.pow(t1.ycor() - t2.ycor(), 2)
if distance &lt; math.pow(20, 2):
    #[...]