Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
masheen/conwayOSC/ConwayComposer.py
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
331 lines (261 sloc)
9.04 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Extension of game code by Nick Jarvis and Nick Wayne | |
# https://www.pygame.org/project-John+Conway's+Game+of+Life-2899-.html | |
''' | |
Conway Composer by Darius Smith | |
Uses Conway's Game of Life to send OSC messages to another program (PureData) | |
to generate music | |
Required libraries | |
pip3 install osc4py3, pygame | |
================================================================================ | |
Rules (from Conway's Game of Life) | |
1) Any live cell with fewer than two live neighbours dies, as if by underpopulation. | |
2) Any live cell with two or three live neighbours lives on to the next generation. | |
3) Any live cell with more than three live neighbours dies, as if by overpopulation. | |
4) Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. | |
================================================================================ | |
TO PLAY (KEY MAPPINGS) | |
LEFT CLICK >> mark a cell as 'alive' (blue) | |
RIGHT CLICK >> mark a cell as 'dead' (black) | |
- KEY >> clear grid | |
= KEY >> random grid | |
a-z or A-Z >> assign a letter to the cell your mouse is over ( | |
UP ARROW - progress time 1 frame | |
SPACEBAR - starts and stops the progression of time (toggle) | |
================================================================================ | |
When a cell is "born" (transitions from dead to alive) if it contains a letter | |
it sends out an OSC message "/conway/<letter>" which can be used to trigger | |
sounds/events in another program (PureData) | |
''' | |
from math import ceil | |
from osc4py3.as_eventloop import * | |
from osc4py3 import oscbuildparse | |
from collections import OrderedDict | |
import pygame,random | |
from pygame.locals import * | |
# Start the system. | |
osc_startup() | |
# Make client channels to send packets. | |
osc_udp_client("127.0.0.1", 8000, "pureData") | |
pygame.init() | |
''' ###### PARAMETERS ####### ''' | |
speed = 10 # how many iterations per second | |
squares = 2 # size of squares: 0 = 8X8, 1 = 16X16, 2 = 32X32, 3 = 64X64 | |
map_size = 32 # the width and height | |
''' ######################### ''' | |
if squares == 0: | |
imgs = ["res/alive_8.png","res/dead_8.png",8] | |
if squares == 1: | |
imgs = ["res/alive_16.png","res/dead_16.png",16] | |
if squares == 2: | |
imgs = ["res/alive_32.png","res/dead_32.png",32] | |
if squares == 3: | |
imgs = ["res/alive_64.png","res/dead_64.png",64] | |
#-----CONFIG----- | |
width = map_size*imgs[2] | |
height = map_size*imgs[2] | |
screen_size = width,height | |
screen = pygame.display.set_mode(screen_size) | |
clock = pygame.time.Clock() | |
alive = pygame.image.load(imgs[0]).convert() | |
dead = pygame.image.load(imgs[1]).convert() | |
done = False | |
marked_alive = [] | |
font = pygame.font.Font('freesansbold.ttf', 12) | |
white = (255, 255, 255) | |
class cell: | |
def __init__(self,location,alive = False): | |
self.to_be = None | |
self.alive = alive | |
self.pressed = False | |
self.location = location | |
self.osc = '' | |
self.text = font.render('', True, white) | |
class board: | |
def __init__(self): | |
self.map = [] | |
def fill(self,ran): | |
for i in range(map_size): | |
self.map.append([]) | |
for g in range(map_size): | |
if ran == True: | |
a = random.randint(0,4) | |
if a == 0: self.map[i].insert(g,cell((i,g),True)) | |
else: self.map[i].insert(g,cell((i,g))) | |
else: self.map[i].insert(g,cell((i,g))) | |
def draw(self): | |
for i in range(map_size): | |
for g in range(map_size): | |
cell = self.map[i][g] | |
loc = cell.location | |
if cell.alive == True: | |
screen.blit(alive,(loc[0]*imgs[2],loc[1]*imgs[2])) | |
else: | |
screen.blit(dead,(loc[0]*imgs[2],loc[1]*imgs[2])) | |
def get_cells(self,cell):# gets the cells around a cell | |
mapa = self.map | |
a = [] | |
b = [] | |
c = 0 | |
cell_loc = cell.location | |
try: a.append(mapa[abs(cell_loc[0]-1)][abs(cell_loc[1]-1)].location) | |
except Exception: pass | |
try: a.append(mapa[abs(cell_loc[0])][abs(cell_loc[1]-1)].location) | |
except Exception: pass | |
try: a.append(mapa[abs(cell_loc[0]+1)][abs(cell_loc[1]-1)].location) | |
except Exception: pass | |
try: a.append(mapa[abs(cell_loc[0]-1)][abs(cell_loc[1])].location) | |
except Exception: pass | |
try: a.append(mapa[abs(cell_loc[0]+1)][abs(cell_loc[1])].location) | |
except Exception: pass | |
try: a.append(mapa[abs(cell_loc[0]-1)][abs(cell_loc[1]+1)].location) | |
except Exception: pass | |
try: a.append(mapa[abs(cell_loc[0])][abs(cell_loc[1]+1)].location) | |
except Exception: pass | |
try: a.append(mapa[abs(cell_loc[0]+1)][abs(cell_loc[1]+1)].location) | |
except Exception: pass | |
num = len(list(OrderedDict.fromkeys(a)))# removes duplicates | |
for i in range(len(a)): b.append(mapa[a[i][0]][a[i][1]].alive) | |
for i in b:# c houses how many cells are alive around it | |
if i == True: c+=1 | |
if cell.alive == True: # rules | |
if c < 2: cell.to_be = False | |
if c > 3:cell.to_be = False | |
else: | |
if c == 3: cell.to_be = True | |
# rules | |
def update_frame(self): | |
for i in range(map_size): | |
for g in range(map_size): | |
cell = self.map[i][g] | |
self.get_cells(cell) | |
def update(self): | |
for i in range(map_size): | |
for g in range(map_size): | |
cell = self.map[i][g] | |
loc = cell.location | |
if cell.to_be != None: cell.alive = cell.to_be | |
if self.map[i][g].alive == True: | |
screen.blit(alive,(loc[0]*imgs[2],loc[1]*imgs[2])) | |
textRect = cell.text.get_rect() | |
textRect.center = (loc[0]*imgs[2] +ceil(imgs[2]/2),loc[1]*imgs[2]+ceil(imgs[2]/2)) | |
screen.blit(cell.text, textRect) | |
if run and loc not in marked_alive: | |
# OSC | |
if cell.osc != '': | |
print(cell.osc) | |
# Build a message with autodetection of data types, and send it. | |
msg = oscbuildparse.OSCMessage("/conway", None, [cell.osc]) | |
osc_send(msg, "pureData") | |
osc_process() | |
marked_alive.append(loc) | |
else: | |
screen.blit(dead,(loc[0]*imgs[2],loc[1]*imgs[2])) | |
textRect = cell.text.get_rect() | |
textRect.center = (loc[0]*imgs[2] +ceil(imgs[2]/2),loc[1]*imgs[2]+ceil(imgs[2]/2)) | |
screen.blit(cell.text, textRect) | |
if loc in marked_alive: | |
marked_alive.remove(loc) | |
cell.to_be = None | |
def cell_list(): | |
lst = [] | |
for i in range(map_size): | |
lst.append([]) | |
for g in range(map_size): lst[i].append((board.map[i][g].location[0]*imgs[2],board.map[i][g].location[1]*imgs[2])) | |
return lst | |
############################################################################################# | |
board = board() | |
board.fill(False) | |
board.draw() | |
tp = 0 | |
run = False | |
shift = False | |
while done == False: | |
milliseconds = clock.tick(60) | |
seconds = milliseconds / 1000.0 | |
tp += milliseconds | |
for event in pygame.event.get(): | |
if event.type == QUIT: | |
osc_terminate() | |
done = True | |
if event.type == KEYDOWN: | |
if event.key == K_SPACE: | |
run = not run | |
elif event.key == K_MINUS: | |
board.map = [] | |
board.fill(False) | |
board.draw() | |
elif event.key == K_EQUALS: | |
board.map = [] | |
board.fill(True) | |
board.draw() | |
elif event.key == K_RSHIFT or event.key == K_LSHIFT: | |
shift = True | |
elif event.key == K_BACKSPACE: | |
pos = pygame.mouse.get_pos() | |
rects = cell_list() | |
for i in range(map_size): | |
for g in range(map_size): | |
if pos[0] >= rects[i][g][0] and pos[0] < rects[i][g][0]+imgs[2] and pos[1] >= rects[i][g][1] and pos[1] < rects[i][g][1]+imgs[2]: | |
#print(i,g,key) | |
board.map[i][g].osc = '' | |
board.map[i][g].text = font.render('', True, white) | |
board.update() | |
else: | |
key = pygame.key.name(event.key) | |
if shift: | |
key = key.upper() | |
if key.isalpha() and len(key) == 1: | |
pos = pygame.mouse.get_pos() | |
rects = cell_list() | |
for i in range(map_size): | |
for g in range(map_size): | |
if pos[0] >= rects[i][g][0] and pos[0] < rects[i][g][0]+imgs[2] and pos[1] >= rects[i][g][1] and pos[1] < rects[i][g][1]+imgs[2]: | |
#print(i,g,key) | |
board.map[i][g].osc = key | |
board.map[i][g].text = font.render(key, True, white) | |
board.update() | |
if event.type == KEYUP: | |
if event.key == K_UP: | |
run = True | |
board.update_frame() | |
board.update() | |
run = False | |
elif event.key == K_RSHIFT or event.key == K_LSHIFT: | |
shift = False | |
if event.type == MOUSEBUTTONUP: | |
for i in range(map_size): | |
for g in range(map_size): | |
board.map[i][g].pressed = False | |
pressed = pygame.key.get_pressed() | |
mouse = pygame.mouse.get_pressed() | |
pos = pygame.mouse.get_pos() | |
# if pressed[K_MINUS]: | |
# board.map = [] | |
# board.fill(False) | |
# board.draw() | |
# if pressed[K_EQUALS]: | |
# board.map = [] | |
# board.fill(True) | |
# board.draw() | |
if run == True and tp >= 1000/speed : | |
tp = 0 | |
board.update_frame() | |
board.update() | |
if mouse[0]:# makes cells alive | |
rects = cell_list() | |
for i in range(map_size): | |
for g in range(map_size): | |
if pos[0] >= rects[i][g][0] and pos[0] < rects[i][g][0]+imgs[2] and pos[1] >= rects[i][g][1] and pos[1] < rects[i][g][1]+imgs[2] and board.map[i][g].pressed == False: | |
board.map[i][g].alive = True | |
board.map[i][g].pressed = True | |
board.update() | |
if mouse[2]: # kills cells | |
rects = cell_list() | |
for i in range(map_size): | |
for g in range(map_size): | |
if pos[0] >= rects[i][g][0] and pos[0] < rects[i][g][0]+imgs[2] and pos[1] >= rects[i][g][1] and pos[1] < rects[i][g][1]+imgs[2] and board.map[i][g].pressed == False: | |
board.map[i][g].alive = False | |
board.map[i][g].pressed = False | |
board.update() | |
pygame.display.flip() | |
pygame.quit() |