#RaspberryPi python games for #Pimoroni Unicorn HAT HD

By | November 7, 2017

There are some nice demos that come with Pimoroni Unicorn HAT HD library but if you want something more fun you can have interactive applications.
How about GAMES ?
I stumbled over a thread Unicorn HAT Demo Ideas where someone was asking foe ideas of demos for the standard Unicorn HAT.
Two of the best demos delivered there by two users (Thank you guys !!!):
evilunix: CPU vs CPU game of pong with rainbow colours
Timcw (Tim Mulford): Battleships !!!

I ended up adapting them for the bigger matrix of the Unicorn HAT HD

CPU vs CPU game of pong with rainbow colours

Duble-Click to get the whole code.

# Adapted to Unicorn HD by George Voina
# blog.voina.org

import unicornhathd as UH
import time
import random
import colorsys as col

#UH.brightness(1) # max brightness :D

SPEED = 0.1

# convert hex to rgb tuple
def hex_to_rgb(value):
	value = value.lstrip('#')
	lv = len(value)
	return tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))


class Player:

	def __init__(self, hue):
		self.hue = hue
 
	direction_x = 0 # 1 = up, 2 = down
	y = 0 # position of topmost pixel

	def spawn(self):
		self.y = random.randint(0,13)

	def think(self, ball):

		# change colour
		if self.hue < 360:
			self.hue = self.hue + 1
		else:
			self.hue = 0

        	rand = random.randint(0,19)
        	if(rand == 13):
                	derp = 1
        	else:
                	derp = 0

        	if ball.y > self.y + 1 and self.y < 13:
                	# ball is below player center - move down
                	if derp == 0:
                        	self.y = self.y + 1


        	if ball.y < self.y + 1 and self.y > 0:
                	# ball is above player center - move up
                	if derp == 0:
                        	self.y = self.y - 1

		

class Ball:
    
	direction_x = 0 # 1 = up, 2 = down
    	direction_y = 0 # 1 = left, 2 = right
    
    	x = 0
    	y = 0
    
    	colour = hex_to_rgb('ffffff')
    
    	def spawn(self):

		print 'spawning ball...'

        	# ball starting directions
        	self.direction_x = random.randint(1,2)
		self.direction_y = random.randint(1,2)
	
		# ball starting position
		self.x = random.randint(3,4)
		self.y = random.randint(3,4)	


player1 = Player(0)
player2 = Player(90)
ball = Ball()


def update():
	global ball, player1, player2

	player1.think(ball)
	player2.think(ball)
    
    	# check if ball hit upper or lower wall
    	if ball.y == 0:
        	#change direction
        	ball.direction_y = 2 # down
    	if ball.y == 15:
        	# change direction
        	ball.direction_y = 1 # up
    
    	if ball.direction_y == 2: # down
        	# move 1 cell down
        	ball.y = ball.y + 1
    	elif ball.direction_y == 1: #up
        	# move 1 cell up
        	ball.y = ball.y - 1
        
    
    	if ball.direction_x == 1: # moving left
		
		ball.x = ball.x - 1
		
        	if ball.x == 0:
           		# check for collision
			if ball.y >=  player1.y and ball.y <= player1.y + 3:
				print 'SAVE!'
				#change direction
				ball.direction_x = 2
				ball.x = ball.x + 1
			else: 
           			# GOAL!
				print 'GOAL!'
				goal()
				ball.spawn()
					

    	if ball.direction_x == 2: # moving right

		ball.x = ball.x + 1

        	if ball.x == 15:
            		# check for collision
			if ball.y >= player2.y and ball.y <= player2.y + 3:
				print 'SAVE!'
				# change direction
				ball.direction_x = 1
				ball.x = ball.x - 2
			else: 	
				# GOAL!
				goal()
				print 'GOAL!'
            			ball.spawn()

def goal():
	global ball

	draw()
	time.sleep(SPEED)

	set_pixel(ball.x, ball.y, hex_to_rgb('000000'))
	UH.show()
	time.sleep(SPEED)
	
	set_pixel(ball.x, ball.y, ball.colour)
	UH.show()
	time.sleep(SPEED)

	set_pixel(ball.x, ball.y, hex_to_rgb('000000'))
	UH.show()
	time.sleep(SPEED)


        set_pixel(ball.x, ball.y, ball.colour)
        UH.show()
        time.sleep(SPEED)
	
	

def set_pixel(x, y, colour):
	UH.set_pixel(x, y, colour[0], colour[1], colour[2])

def fill_hex(colour):
	rgb = hex_to_rgb(colour)
	for x in range(0, 16):
		for y in range(0, 16):
			set_pixel(x, y, rgb)
	UH.show()


def set_pixel_hue(x, y, h):

	hfloat = h / 255.0	

	rgb = col.hsv_to_rgb(hfloat, 0.5, 1.0)
	r = int(rgb[0] * 255)
	g = int(rgb[1] * 255)
	b = int(rgb[2] * 255)
	UH.set_pixel(x, y, r, g, b)  


def draw():
    	global ball, player1, player2, BG_COLOUR
    	UH.off()

	#fill_hex(BG_COLOUR)

	# draw ball
    	set_pixel(ball.x, ball.y, ball.colour)

	# draw player1
	set_pixel_hue(0, player1.y, player1.hue)
	set_pixel_hue(0, player1.y + 1, player1.hue)
	set_pixel_hue(0, player1.y + 2, player1.hue)

    	# draw player2
        set_pixel_hue(15, player2.y, player2.hue)
        set_pixel_hue(15, player2.y + 1, player2.hue)
        set_pixel_hue(15, player2.y + 2, player2.hue)
	

    	UH.show()


player1.spawn()
player2.spawn()    
ball.spawn()
draw()

while True:
	
    	time.sleep(SPEED)
    	update()
    	draw()

Battleships:

Duble-Click to get the whole code.

# Battleships Unicorn Hat display
# Author: Tim Mulford
# Date: 28/08/2015
# Version: 0.5

# Changes:
# I have update the code to make the game area a class with methods for the game. 

# Adapted to Unicorn HD by George Voina
# blog.voina.org

import unicornhathd as unicorn
import time, random

# initialise Unicornhat board
# Unless you are using a difusser keep brightness low
#unicorn.brightness(0.1)
unicorn.rotation(180)

# ocean stores the information about the game area and the methods required to
# interact with it

class ocean:

    ships = 0
    ammo = 0
    water = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
             [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
             [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
             [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
             [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
             [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
             [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
	     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
             [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
	     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
	     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
	     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
             [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
	     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
	     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
	     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]

    # Reset the game board
    def reset(self):

        self.water = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
		      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]
    
    # Display the current board state on the Unicorn hat
    def display_water(self):

        for y in range(16):
            for x in range(16):

                if self.water[y][x] == 0 or self.water[y][x] == 1:
                    
                    unicorn.set_pixel(x,y,79,106,226)

                elif self.water[y][x] == 2:
                    
                    unicorn.set_pixel(x,y,0,0,0)

                elif self.water[y][x] == 3:
                    
                    unicorn.set_pixel(x,y,255,0,0)

        unicorn.show()

    # Set every light on the board to the set colour
    def flood_colour(self,red,green,blue):

        for x in range(16):
            for y in range(16):

                unicorn.set_pixel(x,y,red,green,blue)

        unicorn.show()

    # Animation for when a shot is a hit
    def hit_flash(self,count):
        
        for repeat in range(count):
                    
            self.flood_colour(255,0,0)
            time.sleep(0.2)

            self.flood_colour(255,255,0)
            time.sleep(0.2)
            
        self.flood_colour(0,0,255)
        time.sleep(0.5)

    # Animation for when a shot is a miss
    def miss_flash(self):

        self.flood_colour(255,255,255)
        time.sleep(0.3)
        
        for a in range(0,255,10):
            
            self.flood_colour(0,0,a)

    # Animation for targetting using passed co-ordinates
    def target_flash(self,x,y):

        for a in range(16):
            
            unicorn.set_pixel(x,a,0,200,0)
            unicorn.show()
            time.sleep(0.05)
                 
        for a in range(16):
            
            unicorn.set_pixel(a,y,0,200,0)
            unicorn.show()
            time.sleep(0.05)

        time.sleep(1)
        
        for a in range(0,255,10):
            
            unicorn.set_pixel(x,y,a,a,a)
            unicorn.show()
            time.sleep(0.01)
            
        for a in range(0,255,10):
            
            unicorn.set_pixel(x,y,255-a,255-a,255-a)
            unicorn.show()
            time.sleep(0.01)

    # Animation for when the game is lost
    def defeated(self):
        
        for fade in range(0,255):
            for y in range(16):
                for x in range(16):
                    
                    unicorn.set_pixel(x,y,255,255-fade,255-fade)

            unicorn.show()
            time.sleep(0.01)

    # Animation for when the game is won
    def victory(self):

        for fade in range(0,255):
            for y in range(16):
                for x in range(16):
                    
                    unicorn.set_pixel(x,y,255-fade,255,255-fade)
                    
            unicorn.show()
            time.sleep(0.01)
    
    # Place a boat of the passed size on the game board
    # There is no limit to the number of boats placed though
    # if too many boats are placed it might not be possible to
    # place more and the program will get stuck in an infinite loop
    # A "1" is placed in the water 2D array for each part of the boat
    # The ships variable is updated to reflect the number of boat parts
    # on the game area in total after the boat it placed.
    def boat(self, size):

        boat_mask = []

        for a in range(size):
            
            boat_mask.append(0)
        
        orientation = random.choice(["horizontal","vertical"])
        
        if orientation == "horizontal":
            
            x = random.randint(0,16-size)
            y = random.randint(0,15)

            placement = []

            for a in range(size):
                
                placement.append(self.water[y][x+a])
            
            while placement != boat_mask:

                x = random.randint(0,16-size)
                y = random.randint(0,15)

                placement = []

                for a in range(size):
                    
                    placement.append(self.water[y][x+a])
            
            for a in range(size):
                
                self.water[y][x+a] = 1

        else:
            
            x = random.randint(0,15)
            y = random.randint(0,16-size)

            placement = []

            for a in range(size):
                
                placement.append(self.water[y+a][x])

            while placement != boat_mask:
                
                x = random.randint(0,16-size)
                y = random.randint(0,15)

                placement = []

                for a in range(size):
                    
                    placement.append(self.water[y+a][x])

            for a in range(size):
                
                self.water[y+a][x]=1

        self.ships += size

    # Process a shot using the passed co-ordinates on the game area
    # determine if the shot is a hit, miss or an already hit area.
    # The game area is then updated and the updated game area is displayed
    # on the unicorn hat.
    def shot(self,x,y):

        if self.water[y][x] == 1:

            print("Hit")

            self.water[y][x] = 3

            self.hit_flash(3)
            
            self.ships -= 1

        elif self.water[y][x] == 2:

            print("You have already hit this area.")

        else:

            print("Miss")

            self.water[y][x] = 2

            self.miss_flash()
        
            self.ammo -= 1        

        self.display_water()
        
# Enter and validate a co-ordinate
def enter_coord(direction):

    valid = False

    while valid != True:

        try:

            co_ord = int(input("Enter the "+direction+"-cordinate for your shot: "))

            if co_ord in range(1,17):
                
                valid = True

            else:
                
                print("Must be a number between 1 and 16.")

        except:
            
            print("Must be an number between 1 and 16.")

    if direction == "x":

        co_ord = co_ord - 1

    else:

        co_ord = 16 - co_ord
        
    return co_ord

# Main Program

# Declare an instance of the game area
ocean = ocean()

# Main program loop 
while True:
   
    # Initialise the game area
    ocean.reset()
    ocean.boat(5)
    ocean.boat(3)
    ocean.boat(3)
    ocean.boat(2)
    ocean.boat(2)
    ocean.ammo = 20
    game_over = False

    # Display the initial game area to the Unicornhat
    ocean.display_water()

    # Loop until game over conditions are met
    while game_over == False:

        # Display current game stats to the screen
        print("\nYou have",ocean.ammo,"shots left")
        print("There are",ocean.ships,"targets in our waters.")
        print("")
        
        # Get x and y co-ordinates of the shot
        x = enter_coord("x")    
        y = enter_coord("y")

        # Targetting animation
        ocean.target_flash(x,y)
        
        # Process the shot
        ocean.shot(x,y)

        # Check if the game over conditions are met
        if ocean.ships == 0 or ocean.ammo == 0:

            game_over = True

    # If the game is over because it is lost display game over
    if ocean.ammo == 0:
        
        print("\nOur fleet is defeated.")
        ocean.defeated()
            
    # Else if it is over because the game is won display victory
    elif ocean.ships == 0:
        
        print("\nOur fleet is victorious.")
        ocean.victory()

    # Ask if the player wants another game
    repeat = input("\nDo you want a rematch? ").lower()

    # If the player doesn't want to play again quit the program
    if repeat in ["no","n"]:
        print("Thanks for playing")
        break

Have fun !!!

Contribute to this site maintenance !

This is a self hosted site, on own hardware and Internet connection. The old, down to earth way 🙂. If you think that you found something useful here please contribute. Choose the form below (default 1 EUR) or donate using Bitcoin (default 0.0001 BTC) using the QR code. Thank you !

€1.00

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.