Jic-Jac-Joe

As the name suggests, this is a computer version of the well-known game Tic-Tac-Toe. This version supports a computer player, but it is not the smartest algorithm and can lose. In this setup, the computer plays ‘O’ and starts, the player plays ‘X’.
Win detection is fully implemented.

Controls

  • The 3×3-field is projected on the numpad
    • So 7 sets your piece in the upper left corner
    • And 3 puts it in the lower right corner
  • Escape resets the game

Draw Computer Wins Computer Wins Again


# Python 2.7.7 Code
# Pygame 1.9.1 (for Python 2.7.7)
# Jonathan Frech  9th of July, 2015
#         edited 10th of July, 2015

# importing needed modules
import pygame, sys, time, math, os, random

""" CLASSES """
# dummy class for global variables
class dummy():
	pass

""" FUNCTIONS """
# gets the mouse position
def getMousePos():
	p = pygame.mouse.get_pos()
	return [p[0], p[1]]

# validates color integer
# extra feature: _min and _max implementation
def colorValid(_color, _min = 0, _max = 255):
	newColor = math.fabs(_color)
	n = _max - _min
	if newColor > n:
		if int(newColor / n) % 2 == 0:
			newColor = newColor % n
		else:
			newColor = n - (newColor % n)
	
	return int(newColor) + _min

# gets the position on a circle
# circle center                           : '_pos'
# circle radius                           : '_radius'
# angle from center to point on the circle: '_angle'
def getCirclePos(_pos, _radius, _angle):
	return [
				_pos[0] + _radius * math.cos(math.radians(_angle)),
				_pos[1] + _radius * math.sin(math.radians(_angle))
			]

# returns an integer version of given positon
def intpos(_pos):
	return [int(_pos[0]), int(_pos[1])]

# basic vector functions
def vecConvert(p1, p2):
	return [p2[0] - p1[0], p2[1] - p1[1]]
def vecLen(vec):
	return math.sqrt( (vec[0]**2) + (vec[1]**2) )
def vecMultiply(vec, n):
	return [vec[0] * n, vec[1] * n]
def vecGetPoint(vec, point):
	return [point[0] + vec[0], point[1] + vec[1]]
def vecAdd(vec1, vec2):
	return [vec1[0] + vec2[0], vec1[1] + vec2[1]]

# calculates distance between given positions
def posDistance(p1, p2):
	return math.sqrt( (p2[0] - p1[0])**2 + (p2[1] - p1[1])**2 )

# quits the program
def quit():
	sys.exit()

# sets a piece
def set(_n):
	if not main.GAMEOVER and main.FIELD[_n] == -1:
		main.FIELD[_n] = main.CURRENT
		if main.CURRENT == 0:
			main.CURRENT = 1
		else:
			main.CURRENT = 0

# computer move
def com():
	wins = [
		[0, 1, 2],
		[3, 4, 5],
		[6, 7, 8],
		[0, 3, 6],
		[1, 4, 7],
		[2, 5, 8],
		[0, 4, 8],
		[2, 4, 6]
	]
	
	s = -1
	
	if s == -1:
		# win
		for _ in wins:
			if main.FIELD[_[1]] == main.CURRENT and main.FIELD[_[0]] == main.FIELD[_[1]] and main.FIELD[_[2]] == -1:
				s = _[2];break
			elif main.FIELD[_[2]] == main.CURRENT and main.FIELD[_[1]] == main.FIELD[_[2]] and main.FIELD[_[0]] == -1:
				s = _[0];break
			elif main.FIELD[_[0]] == main.CURRENT and main.FIELD[_[2]] == main.FIELD[_[0]] and main.FIELD[_[1]] == -1:
				s = _[1];break
	
	if s == -1:
		# stop other player
		for _ in wins:
			if main.FIELD[_[1]] != -1 and main.FIELD[_[1]] != main.CURRENT and main.FIELD[_[0]] == main.FIELD[_[1]] and main.FIELD[_[2]] == -1:
				s = _[2];break
			elif main.FIELD[_[2]] != -1 and main.FIELD[_[2]] != main.CURRENT and main.FIELD[_[1]] == main.FIELD[_[2]] and main.FIELD[_[0]] == -1:
				s = _[0];break
			elif main.FIELD[_[0]] != -1 and main.FIELD[_[0]] != main.CURRENT and main.FIELD[_[2]] == main.FIELD[_[0]] and main.FIELD[_[1]] == -1:
				s = _[1];break
	
	if s == -1:
		# try to put in corners or center
		available = []
		for _ in [0, 2, 4, 6, 8]:
			if main.FIELD[_] == -1:
				available.append(_)
		if len(available) > 0:
			s = available[random.randint(0, len(available) - 1)]
	
	if s == -1:
		# do something...
		available = []
		for _ in range(0, len(main.FIELD) - 1):
			if main.FIELD[_] == -1:
				available.append(_)
		if len(available) > 0:
			s = available[random.randint(0, len(available) - 1)]
	
	if s != -1:
		set(s)
	
# checks for win
def check():
	wins = [
		[0, 1, 2],
		[3, 4, 5],
		[6, 7, 8],
		[0, 3, 6],
		[1, 4, 7],
		[2, 5, 8],
		[0, 4, 8],
		[2, 4, 6]
	]
	
	full = True
	
	for _ in wins:
		if main.FIELD[_[0]] == -1 or main.FIELD[_[1]] == -1 or main.FIELD[_[2]] == -1:
			full = False
		elif main.FIELD[_[0]] == main.FIELD[_[1]] and main.FIELD[_[1]] == main.FIELD[_[2]]:
			main.GAMEOVER = True
			main.WINNER = main.FIELD[_[0]]
			main.WIN = _
			break
	
	if full:
		main.GAMEOVER = True
	
""" TICK; RENDER """
# tick function
def tick():
	# handle events
	for event in pygame.event.get():
		# quit
		if event.type == pygame.QUIT:
				quit()
		
		# keyup
		if event.type == pygame.KEYUP:
			# handle 'main.KEYSDOWN'
			if event.key in main.KEYSDOWN:
				main.KEYSDOWN.remove(event.key)
			
			if event.key == pygame.K_ESCAPE:
				reset()
			
			if not main.CURRENT in main.COM:
				if event.key == pygame.K_KP1:
					set(6)
				elif event.key == pygame.K_KP2:
					set(7)
				elif event.key == pygame.K_KP3:
					set(8)
				elif event.key == pygame.K_KP4:
					set(3)
				elif event.key == pygame.K_KP5:
					set(4)
				elif event.key == pygame.K_KP6:
					set(5)
				elif event.key == pygame.K_KP7:
					set(0)
				elif event.key == pygame.K_KP8:
					set(1)
				elif event.key == pygame.K_KP9:
					set(2)
		
		# keydown
		if event.type == pygame.KEYDOWN:
			# handle 'main.KEYSDOWN'
			if event.key not in main.KEYSDOWN:
				main.KEYSDOWN.append(event.key)
	
	check()
	if main.CURRENT in main.COM:
		main.COMDELAY -= 1
		if main.COMDELAY <= 0:
			main.COMDELAY = main.MAXCOMDELAY
			com()
	check()

# render function
def render():
	# fill
	main.SURF.fill(main.COLOR)
	
	for _ in range(0, 9):
		x, y = (main.FWIDTH+main.GAP) * (_ % 3) + main.GAP, (main.FHEIGHT+main.GAP) * (_ / 3) + main.GAP
		
		if main.FIELD[_] == -1:
			pygame.draw.rect(main.SURF, (50, 50, 50), [x, y, main.FWIDTH, main.FHEIGHT])
		else:
			pygame.draw.rect(main.SURF, (20, 20, 20), [x, y, main.FWIDTH, main.FHEIGHT])
		
		if main.WIN:
			if _ in main.WIN:
				pygame.draw.rect(main.SURF, (70, 20, 20), [x, y, main.FWIDTH, main.FHEIGHT])
		
		if main.FIELD[_] == 0:
			pygame.draw.rect(main.SURF, (0, 0, 255), [x, y, main.FWIDTH, main.FHEIGHT], 1)
		elif main.FIELD[_] == 1:
			pygame.draw.line(main.SURF, (0, 0, 255), [x, y], [x + main.FWIDTH - 1, y + main.FHEIGHT - 1])
			pygame.draw.line(main.SURF, (0, 0, 255), [x, y + main.FHEIGHT - 1], [x + main.FWIDTH - 1, y])
	
	# blit and flip
	main.SCREEN.blit(pygame.transform.scale(main.SURF, main.SSIZE), [0, 0])
	pygame.display.flip()

""" INIT; RESET """
# resets the game
def reset():
	main.FIELD = [
		-1, -1, -1,
		-1, -1, -1,
		-1, -1, -1
	]
	main.CURRENT = 0
	
	main.GAMEOVER = False
	main.WINNER = -1
	main.WIN = None

# initialize program
def init():
	main.GAP = 1
	
	main.FWIDTH, main.FHEIGHT = 10, 10
	main.FSIZE = [main.FWIDTH, main.FHEIGHT]
	
	main.WIDTH, main.HEIGHT = (main.FWIDTH+main.GAP)*3+main.GAP, (main.FHEIGHT+main.GAP)*3+main.GAP
	main.SIZE = [main.WIDTH, main.HEIGHT]
	main.SURF = pygame.Surface(main.SIZE)
	
	main.SCALE = 10
	main.SWIDTH, main.SHEIGHT = main.WIDTH * main.SCALE, main.HEIGHT * main.SCALE
	main.SSIZE = [main.SWIDTH, main.SHEIGHT]
	main.SCREEN = pygame.display.set_mode(main.SSIZE)
	
	main.CAPTION = "Jic-Jac-Joe"
	main.COLOR = (0, 0, 0)
	main.TICKS = 0
	main.KEYSDOWN = []
	
	reset()
	
	main.COM = [0]
	main.MAXCOMDELAY = 10
	main.COMDELAY = main.MAXCOMDELAY
	
	# functions
	pygame.display.set_caption(main.CAPTION)

""" RUN """
# run function (uses tick() and render())
def run():
	ticksPerSecond = 60
	lastTime = time.time() * 1000000000
	nsPerTick =  1000000000.0 / float(ticksPerSecond)
	
	ticks = 0
	frames = 0
	
	lastTimer = time.time() * 1000
	delta = 0.0
	
	while True:
		now = time.time() * 1000000000
		delta += float(now - lastTime) / float(nsPerTick)
		lastTime = now
		shouldRender = False
				
		while delta >= 1:
			ticks += 1
			main.TICKS += 1
			tick()
			delta -= 1
			shouldRender = True
		
		if shouldRender:
			frames += 1
			render()
		
		if time.time() * 1000 - lastTimer >= 1000:
			lastTimer += 1000
			
			# debug
			# print("Frames: " + str(frames) + ", ticks: " + str(ticks))
			
			frames = 0
			ticks = 0

# main variable
main = dummy()
init()

# start program
run()
Advertisements

2 thoughts on “Jic-Jac-Joe

  1. Pingback: Jonnect Jour | J-Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s