Skip to content

Instantly share code, notes, and snippets.

@jtemporal
Created April 3, 2024 21:23
Show Gist options
  • Save jtemporal/d9055d7fc855b8c0278ff00a5c5bc620 to your computer and use it in GitHub Desktop.
Save jtemporal/d9055d7fc855b8c0278ff00a5c5bc620 to your computer and use it in GitHub Desktop.
import time, math
import badger2040
import badger_os
# Global Constants
WIDTH = badger2040.WIDTH
HEIGHT = badger2040.HEIGHT
# Tic-Tac-Toe / Noughts and Crosses game
# Grid is x,y
# x is 0 to 2 (left to right)
# y is 0 to 2 (top to bottom)
def draw():
display.set_pen(15)
display.clear()
# Show grid
display.set_pen(0)
display.set_thickness(2)
display.line(103, 49, 193, 49)
display.line(103, 79, 193, 79)
display.line(133, 19, 133, 109)
display.line(163, 19, 163, 109)
# draw any played positions
for gy in range (0, 3):
for gx in range (0, 3):
if (grid[gx][gy] == 0):
# draw a cross
draw_cross(gx, gy)
elif (grid[gx][gy] == 1):
# draw a nought
draw_nought(gx, gy)
# Only show player and cursor if in game
if state == "play":
# Show current player
display.text("Player", 20, 20, 1)
if (player == 0):
draw_x (40, 50)
elif (player == 1):
draw_circle (40, 50)
draw_cursor(*cursor)
if state == "gameover":
display.text ("Game Over", 10, 10, 1)
# If there is a winner show the line
winner = is_won()
if winner >= 0:
# Draw line
display.line(*winning_line)
display.text("Winner", 15, 40, 1)
if winner == 0:
draw_x (40, 70)
if winner == 1:
draw_circle (40, 70)
# It's a draw
else:
display.text ("Draw", 10, 40, 1)
# Draw the noughts and crosses
# Top level - draw nought on grid
def draw_nought(gridx, gridy):
# Approximation of a circle using lines
# get centre of circle
(cx, cy) = grid_to_coord(gridx, gridy)
draw_circle (cx, cy)
# Lower level needs co-ords - useful for player scores etc.
def draw_circle(cx, cy, radius=10):
degree_step_size = 10
# build list of points
points = []
for i in range (0, 360, degree_step_size):
irad = math.radians(i)
this_x = int(cx + radius * math.cos(irad))
this_y = int(cy + radius * math.sin(irad))
points.append ((this_x, this_y))
for i in range(len(points)-1):
display.line (*points[i], *points[i+1])
# final back to the start
display.line(*points[len(points)-1], *points[0])
# High level - draw cross on grid
def draw_cross(gridx, gridy):
# get centre of cross
(cx, cy) = grid_to_coord(gridx, gridy)
draw_x (cx, cy)
# Lower level needs co-ords - useful for player scores etc.
def draw_x (cx, cy):
display.line (cx -10, cy -10, cx + 10, cy + 10)
display.line (cx +10, cy -10, cx - 10, cy + 10)
def draw_cursor(gridx, gridy):
# draw square
(cx, cy) = grid_to_coord(gridx, gridy)
display.rectangle (cx -4, cy -4, 8, 8)
# ------------------------------
# Helper methods
# ------------------------------
# Convert x,y position to centre of square
def grid_to_coord (gridx, gridy):
x = 118 + 30 * gridx
y = 34 + 30 * gridy
return (x, y)
# Checks for possible wins
def is_won ():
global willing_line
# start with first square on a possible line, check that has a player assigned
# then check rest of that line matches - if so then return the first square value
# which will equal the player number. If not return -1
# Check vertical lines
for col in range (0, 3):
if grid[col][0] != -1 and grid[col][0] == grid[col][1] and grid[col][1] == grid[col][2]:
winning_line[0] = 118 + col * 30
winning_line[1] = 19
winning_line[2] = 118 + col * 30
winning_line[3] = 109
return grid[col][0]
# Check horizontal lines
for line in range (0, 3):
if grid[0][line] != -1 and grid[0][line] == grid[1][line] and grid[1][line] == grid[2][line]:
winning_line[0] = 103
winning_line[1] = 34 + line * 30
winning_line[2] = 193
winning_line[3] = 34 + line * 30
return grid[0][line]
# check 2 diagnals
if grid[0][0] != -1 and grid[0][0] == grid[1][1] and grid[1][1] == grid[2][2]:
winning_line[0] = 103
winning_line[1] = 19
winning_line[2] = 193
winning_line[3] = 109
return grid[0][0]
if grid[2][0] != -1 and grid[2][0] == grid[1][1] and grid[1][1] == grid[0][2]:
winning_line[0] = 193
winning_line[1] = 19
winning_line[2] = 103
winning_line[3] = 109
return grid[2][0]
# reach here no match
return -1
# ------------------------------
# Program setup
# ------------------------------
# Create a new Badger and set it to update NORMAL
display = badger2040.Badger2040()
display.led(128)
# ------------------------------
# Main program
# ------------------------------
state = "play"
# Player 0 = crosses (goes first on first game)
# Player 1 = noughts
player = 0
cursor = [0,0]
# number of goes played - when reach 9 know that grid is full
played = 0
# Grid is x y (cols then rows) - so array does not look the same
# -1 = none
# 0 = player 0
# 1 = player 1
grid = [
[-1,-1, -1],
[-1,-1,-1],
[-1,-1,-1]]
# winning_line used as a global to determine where to draw line when someone wins
winning_line = [0,0,0,0]
# Display initial screen
draw()
display.update()
while (1):
# wait for action (uses loop)
while (1):
if state == "play":
display.set_update_speed(badger2040.UPDATE_TURBO)
if display.pressed(badger2040.BUTTON_A):
if cursor[0] > 0:
cursor[0] -= 1
break
if display.pressed(badger2040.BUTTON_C):
if cursor[0] < 2:
cursor[0] += 1
break
if display.pressed(badger2040.BUTTON_UP):
if cursor[1] > 0:
cursor[1] -= 1
break
if display.pressed(badger2040.BUTTON_DOWN):
if cursor[1] < 2:
cursor[1] += 1
break
if display.pressed(badger2040.BUTTON_B):
display.set_update_speed(badger2040.UPDATE_MEDIUM)
# If empty then place the mark
# If not empty then ignore button press
if (grid[cursor[0]][cursor[1]] == -1):
grid[cursor[0]][cursor[1]] = player
played += 1
# Swap player and reset cursor
if player == 0:
player = 1
else:
player = 0
# return cursor to top left
cursor[0] = 0
cursor[1] = 0
break
# Otherwise press B to start game
else:
if display.pressed(badger2040.BUTTON_B):
state == "play"
if is_won() >= 0 or played >= 9:
state = "gameover"
draw()
display.update()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment