Skip to content

Instantly share code, notes, and snippets.

@mobyjames
Created December 29, 2018 18:52
Show Gist options
  • Save mobyjames/0415ad667caf0d92491a58aa54756114 to your computer and use it in GitHub Desktop.
Save mobyjames/0415ad667caf0d92491a58aa54756114 to your computer and use it in GitHub Desktop.
Trellis Sweeper
# Mine Puzzle Game
# Created by James Jacoby, December 2018
#
# A mine clearing game loosely based on minesweeper
#
# HOW TO PLAY:
#
# Press a key to clear a space
# If it's a mine, you lose
# Otherwise, the adjacent spaces will change color to indicate the number
# of surrounding mines neaby. If it doesn't change- it's a mine for sure!
# Try to clear all the non-mine spaces!
# Thump to reset board
#
# 0: mint
# 1: dark green
# 2: dark blue
# 3: purple
# 4: dark red
# 5 or more: medium red
#
# IDEAS TO TRY:
#
# Change color codes to suite your eyes
# Add more risk levels if you feel like memorizing more colors
# Change difficulty level by adjusting percentage of mines
# Add other fun animations for victory, failure or resetting the board
# Add a way to flag a mine
#
import time
import math
import random
import adafruit_trellism4
import adafruit_adxl34x
import board
import busio
trellis = adafruit_trellism4.TrellisM4Express()
i2c = busio.I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA)
accelerometer = adafruit_adxl34x.ADXL345(i2c)
accelerometer.enable_motion_detection(threshold=250)
UNKNOWN = 0x000000
MINE = 0xFF0000
CLEAR = 0x315612
ONE = 0x001100
TWO = 0x000011
THREE = 0xDD00AA
FOUR = 0x110000
FIVE = 0xAA0000
STATE_PLAY = 0
STATE_FAIL = 1
STATE_VICTORY = 2
w = 8
h = 4
percent = 0.2
mines = [0 for _ in range(32)]
key_state = [0 for _ in range(32)]
risks = [CLEAR, ONE, TWO, THREE, FOUR, FIVE, FIVE, FIVE, FIVE]
total_mines = 0
game_state = STATE_PLAY
current_press = set()
victory_flash = True
def setPixel(index, color):
global key_state
key_state[index] = color
y = math.floor(index / 8)
x = index % 8
trellis.pixels[x, y] = color
def reset():
global total_mines
global game_state
global mines
total_mines = 0
for i in range(8):
sweep(i)
time.sleep(0.05)
for i in range(32):
setPixel(i, UNKNOWN)
mines[i] = random.random() <= percent
if mines[i]:
total_mines += 1
game_state = STATE_PLAY
def mineAt(x, y):
if x < 0 or x >= w:
return False
elif y < 0 or y >= h:
return False
else:
index = y * 8 + x
return mines[index]
def showRiskForSpace(x, y):
if x < 0 or x >= w or y < 0 or y >= h:
return
index = y * 8 + x
if mines[index]: # don't show clue for for-sure mines
return
count = 0
if mineAt(x-1, y-1):
count +=1
if mineAt(x, y-1):
count +=1
if mineAt(x+1, y-1):
count +=1
if mineAt(x-1, y):
count +=1
if mineAt(x+1, y):
count +=1
if mineAt(x-1, y+1):
count +=1
if mineAt(x, y+1):
count +=1
if mineAt(x+1, y+1):
count +=1
if count == 0: # keep going to clear obvious zero-risk spaces
clearSpace(x, y)
color = risks[count]
setPixel(index, color)
def clearSpace(x, y):
index = y * 8 + x
current = key_state[index]
if current != UNKNOWN: # can't press spaces with known values
return
elif mines[index]: # you dead
explodeTheBoard()
else:
setPixel(index, CLEAR)
showRiskForSpace(x-1, y-1)
showRiskForSpace(x, y-1)
showRiskForSpace(x+1, y-1)
showRiskForSpace(x-1, y)
showRiskForSpace(x+1, y)
showRiskForSpace(x-1, y+1)
showRiskForSpace(x, y+1)
showRiskForSpace(x+1, y+1)
checkVictory()
def explodeTheBoard():
for i in range(32):
setPixel(i, MINE)
def showVictory(flashOn):
for i in range(32):
if mines[i]:
if flashOn:
setPixel(i, MINE)
else:
setPixel(i, 0)
def checkVictory():
global total_mines
global game_state
remaining = 0
for i in range(32):
if key_state[i] == UNKNOWN:
remaining += 1
if remaining == total_mines:
game_state = STATE_VICTORY
showVictory(True)
def sweep(col):
for i in range(32):
x = i % 8
if x == col:
setPixel(i, MINE)
elif x < col:
setPixel(i, 0)
reset()
while True:
pressed = set(trellis.pressed_keys)
if game_state == STATE_PLAY:
for press in pressed:
if press:
x, y = press
index = (y * 8) + x
clearSpace(x, y)
elif game_state == STATE_VICTORY:
showVictory(victory_flash)
victory_flash = not victory_flash
if accelerometer.events['motion'] == True:
reset()
time.sleep(0.08)
current_press = pressed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment