Created
March 19, 2013 10:37
-
-
Save rcruz63/5195131 to your computer and use it in GitHub Desktop.
Pythonista Scripts
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
# Card Game | |
# | |
# In this game, you have to find matching pairs of cards. | |
# This scene consists entirely of layers and demonstrates some | |
# interesting animation techniques. | |
from scene import * | |
from random import shuffle | |
from functools import partial | |
import sound | |
class Game (Scene): | |
def setup(self): | |
self.root_layer = Layer(self.bounds) | |
for effect in ['Click_1', 'Click_2', 'Coin_2', 'Coin_5']: | |
sound.load_effect(effect) | |
self.deal() | |
def draw(self): | |
background(0.0, 0.2, 0.3) | |
self.root_layer.update(self.dt) | |
self.root_layer.draw() | |
def deal(self): | |
images = ['Rabbit_Face', 'Mouse_Face', 'Cat_Face', | |
'Dog_Face', 'Octopus', 'Bear_Face', | |
'Chicken', 'Cow_Face'] * 2 | |
for image in images: | |
load_image(image) | |
shuffle(images) | |
self.root_layer.sublayers = [] | |
self.cards = [] | |
self.selected = [] | |
card_size = 96 if self.size.w > 700 else 64 | |
width = (card_size + 5) * 4 | |
offset = Point((self.size.w - width)/2, | |
(self.size.h - width)/2) | |
for i in xrange(len(images)): | |
x, y = i % 4, i / 4 | |
card = Layer(Rect(offset.x + x * (card_size + 5), | |
offset.y + y * (card_size + 5), | |
card_size, card_size)) | |
card.card_image = images[i] | |
card.background = Color(0.9, 0.9, 0.9) | |
card.stroke = Color(1, 1, 1) | |
card.stroke_weight = 4.0 | |
self.add_layer(card) | |
self.cards.append(card) | |
self.touch_disabled = False | |
def touch_began(self, touch): | |
if self.touch_disabled or len(self.cards) == 0: | |
return | |
if len(self.selected) == 2: | |
self.discard_selection() | |
return | |
for card in self.cards: | |
if card in self.selected or len(self.selected) > 1: | |
continue | |
if touch.location in card.frame: | |
def reveal_card(): | |
card.image = card.card_image | |
card.animate('scale_x', 1.0, 0.15, | |
completion=self.check_selection) | |
self.selected.append(card) | |
self.touch_disabled = True | |
card.animate('scale_x', 0.0, 0.15, | |
completion=reveal_card) | |
card.scale_y = 1.0 | |
card.animate('scale_y', 0.9, 0.15, autoreverse=True) | |
sound.play_effect('Click_1') | |
break | |
def discard_selection(self): | |
sound.play_effect('Click_2') | |
for card in self.selected: | |
def conceal(card): | |
card.image = None | |
card.animate('scale_x', 1.0, 0.15) | |
card.animate('scale_x', 0.0, 0.15, | |
completion=partial(conceal, card)) | |
card.scale_y = 1.0 | |
card.animate('scale_y', 0.9, 0.15, autoreverse=True) | |
self.selected = [] | |
def check_selection(self): | |
self.touch_disabled = False | |
if len(self.selected) == 2: | |
card_img1 = self.selected[0].card_image | |
card_img2 = self.selected[1].card_image | |
if card_img1 == card_img2: | |
sound.play_effect('Coin_5') | |
for c in self.selected: | |
c.animate('background', Color(0.5, 1, 0.5)) | |
self.cards.remove(c) | |
self.selected = [] | |
if len(self.cards) == 0: | |
self.win() | |
def new_game(self): | |
sound.play_effect('Coin_2') | |
self.deal() | |
self.root_layer.animate('scale_x', 1.0) | |
self.root_layer.animate('scale_y', 1.0) | |
def win(self): | |
self.delay(0.5, partial(sound.play_effect, 'Powerup_2')) | |
font_size = 100 if self.size.w > 700 else 50 | |
text_layer = TextLayer('Well Done!', 'Futura', font_size) | |
text_layer.frame.center(self.bounds.center()) | |
overlay = Layer(self.bounds) | |
overlay.background = Color(0, 0, 0, 0) | |
overlay.add_layer(text_layer) | |
self.add_layer(overlay) | |
overlay.animate('background', Color(0.0, 0.2, 0.3, 0.7)) | |
text_layer.animate('scale_x', 1.3, 0.3, autoreverse=True) | |
text_layer.animate('scale_y', 1.3, 0.3, autoreverse=True) | |
self.touch_disabled = True | |
self.root_layer.animate('scale_x', 0.0, delay=2.0, | |
curve=curve_ease_back_in) | |
self.root_layer.animate('scale_y', 0.0, delay=2.0, | |
curve=curve_ease_back_in, | |
completion=self.new_game) | |
run(Game()) |
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
# Cascade Game | |
# | |
# This is a complete game that demonstrates drawing images | |
# and text, handling touch events and combining simple drawing | |
# with layer animations. | |
# | |
# The game is also known as "Same Game". | |
# It may appear simple at first, but getting a good score | |
# actually requires some strategy. | |
from scene import * | |
from random import randint | |
from sound import load_effect, play_effect | |
from functools import partial | |
# These values are adjusted for the current screen size in | |
# the setup method, changing them here won't have an effect. | |
tile_size = 40 | |
cols = 8 | |
rows = 10 | |
class Tile (object): | |
def __init__(self, image, x, y): | |
self.offset = Point() # used for falling animation | |
self.selected = False | |
self.image = image | |
self.x, self.y = x, y | |
def hit_test(self, touch): | |
frame = Rect(self.x * tile_size + self.offset.x, | |
self.y * tile_size + self.offset.y, | |
tile_size, tile_size) | |
return touch.location in frame | |
class Game (Scene): | |
def setup(self): | |
#Use different sizes on iPad and iPhone: | |
global tile_size, cols, rows | |
ipad = self.size.w > 700 | |
tile_size = 64 if ipad else 40 | |
cols = 12 if ipad else 8 | |
rows = 12 if ipad else 10 | |
if not ipad and self.size.h > 480: | |
rows += 2 #iPhone 5 | |
#Preload some sound effects to reduce latency: | |
for sound_effect in ['Click_1', 'Error', 'Coin_3']: | |
load_effect(sound_effect) | |
self.new_game() | |
def new_game(self): | |
#The effects layer is used to display animated text | |
#overlays for scores and the game over screen: | |
self.effects = Layer(self.bounds) | |
images = ['Green_Apple', 'Grapes', 'Tangerine'] | |
self.score = 0 | |
self.game_over = False | |
self.grid = list() | |
for i in xrange(cols * rows): | |
tile = Tile(images[randint(0, len(images)-1)], | |
i % cols, i / cols) | |
self.grid.append(tile) | |
def neighbors(self, tile): | |
result = [] | |
if tile is None: return result | |
x, y = tile.x, tile.y | |
#Check for neighbors with the same image | |
#in all 4 directions: | |
directions = [(0, -1), (1, 0), (0, 1), (-1, 0)] | |
for direction in directions: | |
neighbor = self.tile_at(x + direction[0], | |
y + direction[1]) | |
if neighbor is not None and neighbor.image == tile.image: | |
result.append(neighbor) | |
return result | |
def tile_at(self, x, y): | |
if x < 0 or y < 0 or x >= cols or y >= rows: | |
return None | |
return self.grid[y * cols + x] | |
def touch_began(self, touch): | |
play_effect('Click_1') | |
for tile in self.grid: | |
if tile is not None: tile.selected = False | |
for tile in self.grid: | |
if tile is None: continue | |
if tile.hit_test(touch): | |
self.select_from(tile, set()) | |
break | |
def touch_ended(self, touch): | |
if self.game_over: | |
#Start a new game if the current game has ended: | |
self.new_game() | |
play_effect('Powerup_3') | |
return | |
#At least 2 tiles have to be removed: | |
sel_count = len(filter(lambda(x): x and x.selected, | |
self.grid)) | |
if sel_count < 2: | |
play_effect('Error') | |
for tile in self.grid: | |
if tile is not None: tile.selected = False | |
return | |
#The first tile is 10 points, the second 20, etc.: | |
score_added = ((sel_count * (sel_count + 1)) / 2) * 10 | |
self.score += score_added | |
play_effect('Coin_3') | |
#Show the added score as an animated text layer: | |
score_layer = TextLayer(str(score_added), | |
'GillSans-Bold', 40) | |
score_layer.frame.center(touch.location) | |
self.effects.add_layer(score_layer) | |
from_frame = score_layer.frame | |
to_frame = Rect(from_frame.x, from_frame.y + 200, | |
from_frame.w, from_frame.h) | |
score_layer.animate('frame', to_frame, duration=0.75) | |
score_layer.animate('alpha', 0.0, delay=0.3, | |
completion=score_layer.remove_layer) | |
#Remove selected tiles: | |
for i in xrange(len(self.grid)): | |
tile = self.grid[i] | |
if tile is None: continue | |
if tile.selected: | |
self.grid[i] = None | |
#Adjust the positions of the remaining tiles: | |
self.drop_tiles() | |
#If at least one tile has a neighbor with the same image, | |
#another move is possible: | |
can_move = max(map(len, map(self.neighbors, | |
self.grid))) > 0 | |
if not can_move: | |
play_effect('Bleep') | |
rest = len(filter(lambda x: x is not None, self.grid)) | |
msg = 'Perfect!' if rest == 0 else 'Game Over' | |
#Show an animated 'Game Over' message: | |
font_size = 100 if self.size.w > 700 else 50 | |
game_over_layer = TextLayer(msg, 'GillSans', font_size) | |
game_over_layer.frame.center(self.size.w / 2, | |
self.size.h / 2) | |
game_over_layer.alpha = 0.0 | |
self.effects.add_layer(game_over_layer) | |
#When the animation completes, the game_over flag is set, | |
#so that the next tap starts a new game: | |
completion = partial(setattr, self, 'game_over', True) | |
game_over_layer.animate('alpha', 1.0, duration=1.0, | |
completion=completion) | |
game_over_layer.animate('scale_x', 1.2, autoreverse=True, | |
duration=1.0) | |
game_over_layer.animate('scale_y', 1.2, autoreverse=True, | |
duration=1.0) | |
def drop_tiles(self): | |
new_grid = [None for x in xrange(len(self.grid))] | |
shift = 0 | |
for col in xrange(cols): | |
drop = 0 | |
col_empty = True | |
for row in xrange(rows): | |
tile = self.tile_at(col, row) | |
if tile is None: | |
drop += 1 | |
else: | |
col_empty = False | |
new_y = tile.y - drop | |
new_x = tile.x - shift | |
tile.offset.y += tile_size * (tile.y - new_y) | |
tile.offset.x += (tile.x - new_x) * tile_size | |
tile.x, tile.y = new_x, new_y | |
new_grid[new_y * cols + new_x] = tile | |
if col_empty: | |
shift += 1 | |
self.grid = new_grid | |
def select_from(self, tile, visited, count=1): | |
#Recursively select all neighboring tiles | |
#with the same image: | |
tile.selected = True | |
visited.add(tile) | |
n = self.neighbors(tile) | |
for neighbor in n: | |
if neighbor in visited: continue | |
if neighbor.image == tile.image: | |
count = self.select_from(neighbor, visited, count) + 1 | |
return count | |
def draw(self): | |
background(0, 0.1, 0.2) | |
collision = False | |
falling = False | |
#Adjust the falling animation speed based | |
#on the current framerate: | |
fall_speed = self.dt * 700 | |
#Draw all the tiles: | |
draw_selected = False | |
tint(1.0, 1.0, 1.0) | |
for tile in self.grid: | |
if tile is None: continue | |
if draw_selected != tile.selected: | |
tint(1.0, 1.0, 1.0, 0.5 if tile.selected else 1.0) | |
draw_selected = tile.selected | |
image(tile.image, | |
tile.x * tile_size + tile.offset.x, | |
tile.y * tile_size + tile.offset.y, | |
tile_size, tile_size) | |
if tile.offset.y > 0: | |
tile.offset.y = max(0.0, tile.offset.y - fall_speed) | |
if tile.offset.y == 0.0: collision = True | |
falling = True | |
#Draw the current score: | |
tint(1.0, 1.0, 1.0) | |
w, h = self.size.w, self.size.h | |
font_size = 60 if self.size.w > 700 else 40 | |
text(str(self.score), 'GillSans', font_size, w * 0.5, h - 50) | |
#Animate shifting empty columns: | |
if not falling: | |
for tile in self.grid: | |
if tile is None: continue | |
if tile.offset.x > 0: | |
tile.offset.x = max(0.0, tile.offset.x - fall_speed) | |
if tile.offset.x == 0: collision = True | |
#Play a sound effect if at least one tile has "landed": | |
if collision: | |
play_effect('Click_1') | |
#Update and draw the text effects layer: | |
self.effects.update(self.dt) | |
self.effects.draw() | |
#Always run the game in portrait orientation): | |
run(Game(), PORTRAIT) |
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
# Clock | |
# | |
# An analog clock that demonstrates drawing basic | |
# shapes with the scene module. | |
from scene import * | |
from time import localtime | |
ipad = False #will be set in the setup method | |
#Our Clock class inherits from Scene, so that its draw method | |
#is automatically called 60 times per second when we run it. | |
class Clock (Scene): | |
def setup(self): | |
global ipad | |
ipad = self.size.w > 700 | |
def should_rotate(self, orientation): | |
return True | |
def draw(self): | |
background(0, 0.2, 0.3) | |
t = localtime() | |
minute = t.tm_min | |
second = t.tm_sec | |
hour = t.tm_hour % 12 | |
margin = 25 if ipad else 5 | |
r = (min(self.size.w, self.size.h) / 2) - margin * 2 | |
center = Point(self.size.w/2, self.size.h/2) | |
#Draw the clock face: | |
fill(0.8, 0.8, 0.8) | |
stroke(0.5, 0.5, 0.5) | |
line_w = 10 if ipad else 5 | |
stroke_weight(line_w) | |
ellipse(center.x - r, center.y - r, r*2, r*2) | |
#Draw 12 markers for the hours: | |
push_matrix() | |
fill(0.5, 0.5, 0.5) | |
no_stroke() | |
translate(center.x, center.y) | |
digit_w = 20 if ipad else 10 | |
digit_h = 40 if ipad else 20 | |
for i in xrange(12): | |
rotate(30) | |
rect(-digit_w/2, r-digit_h, digit_w, digit_h) | |
pop_matrix() | |
#Draw the minute hand: | |
push_matrix() | |
translate(center.x, center.y) | |
rotate((-360 / 60) * minute + (-360/60) * (second/60.)) | |
fill(0, 0, 0) | |
m_height = r - (60 if ipad else 30) | |
m_width = 20 if ipad else 10 | |
rect(-m_width/2, -m_width/2, m_width, m_height) | |
pop_matrix() | |
#Draw the hour hand: | |
push_matrix() | |
translate(center.x, center.y) | |
rotate((-360 / 12) * hour + (-360/12.) * (minute/60.)) | |
fill(0, 0, 0) | |
h_width = 20 if ipad else 10 | |
h_height = r - (120 if ipad else 60) | |
rect(-h_width/2, -h_width/2, h_width, h_height) | |
pop_matrix() | |
#Draw the second hand: | |
push_matrix() | |
translate(center.x, center.y) | |
rotate((-360 / 60) * second) | |
fill(1, 0, 0) | |
s_width = 10 if ipad else 6 | |
s_height = r - (60 if ipad else 20) | |
rect(-s_width/2, -s_width/2, s_width, s_height) | |
pop_matrix() | |
fill(0, 0, 0) | |
#Draw the small circle in the middle: | |
r = 20 if ipad else 10 | |
ellipse(center.x - r, center.y - r, r*2, r*2) | |
#Run the scene that we just defined: | |
run(Clock()) |
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
# Image Effects | |
# Demonstrates some effects using different modules | |
# from the Python Imaging Library (PIL). | |
# | |
# Tip: You can touch and hold an image in the output | |
# to copy it to the clipboard or save it to your | |
# camera roll. | |
import Image, ImageOps, ImageFilter | |
from Image import BILINEAR | |
from math import sqrt, sin, cos, atan2 | |
def sketch(img): | |
edge_img = img.filter(ImageFilter.CONTOUR) | |
return ImageOps.grayscale(edge_img) | |
def color_tiles(img): | |
size = img.size | |
small_img = img.resize((size[0]/2, size[1]/2), BILINEAR) | |
bw_img = small_img.convert('1', dither=False) | |
gray_img = bw_img.convert('L') | |
result = Image.new('RGB', size) | |
tile1 = ImageOps.colorize(gray_img, 'green', 'red') | |
tile2 = ImageOps.colorize(gray_img, 'purple', 'yellow') | |
tile3 = ImageOps.colorize(gray_img, 'yellow', 'brown') | |
tile4 = ImageOps.colorize(gray_img, 'red', 'cyan') | |
result.paste(tile1, (0, 0)) | |
result.paste(tile2, (size[0]/2, 0)) | |
result.paste(tile3, (0, size[1]/2)) | |
result.paste(tile4, (size[0]/2, size[1]/2)) | |
return result | |
def twisted(img, strength): | |
mesh = [] | |
m = 16 | |
w, h = img.size | |
for x in xrange(w / m): | |
for y in xrange(h / m): | |
target_rect = (x * m, y * m, x * m + m, y * m + m) | |
quad_points = ((x * m, y * m), (x * m, y * m + m), | |
(x * m + m, y * m + m), (x * m + m, y * m)) | |
quad_list = [] | |
for qx, qy in quad_points: | |
dx = w/2 - qx | |
dy = h/2 - qy | |
d = sqrt(dx**2 + dy**2) | |
angle = atan2(dx, dy) | |
angle += max((w/2 - d), 0) * strength | |
qx = w/2 - sin(angle) * d | |
qy = h/2 - cos(angle) * d | |
quad_list.append(qx) | |
quad_list.append(qy) | |
mesh.append((target_rect, quad_list)) | |
return img.transform(img.size, Image.MESH, mesh, BILINEAR) | |
def main(): | |
img = Image.open('Test_Lenna') | |
img = img.resize((256, 256), Image.BILINEAR) | |
img.show() | |
sketch(img).show() | |
color_tiles(img).show() | |
twisted(img, 0.02).show() | |
if __name__ == '__main__': | |
main() |
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
# Image Warp | |
# | |
# Demonstrates an interesting use of the image_quad function | |
# to distort an image based on touch. | |
from scene import * | |
from math import sqrt, sin, pi, floor | |
import Image | |
M = 16 # number of vert. and horiz. quads in the mesh (16*16=256) | |
class ImageWarp (Scene): | |
def setup(self): | |
self.offsets = [[(0.0, 0.0) for x in xrange(M+1)] for y in xrange(M+1)] | |
if self.size.w >= 700: | |
# Use the original image on iPad: | |
self.img = 'Test_Lenna' | |
s = 512 | |
else: | |
# Resize the image for small screens: | |
s = 256 | |
img_name = 'Test_Lenna' | |
img = Image.open(img_name).convert('RGBA') | |
img = img.resize((s, s), Image.BILINEAR) | |
self.img = load_pil_image(img) | |
self.img_size = s | |
self.m = s / M | |
def draw_warped_image(self): | |
m = self.m | |
for x in xrange(M): | |
for y in xrange(M): | |
d = self.offsets | |
# distances of the 4 corner points from their original position: | |
d1 = d[x][y]; d2 = d[x + 1][y] | |
d3 = d[x][y + 1]; d4 = d[x + 1][y + 1] | |
image_quad(self.img, | |
# distorted quad: | |
x * m + d1[0], y * m + d1[1], | |
x * m + m + d2[0], y * m + d2[1], | |
x * m + d3[0], y * m + m + d3[1], | |
x * m + m + d4[0], y * m + m + d4[1], | |
# source quad in image: | |
x * m, y * m, x * m + m, y * m, | |
x * m, y * m + m, x * m + m, y * m + m) | |
def bulge(self, touch_x, touch_y): | |
# push mesh vertices away from touch location: | |
m = self.m | |
r = self.img_size / 5 | |
for x in xrange(0, M + 1): | |
for y in xrange(0, M + 1): | |
offset = self.offsets[x][y] | |
dist = sqrt((x*m-touch_x + offset[0])**2.0 + | |
(y*m-touch_y + offset[1])**2.0) | |
dx = x*m - touch_x | |
dy = y*m - touch_y | |
unit_x = dx / dist if dist > 0 else 0.0 | |
unit_y = dy / dist if dist > 0 else 0.0 | |
b = self.dt * 50 | |
if dist < r: | |
falloff = max(sin(dist/r*pi), 0) | |
offset_x = unit_x * b * falloff + offset[0] | |
offset_y = unit_y * b * falloff + offset[1] | |
self.offsets[x][y] = (offset_x, offset_y) | |
def revert(self): | |
for x in xrange(0, M + 1): | |
for y in xrange(0, M + 1): | |
offset = self.offsets[x][y] | |
offset_x = floor(offset[0] - cmp(offset[0], 0)) | |
offset_y = floor(offset[1] - cmp(offset[1], 0)) | |
self.offsets[x][y] = (offset_x, offset_y) | |
def draw(self): | |
background(0, 0, 0) | |
push_matrix() | |
tx = self.size.w/2 - self.img_size/2 | |
ty = self.size.h/2 - self.img_size/2 | |
translate(tx, ty) | |
text('Touch the image to deform it.', 'Helvetica-Bold', | |
18, self.img_size/2, -30, alignment=5) | |
text('Use two fingers to revert.', 'Helvetica-Bold', | |
18, self.img_size/2, -60, alignment=5) | |
self.draw_warped_image() | |
pop_matrix() | |
if len(self.touches) ==0: | |
return | |
if len(self.touches) > 1: | |
self.revert() | |
else: | |
loc = self.touches.values()[0].location | |
touch_x, touch_y = loc.x - tx, loc.y - ty | |
self.bulge(touch_x, touch_y) | |
run(ImageWarp(), frame_interval=1) |
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
# Markdown Conversion | |
# | |
# This script demonstrates how you can convert Markdown documents | |
# to HTML and view the results in the built-in browser. | |
import os, tempfile, codecs | |
import console, clipboard, webbrowser | |
from markdown2 import markdown | |
DEMO = ''' | |
# Markdown Conversion Demo | |
**Markdown** is a plain text formatting language | |
invented by [John Gruber][1]. | |
You can use this script to convert markdown | |
documents to html and preview them in the | |
built-in browser. | |
Markdown makes it easy to make text **bold** or *italic*, | |
and to add [links][2]. | |
You can also format block quotes: | |
> Any intelligent fool can make things bigger, more | |
> complex, and more violent. It takes a touch of genius | |
> -- and a lot of courage -- to move in the opposite | |
> direction. | |
*-- Albert Einstein* | |
...and code blocks: | |
from markdown2 import markdown | |
text = "*hello world*" | |
html = markdown(text) | |
print html | |
For more detailed information about Markdown, | |
please read the [introduction and syntax reference][3] | |
on the project page. | |
[1]: http://daringfireball.net | |
[2]: http://omz-software.com/pythonista | |
[3]: http://daringfireball.net/projects/markdown | |
''' | |
# Basic HTML document structure and CSS styling: | |
TEMPLATE = ''' | |
<html> | |
<head> | |
<meta charset="utf-8"/> | |
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> | |
<style> | |
body { | |
font-family: helvetica; | |
font-size: 18px; | |
color: #333; | |
} | |
blockquote { | |
border-left: solid 3px #bbb; | |
margin-left: 0px; | |
padding-left: 10px; | |
} | |
pre { | |
border: 1px solid #bbb; | |
border-radius: 3px; | |
padding: 3px; | |
background-color: #f8f8f8; | |
} | |
code { | |
font-family: DejaVuSansMono, monospace; | |
} | |
#wrapper { | |
margin: 20px;} | |
</style> | |
</head> | |
<body> | |
<div id="wrapper"> | |
{{CONTENT}} | |
</div> | |
</body> | |
</html> | |
''' | |
def main(): | |
choice = console.alert('Markdown Conversion', '', 'Demo', 'Convert Clipboard') | |
md = DEMO if choice == 1 else clipboard.get() | |
html = markdown(md, extras=['smarty-pants']) | |
tempdir = tempfile.gettempdir() | |
html_path = os.path.join(tempdir, 'temp.html') | |
html = TEMPLATE.replace('{{CONTENT}}', html) | |
with codecs.open(html_path, 'w', 'utf-8') as f: | |
f.write(html) | |
file_url = 'file://' + html_path | |
webbrowser.open(file_url) | |
if __name__ == '__main__': | |
main() |
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
# Particles | |
# | |
# Create colorful bubbles by moving your fingers. | |
from scene import * | |
from random import random | |
from colorsys import hsv_to_rgb | |
class Particle (object): | |
def __init__(self, location): | |
self.velocity = Size(random() * 4 - 2, random() * 4 - 2) | |
self.location = location | |
self.hue = random() | |
self.alpha = 1.0 | |
class Particles (Scene): | |
def setup(self): | |
self.show_instructions = True | |
self.particles = set() | |
self.p_size = 64 if self.size.w > 700 else 32 | |
def should_rotate(self, orientation): | |
return True | |
def touch_began(self, touch): | |
if self.show_instructions: | |
self.show_instructions = False | |
blend_mode(BLEND_ADD) | |
def touch_moved(self, touch): | |
particle = Particle(touch.location) | |
self.particles.add(particle) | |
def draw(self): | |
background(0, 0, 0) | |
if self.show_instructions: | |
s = 40 if self.size.w > 700 else 17 | |
text('Move your fingers across the screen.', | |
'Futura', s, *self.bounds.center().as_tuple()) | |
dead = set() | |
for particle in self.particles: | |
r, g, b = hsv_to_rgb(particle.hue, 1, 1) | |
a = particle.alpha | |
tint(r * a, g * a, b * a, a) | |
x, y = particle.location.as_tuple() | |
s = (2 - a) * self.p_size | |
image('White_Circle', x - s/2, y - s/2, s, s) | |
particle.alpha -= 0.02 | |
particle.hue += 0.02 | |
particle.location.x += particle.velocity.w | |
particle.location.y += particle.velocity.h | |
if particle.alpha <= 0: | |
dead.add(particle) | |
self.particles -= dead | |
run(Particles()) |
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
# Piano | |
# | |
# A simple multi-touch piano. | |
from scene import * | |
import sound | |
from itertools import chain | |
class Key (object): | |
def __init__(self, frame): | |
self.frame = frame | |
self.name = None | |
self.touch = None | |
self.color = Color(1, 1, 1) | |
self.highlight_color = Color(0.9, 0.9, 0.9) | |
def hit_test(self, touch): | |
return touch.location in self.frame | |
class Piano (Scene): | |
def setup(self): | |
self.white_keys = [] | |
self.black_keys = [] | |
white_key_names = ['Piano_C3', 'Piano_D3', 'Piano_E3', | |
'Piano_F3', 'Piano_G3', 'Piano_A3', | |
'Piano_B3', 'Piano_C4'] | |
black_key_names = ['Piano_C3#', 'Piano_D3#', 'Piano_F3#', | |
'Piano_G3#', 'Piano_A3#'] | |
for key_name in chain(white_key_names, black_key_names): | |
sound.load_effect(key_name) | |
white_positions = range(8) | |
black_positions = [0.5, 1.5, 3.5, 4.5, 5.5] | |
key_w = self.size.w | |
key_h = self.size.h / 8 | |
for i in range(len(white_key_names)): | |
pos = white_positions[i] | |
key = Key(Rect(0, pos * key_h, key_w, key_h)) | |
key.name = white_key_names[i] | |
self.white_keys.append(key) | |
for i in range(len(black_key_names)): | |
pos = black_positions[i] | |
key = Key(Rect(0, pos * key_h + 10, key_w * 0.6, key_h - 20)) | |
key.name = black_key_names[i] | |
key.color = Color(0, 0, 0) | |
key.highlight_color = Color(0.2, 0.2, 0.2) | |
self.black_keys.append(key) | |
def draw(self): | |
stroke_weight(1) | |
stroke(0.5, 0.5, 0.5) | |
for key in chain(self.white_keys, self.black_keys): | |
if key.touch is not None: | |
fill(*key.highlight_color.as_tuple()) | |
else: | |
fill(*key.color.as_tuple()) | |
rect(*key.frame.as_tuple()) | |
def touch_began(self, touch): | |
for key in chain(self.black_keys, self.white_keys): | |
if key.hit_test(touch): | |
key.touch = touch | |
sound.play_effect(key.name) | |
return | |
def touch_moved(self, touch): | |
hit_key = None | |
for key in chain(self.black_keys, self.white_keys): | |
hit = key.hit_test(touch) | |
if hit and hit_key is None: | |
hit_key = key | |
if key.touch is None: | |
key.touch = touch | |
sound.play_effect(key.name) | |
if key.touch == touch and key is not hit_key: | |
key.touch = None | |
def touch_ended(self, touch): | |
for key in chain(self.black_keys, self.white_keys): | |
if key.touch == touch: | |
key.touch = None | |
run(Piano(), PORTRAIT) |
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
# Function Plotter | |
import canvas | |
import console | |
from math import sin, cos, pi | |
def draw_grid(min_x, max_x, min_y, max_y): | |
w, h = canvas.get_size() | |
scale_x = w / (max_x - min_x) | |
scale_y = h / (max_y - min_y) | |
min_x, max_x = round(min_x), round(max_x) | |
min_y, max_y = round(min_y), round(max_y) | |
canvas.begin_updates() | |
canvas.set_line_width(1) | |
canvas.set_stroke_color(0.7, 0.7, 0.7) | |
#Draw vertical grid lines: | |
x = min_x | |
while x <= max_x: | |
if x != 0: | |
draw_x = round(w / 2 + x * scale_x) + 0.5 | |
canvas.draw_line(draw_x, 0, draw_x, h) | |
x += 0.5 | |
#Draw horizontal grid lines: | |
y = min_y | |
while y <= max_y: | |
if y != 0: | |
draw_y = round(h/2 + y * scale_y) + 0.5 | |
canvas.draw_line(0, draw_y, w, draw_y) | |
y += 0.5 | |
#Draw x and y axis: | |
canvas.set_stroke_color(0, 0, 0) | |
canvas.draw_line(0, h/2, w, h/2) | |
canvas.draw_line(w/2, 0, w/2, h) | |
canvas.end_updates() | |
def plot_function(func, color, min_x, max_x, min_y, max_y): | |
#Calculate scale, set line width and color: | |
w, h = canvas.get_size() | |
origin_x, origin_y = w * 0.5, h * 0.5 | |
scale_x = w / (max_x - min_x) | |
scale_y = h / (max_y - min_y) | |
canvas.set_stroke_color(*color) | |
canvas.set_line_width(2) | |
canvas.move_to(origin_x + scale_x * min_x, | |
origin_y + func(min_x) * scale_y) | |
#Draw the graph line: | |
x = min_x | |
while x <= max_x: | |
x += 0.05 | |
draw_x = origin_x + scale_x * x | |
draw_y = origin_y + func(x) * scale_y | |
canvas.add_line(draw_x, draw_y) | |
canvas.set_fill_color(*color) | |
canvas.draw_path() | |
#Set up the canvas size and clear any text output: | |
console.clear() | |
canvas.set_size(688, 688) | |
#Draw the grid: | |
area = (-pi, pi, -pi, pi) | |
draw_grid(*area) | |
#Draw 4 different graphs (sin(x), cos(x), x^2, x^3): | |
plot_function(sin, (1, 0, 0), *area) | |
plot_function(cos, (0, 0, 1), *area) | |
plot_function(lambda x: x ** 2, (0, 1, 1), *area) | |
plot_function(lambda x: x ** 3, (1.0, 0.5, 0), *area) |
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
# Lottery Number Generator | |
from random import choice | |
import console | |
#Helper function to input a number within a given range: | |
def input_number(prompt, min_value, max_value): | |
value = None | |
while value is None: | |
try: | |
value = int(raw_input(prompt)) | |
except ValueError: | |
print 'Please enter a number!' | |
if value < min_value or value > max_value: | |
print ('Please enter a number between %i and %i!' % | |
(min_value, max_value)) | |
value = None | |
return value | |
#Print the title and input the range of numbers: | |
console.clear() | |
title = 'Lottery Number Generator' | |
print title | |
print '=' * 40 | |
minimum = input_number('Smallest number: ', 1, 9999) | |
maximum = input_number('Largest number: ', minimum, 9999) | |
n = input_number('How many numbers do you want to draw? ', | |
1, maximum - minimum + 1) | |
#Pick the numbers and print the results: | |
all_numbers = range(minimum, maximum + 1) | |
selection = [] | |
for i in xrange(n): | |
r = choice(all_numbers) | |
selection.append(r) | |
all_numbers.remove(r) | |
print '=' * 40 | |
print 'Your numbers:', selection |
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
# Snake | |
# | |
# Controls: Turn left or right by tapping the | |
# left or right half of the screen. | |
from scene import * | |
from sound import load_effect, play_effect | |
from random import randint | |
import pickle | |
from functools import partial | |
class Game (Scene): | |
def setup(self): | |
w, h = self.size.as_tuple() | |
self.field = Rect(16, (h - w - 44) / 2 + 16, w - 32, w - 32) | |
for effect in ['Coin_1', 'Explosion_3', 'Powerup_2']: | |
load_effect(effect) | |
self.load_highscore() | |
self.new_game() | |
def draw(self): | |
self.draw_background() | |
segments = self.get_snake_segments() | |
self.draw_snake(segments) | |
if self.paused: | |
return | |
self.move_snake(segments) | |
def touch_began(self, touch): | |
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] | |
if touch.location.x > self.size.w / 2: | |
direction_index = (directions.index(self.direction) + 1) % 4 | |
else: | |
direction_index = directions.index(self.direction) - 1 | |
self.next_direction = directions[direction_index] | |
def new_game(self): | |
self.items = set() | |
self.joints = [] | |
self.joints.append(Point(self.size.w / 2, 256)) #head | |
self.joints.append(Point(self.size.w / 2, 160)) #tail | |
self.direction = (0, 1) #up | |
self.next_direction = None | |
self.grow = 0 | |
self.speed = 3 | |
self.paused = False | |
self.score = 0 | |
for i in xrange(3): self.add_item() | |
def game_over(self): | |
play_effect('Explosion_3') | |
self.paused = True | |
if self.score > self.highscore: | |
self.highscore = self.score | |
self.save_highscore() | |
self.delay(2.0, self.new_game) | |
def draw_background(self): | |
#Draw field and scores: | |
background(0, 0, 0) | |
tint(1, 1, 1) | |
text(str(self.score), 'Futura', 40, self.size.w/2, self.size.h - 50) | |
if self.score < self.highscore: | |
tint(0.6, 0.6, 0.6) | |
else: | |
tint(0, 1, 0) | |
text('Highscore: ' + str(self.highscore), | |
'Futura', 24, self.size.w/2, 50) | |
fill(0, 0.45, 0.65) | |
rect(*self.field.as_tuple()) | |
#Draw collectable items: | |
fill(1, 0, 0) | |
for item in self.items: | |
ellipse(item.x - 10, item.y - 10, 20, 20) | |
def get_snake_segments(self): | |
#Calculate the rectangles that connect the joints: | |
segments = [] | |
prev_joint = None | |
for joint in self.joints: | |
if prev_joint is not None: | |
p1 = prev_joint | |
p2 = joint | |
if p1.x == p2.x: | |
segments.append(Rect(p1.x - 15, p1.y, 30, p2.y - p1.y)) | |
else: | |
segments.append(Rect(p1.x, p1.y - 15, p2.x - p1.x, 30)) | |
prev_joint = joint | |
return segments | |
def draw_snake(self, segments): | |
fill(1, 0.8, 0.25) | |
stroke(0, 0, 0) | |
stroke_weight(1) | |
for joint in self.joints: | |
ellipse(joint.x - 15, joint.y - 15, 30, 30) | |
for segment in segments: | |
rect(*segment.as_tuple()) | |
stroke_weight(0) | |
for joint in self.joints: | |
ellipse(joint.x - 14, joint.y - 14, 28, 28) | |
#Draw eyes: | |
fill(0, 0, 0) | |
stroke(1, 1, 1) | |
stroke_weight(2) | |
head = self.joints[0] | |
if abs(self.direction[0]) > 0: | |
ellipse(head.x - 10 * self.direction[0] - 4, head.y + 2, 8, 8) | |
ellipse(head.x - 10 * self.direction[0] - 4, head.y - 10, 8, 8) | |
else: | |
ellipse(head.x + 2, head.y - 10 * self.direction[1] - 4, 8, 8) | |
ellipse(head.x - 10, head.y - 10 * self.direction[1] - 4, 8, 8) | |
stroke_weight(0) | |
def move_snake(self, segments): | |
hx = self.joints[0].x | |
hy = self.joints[0].y | |
tx = self.joints[-1].x | |
ty = self.joints[-1].y | |
collected = set() | |
for i in xrange(self.speed): | |
#Move head: | |
hx += self.direction[0] | |
hy += self.direction[1] | |
if self.next_direction is not None: | |
if hx % 32 == 0 and hy % 32 == 0: | |
self.joints.insert(1, Point(hx, hy)) | |
self.direction = self.next_direction | |
self.next_direction = None | |
#Don't move the tail while growing: | |
if self.grow > 0: | |
self.grow -= 1 | |
else: | |
#Move the tail towards the last joint: | |
tx += cmp(self.joints[-2].x, tx) | |
ty += cmp(self.joints[-2].y, ty) | |
#When the joint is reached, remove it: | |
if tx == self.joints[-2].x and ty == self.joints[-2].y: | |
del self.joints[-1] | |
#Update head and tail positions: | |
self.joints[0].x = hx | |
self.joints[0].y = hy | |
self.joints[-1].x = tx | |
self.joints[-1].y = ty | |
#Check collisions: | |
head_rect = Rect(hx - 15, hy - 15, 30, 30) | |
for segment in segments[2:]: | |
if head_rect.intersects(segment): | |
self.game_over() | |
if hx < self.field.left() + 16 or hx > self.field.right() - 16: | |
self.game_over() | |
elif hy < self.field.bottom() + 16 or hy > self.field.top() - 16: | |
self.game_over() | |
#Collect items: | |
for item in self.items: | |
if hx == item.x and hy == item.y: | |
collected.add(item) | |
self.collect_items(collected) | |
def collect_items(self, collected): | |
if len(collected) > 0: play_effect('Coin_1') | |
for item in collected: | |
self.items -= collected | |
self.grow += 32 | |
self.score += 10 | |
self.add_item() | |
#Speed up for every 10 collected items: | |
if len(collected) > 0 and self.score % 100 == 0: | |
self.speed = min(8, self.speed + 1) | |
play_effect('Powerup_2') | |
#Pause the game for 1 second when the speed is increased: | |
self.paused = True | |
self.delay(1.0, partial(setattr, self, 'paused', False)) | |
def add_item(self): | |
x = randint(0, int(self.field.w / 32) - 1) * 32 + 32 | |
y = randint(0, int(self.field.h / 32) - 1) * 32 + self.field.y + 16 | |
self.items.add(Point(x, y)) | |
def load_highscore(self): | |
try: | |
with open('snake_highscore', 'r') as f: | |
self.highscore = pickle.load(f) | |
except IOError: | |
self.highscore = 0 | |
def save_highscore(self): | |
with open('snake_highscore', 'w+') as f: | |
pickle.dump(self.highscore, f) | |
run(Game(), PORTRAIT) |
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
# Stopwatch | |
# | |
# A simple stopwatch that demonstrates the scene module's text | |
# drawing capabilities. | |
from scene import * | |
from time import time | |
from math import modf | |
from itertools import chain | |
import string | |
class Stopwatch (Scene): | |
def setup(self): | |
self.start_time = 0.0 | |
self.stop_time = 0.0 | |
self.running = False | |
#Render all the digits as individual images: | |
self.numbers = {} | |
font_size = 150 if self.size.w > 700 else 60 | |
for s in chain(string.digits, [':', '.']): | |
#render_text returns a tuple of | |
#an image name and its size. | |
self.numbers[s] = render_text(s, 'Helvetica-Bold', font_size) | |
def should_rotate(self, orientation): | |
return True | |
def draw(self): | |
background(0, 0, 0) | |
#Format the elapsed time (dt): | |
dt = 0.0 | |
if self.running: | |
dt = time() - self.start_time | |
else: | |
dt = self.stop_time - self.start_time | |
minutes = dt / 60 | |
seconds = dt % 60 | |
centiseconds = modf(dt)[0] * 100 | |
s = '%02d:%02d.%02d' % (minutes, seconds, centiseconds) | |
#Determine overall size for centering: | |
w, h = 0.0, self.numbers['0'][1].h | |
for c in s: | |
size = self.numbers[c][1] | |
w += size.w | |
#Draw the digits: | |
x = int(self.size.w * 0.5 - w * 0.5) | |
y = int(self.size.h * 0.5 - h * 0.5) | |
for c in s: | |
img, size = self.numbers[c] | |
image(img, x, y, size.w, size.h) | |
x += size.w | |
def touch_began(self, touch): | |
if not self.running: | |
if self.start_time > 0: | |
#Reset: | |
self.start_time = 0.0 | |
self.stop_time = 0.0 | |
else: | |
#Start: | |
self.start_time = time() | |
self.running = True | |
else: | |
#Stop: | |
self.stop_time = time() | |
self.running = False | |
run(Stopwatch()) |
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
# Zen | |
# | |
# Prints the Zen of Python with a color gradient. | |
# This demonstrates the use of the console module to set | |
# the output's font and color. | |
import console | |
import sys | |
import codecs | |
from colorsys import hsv_to_rgb | |
from StringIO import StringIO | |
#Suppress the output while importing 'this': | |
prev_out = sys.stdout | |
sys.stdout = StringIO() | |
import this | |
sys.stdout = prev_out | |
console.clear() | |
#Decode the 'Zen of Python' text and split to a list of lines: | |
decoder = codecs.getdecoder('rot_13') | |
text = decoder(this.s)[0] | |
lines = text.split('\n') | |
#Print the title (first line): | |
console.set_font('Futura', 22) | |
console.set_color(0.2, 0.2, 0.2) | |
print lines[0] | |
#Print the other lines in varying colors: | |
hue = 0.45 | |
for line in lines[1:]: | |
r, g, b = hsv_to_rgb(hue, 1.0, 0.8) | |
console.set_color(r, g, b) | |
console.set_font('Futura', 16) | |
print line | |
hue += 0.02 | |
#Reset output to default font and color: | |
console.set_font() | |
console.set_color() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks. Amazing set of scripts