-
-
Save mdecycu/72fc7909f5934afb32bf717d0278e491 to your computer and use it in GitHub Desktop.
Brython examples
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
# 2a w3 grouping program, 與 2b 處理架構相同 | |
from browser import html | |
from browser import document | |
import random | |
brython_div = document["brython_div"] | |
# 根據 href 與 content 將 html 元件中的 anchor 插入頁面 | |
def makeLink(href, content): | |
brython_div <= html.A(content, href=href) | |
#brython_div <= html.BR() | |
# 1a | |
course_num = "0729" | |
# 2a | |
#course_num = "0752" | |
# 2b | |
#course_num = "0764" | |
reg_url = "https://nfulist.herokuapp.com/?semester=1102&courseno="+ course_num + "&column=True" | |
reg_data = open(reg_url).read().split("\n")[:-1] | |
#print(reg_data) | |
aorb = "a" | |
url = "https://mde.tw/studlist/2022spring/1a.txt" | |
course = "wcm2022" | |
# 從 url 讀取資料後, 以跳行符號分割資料進入數列後 | |
# 去除數列中的第一筆與最後一筆資料後可得每位學員所填的資料 | |
data = open(url).read().split("\n")[1:-1] | |
#print(data) | |
# 再以 \t 分割每位學員的資料, | |
#可以取得每位學員的學號, github 帳號與組別 | |
big = [] | |
num_github = {} | |
num_grp = {} | |
for i in data: | |
stud_no, github, grp_no = i.split("\t") | |
#print(stud_no) | |
#print(stud_no, github, grp_no) | |
# 因為納入新成員, 所以 big 必須之後才可組成 | |
#big.append([stud_no, github, grp_no]) | |
if github != "": | |
num_github[stud_no] = github | |
else: | |
num_github[stud_no] = stud_no | |
num_grp[stud_no] = grp_no | |
#print(num_grp) | |
# 根據最新註冊資料更新 studlist 中的內容 | |
for i in reg_data: | |
# 納入新加選的學員或從 data 中移除已經退選者 | |
# 假如最新修課學員學號並不在原名單中, 則屬加選者 | |
if not(i in num_github): | |
#print(i) | |
# 先以學號作為帳號, 分組欄位空白 | |
num_github[i] = i | |
num_grp[i] = "" | |
# 因為隨後查詢 num_github 與 num_grp 會以 reg_data 為主 | |
# 在實作中可以無需從 num_github 或 num_grp 中移除退選者 | |
for i in data: | |
# 表示該 i 學號已經退選 | |
if not(i in reg_data): | |
# 將 i 學號分別從 num_gihub 與 num_grp 移除 | |
try: | |
del num_github[i] | |
del num_grp[i] | |
except: | |
# 表示沒有退選者 | |
pass | |
#print(num_github) | |
for i in reg_data: | |
big.append([i, num_github[i], num_grp[i]]) | |
#print(big) | |
# 根據每一 element 的第三個 element sort | |
big.sort(key = lambda x: x[2]) | |
# big 已經按照組別排序 | |
#print(big) | |
ungrouped = [] | |
grouped = [] | |
for i in big: | |
if i[2] == "": | |
ungrouped.append(i[0]) | |
else: | |
# 將組別放到第一位置 | |
grouped.append([i[2], i[0]]) | |
#print(grouped) | |
#print(ungrouped) | |
d = {} | |
# 逐一檢視 grouped 數列 | |
for i in grouped: | |
# 若該組序已存在 d dict 中, | |
# 則以 extend() 納入除組序之外的組員學號 | |
if i[0] in d: | |
d[i[0]].extend(i[1:]) | |
#print("i[0] in d:",i[0], "d:", d) | |
else: | |
# 若已納分組的 element 中之組序為全新組序, | |
# 則將該已納分組的 element 放入 dict 首位元素 | |
# 準備透過 extend() 納入其他組員學號 | |
d[i[0]] = i | |
#print("i i[0] not in d:", i, "d:", d) | |
#print("finally d:", d, "d.values():", d.values()) | |
group_member = list(d.values()) | |
# 針對 2a.txt 處理第一時間大組人數超過 8 人者 | |
# 將亂數留下 8 名成員, 其餘組員納入 ungrouped 數列 | |
# grouped 重新回歸空數列 | |
grouped = [] | |
for i in group_member: | |
# 連同組序大於 9 表示組員總數大於 8 | |
if len(i) > 9: | |
temp_member = i[1:] | |
# 以 shuffle 處理 temp_member | |
# 目的在隨機留下 8 位組員, 其餘納入 ungrouped | |
random.shuffle(temp_member) | |
# i[0] 為組序, temp_member[:8] 為前 8 位組員 | |
grouped.append([i[0]] + temp_member[:8]) | |
ungrouped = ungrouped + temp_member[8:] | |
else: | |
grouped.append(i) | |
#print(grouped) | |
#print(ungrouped) | |
d = {} | |
# 逐一檢視 grouped 數列 | |
for i in grouped: | |
# 若該組序已存在 d dict 中, | |
# 則以 extend() 納入除組序之外的組員學號 | |
if i[0] in d: | |
d[i[0]].extend(i[1:]) | |
#print("i[0] in d:",i[0], "d:", d) | |
else: | |
# 若已納分組的 element 中之組序為全新組序, | |
# 則將該已納分組的 element 放入 dict 首位元素 | |
# 準備透過 extend() 納入其他組員學號 | |
d[i[0]] = i | |
#print("i i[0] not in d:", i, "d:", d) | |
#print("finally d:", d, "d.values():", d.values()) | |
group_member = list(d.values()) | |
# group_member 第一位為組序, 隨後為組員學號 | |
#print(group_member) | |
random.shuffle(ungrouped) | |
#print("ungrouped:" + str(len(ungrouped))) | |
grp = 1 | |
group = [] | |
for i in group_member: | |
#print("grp " + str(i[0]) + ": num, " + str(len(i[1:]))) | |
if len(i[1:]) < 6: | |
#print("can take " + str(8 - len(i[1:])) + "members") | |
# 若仍有學員未納組, 則可根據缺額補入學員學號 | |
try: | |
#print("add " + str(ungrouped[:8-len(i[1:])])) | |
i.extend(list(ungrouped[:8-len(i[1:])])) | |
# 拿掉已經分配組別的學員學號 | |
ungrouped = ungrouped[8-len(i[1:]):] | |
except: | |
#print("no member to add!") | |
pass | |
else: | |
#print("full") | |
pass | |
# 根據增量決定組序 | |
i[0] = str(grp) | |
group.append(i) | |
grp += 1 | |
# 假如各組已經全部補滿 8 人, 但 ungrouped 仍有學員 | |
# 則依序從第一組依序補滿 | |
ord = 0 | |
#print(len(ungrouped)) | |
if len(ungrouped) > 0: | |
for i in ungrouped: | |
group[ord].append(i) | |
ord += 1 | |
#print(group) | |
# 根據最新的 group 資料更新 num_grp | |
# 先清空 num_grp | |
num_grp.clear() | |
for i in group: | |
# 組序為 element one | |
grp_order = i[0] | |
stud_list = i[1:] | |
for j in stud_list: | |
# j 為該組組員學號 | |
num_grp[j] = grp_order | |
# 列出已經完成分組的結果, 準備更新至 mdecourse/studlist | |
newstud = [] | |
print("1" + aorb + "\tgithub 帳號\t組別") | |
for i in reg_data: | |
#print(i) | |
# i 為學號 | |
try: | |
print(i + "\t" + num_github[i] + "\t" + num_grp[i]) | |
except: | |
newstud.append(i) | |
print("new: " + str(newstud)) | |
for i in group: | |
brython_div <= "第" + str(i[0]) + "組:" + html.BR() | |
grp_repo = course + aorb + "g" + str(i[0]) | |
for num in i[1:]: | |
# num 為各組組員學號 | |
#print(num) | |
studhref = "https://"+ str(num_github[num]) + ".github.io/" + course | |
repohref = "https://github.com/"+ str(num_github[num]) +"/"+course | |
grphref = "https://"+ str(num_github[num]) + ".github.io/" + grp_repo | |
grp_repohref = "https://github.com/"+ str(num_github[num]) +"/" + grp_repo | |
brython_div <= "repo: " | |
makeLink(repohref, str(num)) | |
brython_div <= " www: " | |
makeLink(studhref, str(num)) | |
brython_div <= " " + grp_repo + "-repo: " | |
makeLink(grp_repohref, str(num)) | |
brython_div <= " " + grp_repo + "-www: " | |
makeLink(grphref, str(num)) | |
brython_div <= html.BR() | |
print("done") |
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
# 程式自動猜數字遊戲 | |
from browser import document, html, alert | |
import random | |
id4 = document["brython_div"] | |
執行次數 = 100 | |
總猜測次數 = 0 | |
for i in range(執行次數): | |
id4 <= "第" + str(i+1) + "次玩:" + html.BR() | |
下限 = 1 | |
上限 = 100 | |
標準答案 = random.randint(下限, 上限) | |
pc猜的數字 = random.randint(下限, 上限) | |
#print(標準答案, pc猜的數字) | |
#integer int() | |
#string str() | |
#float float() | |
#你猜的數字 = int(input("請輸入您所猜的整數:")) | |
猜測次數 = 1 | |
while 標準答案 != pc猜的數字: | |
if 標準答案 < pc猜的數字: | |
#print("太大了,再猜一次 :)加油") | |
# 因此已經確定"pc猜的數字"不是答案, 因此 - 1 | |
id4 <= "電腦猜的數字:" + str(pc猜的數字) + " 太大了!" + html.BR() | |
上限 = pc猜的數字 - 1 | |
else: | |
#print("太小了,再猜一次 :)加油") | |
# 因此已經確定"pc猜的數字"不是答案, 因此 + 1 | |
id4 <= "電腦猜的數字:" + str(pc猜的數字) + " 太小了!" + html.BR() | |
下限 = pc猜的數字 + 1 | |
#pc猜的數字 = int(input("請輸入您所猜的整數:")) | |
pc猜的數字 = random.randint(下限, 上限) | |
猜測次數 += 1 | |
#print("猜對了!總共猜了", 猜測次數, "次") | |
id4 <= "電腦猜對了, 答案為: " + str(標準答案) + ", 總共猜了 "+ str(猜測次數) + "次" + html.BR() | |
總猜測次數 += 猜測次數 | |
平均猜測次數 = int(總猜測次數/執行次數) | |
#print("平均次數", 平均猜測次數) | |
id4 <= "平均次數: " + str(平均猜測次數) |
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
# Ggame ball example | |
from ggame import ( | |
App, | |
Color, | |
LineStyle, | |
Sprite, | |
RectangleAsset, | |
ImageAsset, | |
CircleAsset, | |
EllipseAsset, | |
PolygonAsset, | |
) | |
from browser import document as doc | |
from browser import html | |
# 引入既有的id="graphics-column" 標註 | |
graphics_column = doc["graphics-column"] | |
# 建立內定名稱為 "ggame-canvas" 的 canvas 標註 | |
canvas = html.CANVAS(width = 600, height = 100) | |
canvas.id = "ggame-canvas" | |
# 將 canvas 插入 gc 標註中 | |
graphics_column <= canvas | |
# reverse - change the ball direction | |
def reverse(b): | |
b.direction *= -1 | |
# Set up function for handling screen refresh | |
def step(): | |
if ball.go: | |
ball.x += ball.direction | |
if ball.x + ball.width > myapp.width or ball.x < 0: | |
ball.x -= ball.direction | |
reverse(ball) | |
myapp = App() | |
# Three primary colors with no transparency (alpha = 1.0) | |
red = Color(0xff0000, 1.0) | |
green = Color(0x00ff00, 1.0) | |
blue = Color(0x0000ff, 1.0) | |
black = Color(0x000000, 1.0) | |
# define colors and line style | |
green = Color(0x00ff00, 1) | |
black = Color(0, 1) | |
noline = LineStyle(0, black) | |
# a rectangle asset and sprite to use as background | |
bg_asset = RectangleAsset(canvas.width, canvas.height, noline, green) | |
bg = Sprite(bg_asset, (0,0)) | |
ball_asset = ImageAsset("/images/orb-150545_640.png") | |
ball = Sprite(ball_asset, (0, 0)) | |
# Original image is too big. Scale it to 1/10 its original size | |
ball.scale = 0.1 | |
# custom attributes | |
ball.direction = 7 | |
ball.go = True | |
myapp.run(step) |
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
# Cango 24v3 版本 Bezier 繪圖 | |
from browser import window, html | |
from browser import document as doc | |
canvas = html.CANVAS(width = 600, height = 400) | |
canvas.id = "canvas" | |
brython_div = doc["brython_div"] | |
brython_div <= canvas | |
# Javascript 物件 | |
cango = window.Cango.new | |
path = window.Path.new | |
shape = window.Shape.new | |
group = window.Group.new | |
# 24v3 circle 為 Javascript 物件 | |
circle = window.circle.new | |
g1 = cango("canvas") | |
g1.clearCanvas() | |
g1.gridboxPadding(10, 10, 5, 7) | |
g1.fillGridbox("lightgreen") | |
g1.setWorldCoordsRHC(-100, -100, 400) | |
x1 = 40 | |
y1 = 20 | |
cx1 = 90 | |
cy1 = 120 | |
x2 = 120 | |
y2 = 100 | |
cx2 = 130 | |
cy2 = 20 | |
cx3 = 150 | |
cy3 = 120 | |
x3 = 180 | |
y3 = 60 | |
def dragC1(mousePos): | |
global cx1, cy1 | |
cx1 = mousePos.x | |
cy1 = mousePos.y | |
drawCurve() | |
def dragC2(mousePos): | |
global cx2, cy2 | |
cx2 = mousePos.x | |
cy2 = mousePos.y | |
drawCurve() | |
def dragC3(mousePos): | |
global cx3, cy3 | |
cx3 = mousePos.x | |
cy3 = mousePos.y | |
drawCurve() | |
def drawCurve(): | |
qbez = path(['M', x1, y1, 'Q', cx1, cy1, x2, y2], { | |
'strokeColor':'blue'}) | |
cbez = path(['M', x2, y2, 'C', cx2, cy2, cx3, cy3, x3, y3], { | |
'strokeColor':'green'}) | |
L1 = path(['M', x1, y1, 'L', cx1, cy1, x2, y2], { | |
'strokeColor':"rgba(0, 0, 0, 0.2)", | |
'dashed':[4]}) | |
L2 = path(['M', x2, y2, 'L', cx2, cy2], { | |
'strokeColor':"rgba(0, 0, 0, 0.2)", | |
'dashed':[4]}) | |
L3 = path(['M', x3, y3, 'L', cx3, cy3], { | |
'strokeColor':"rgba(0, 0, 0, 0.2)", | |
'dashed':[4]}) | |
# 24v3 直接 translate 無需經過 tranform | |
c1.translate(cx1, cy1) | |
c2.translate(cx2, cy2) | |
c3.translate(cx3, cy3) | |
grp = group(qbez, cbez, L1, L2, L3, c1, c2, c3) | |
g1.render(grp, True) | |
g1.clearCanvas("lightyellow") | |
g1.deleteAllLayers() | |
g1.setWorldCoordsRHC(0, 0, 200) | |
c1 = shape(circle(6), {'fillColor':'red'}) | |
c1.enableDrag(None, dragC1, None) | |
c2 = shape(circle(6), {'fillColor':'red'}) | |
c2.enableDrag(None, dragC2, None) | |
c3 = shape(circle(6), {'fillColor':'red'}) | |
c3.enableDrag(None, dragC3, None); | |
drawCurve() |
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 | |
from browser import document, html, alert | |
import random | |
try: | |
total = int(input("請問要出幾張大樂透彩卷號碼?")) | |
except: | |
alert("請輸入要選擇大樂透電腦選號數量的'整數'") | |
total = int(input("請問要出幾張大樂透彩卷號碼?")) | |
# 準備將電腦選出的號碼, 輸出到內定 id="brython_div" 的標註區域 | |
output_div = document["brython_div"] | |
output_div <= "以下將出 " + str(total) + " 張電腦選號彩卷:" + html.BR() | |
for i in range(1, total + 1): | |
# 利用 list(range()) 產生 1 到 49 的 population list | |
# 然後再透過 random.sample(population, k) | |
# 從 population, 產生 k 個不同的數字 | |
numbers = random.sample(list(range(1, 49)), 6) | |
output_div <= str(i) + ". 電腦選號為: " + str(numbers) + html.BR() |
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
# 導入 sys 模組 | |
import sys | |
# 導入 keyword 模組 | |
import keyword | |
# 利用 sys 模組中的 version_info 印出 Python 版次 | |
print("Python version: ", sys.version_info) | |
# 利用 keyword 模組中的 kwlist 印出關鍵字 | |
print("Python keywords: ", keyword.kwlist) |
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
# from https://bmsleight.github.io/brython-blocks/ brython 3.3.5 to 3.9.0 | |
# original source codes: https://github.com/bmsleight/brython-blocks/ | |
# not complete | |
from browser import document, alert, html | |
from random import randint | |
# 用於定時執行特定函式 | |
import browser.timer | |
# 利用 html 建立一個 CANVAS 標註物件, 與變數 grid 對應 | |
grid = html.CANVAS(width = 0, height = 0) | |
next = html.CANVAS(width = 0, height = 0) | |
stop = html.BUTTON("Stop", id="stop") | |
detail = html.DIV(id="detail") | |
total = html.SPAN(id="total") | |
# 將 canvas 標註的 id 設為 "canvas" | |
grid.id = "grid" | |
next.id = "next" | |
# 將 document 中 id 為 "brython_div" 的標註 | |
# 設為與 brython_div 變數對應 | |
brython_div = document["brython_div"] | |
# 將 canvas 標註放入 brython_div 所在位置 | |
# 頁面中原本就已經放入 <div id="brython_div"></div> 標註 | |
brython_div <= grid + html.BR() | |
brython_div <= "Next Block" + html.BR() + next + html.BR() | |
brython_div <= detail + html.BR() | |
brython_div <= "Total Lines:" + total + html.BR() | |
brython_div <= stop +html.BR() | |
# 將頁面中 id 為 canvas 的 CANVAS 設為與 canvas 變數對應 | |
#canvas = document["grid"] | |
# Globals | |
boarder_size = 5 | |
w = 10 + boarder_size*2 | |
h = 15 + boarder_size*2 | |
block_size = 20 | |
tick_timer = None | |
lines = 0 | |
# Clash is when block + block >31 | |
CLASH = 31 | |
# Empty Blocks | |
WHITE = 0 | |
GRAY = 1 | |
BLOCK_HARD = 15 | |
# Hard Blocks | |
BOARDER = 16 | |
BOARDER_TOP = 17 | |
RED = 18 | |
BLUE = 19 | |
ORANGE = 20 | |
YELLOW = 21 | |
MAGENTA = 22 | |
CYAN = 23 | |
GREEN = 24 | |
def debug_to_browser(text): | |
debug = document["debug"] | |
debug.text = debug.text + str(text) | |
def update_lines_complete(removed): | |
global lines | |
lines = lines + removed | |
document["total"].text = lines | |
def paint_block(canvas_name, x, y, n): | |
if n == WHITE: | |
fill_style = "White" | |
elif n == GRAY: | |
fill_style = "Gray" | |
elif n == RED: | |
fill_style = "Red" | |
elif n == BLUE: | |
fill_style = "Blue" | |
elif n == ORANGE: | |
fill_style = "Orange" | |
elif n == YELLOW: | |
fill_style = "Yellow" | |
elif n == MAGENTA: | |
fill_style = "Magenta" | |
elif n == CYAN: | |
fill_style = "Cyan" | |
elif n == GREEN: | |
fill_style = "Green" | |
elif n == BOARDER: | |
fill_style = "Black" | |
elif n == BOARDER_TOP: | |
fill_style = "Pink" | |
else: | |
fill_style = "Pink" | |
if fill_style: | |
canvas=document[canvas_name].getContext("2d") | |
canvas.beginPath() | |
# Canvas 0,0 it top,left not bottom, left | |
# So we get the height and subtract our value | |
canvas.rect(x*block_size, document[canvas_name].height-y*block_size, block_size, block_size) | |
canvas.fillStyle = fill_style | |
canvas.fill() | |
class PlayingGrid(): | |
def __init__(self): | |
# This looks the wrong way around but it create an x,y array | |
self.grid = [[GRAY for x in range(w)] for y in range(h)] | |
self.set_boarder() | |
def set_boarder(self): | |
for x in range(0, w): | |
for y in range(0, boarder_size): | |
self.grid[y][x] = BOARDER | |
for x in range(0, boarder_size): | |
for y in range(0, h): | |
self.grid[y][x] = BOARDER | |
for x in range(w-boarder_size, w): | |
for y in range(0, h): | |
self.grid[y][x] = BOARDER | |
def remove_complete_lines(self, by): | |
removed = 0 | |
for row in self.grid[by:by+4]: | |
if not WHITE in row and \ | |
not GRAY in row and \ | |
not all(x == row[0] for x in row): | |
self.grid.remove(row) | |
removed = removed + 1 | |
if removed: | |
for r in range(0, removed): | |
# Need a real new row - not the same one added | |
new_row = [GRAY for x in range(w)] | |
self.grid.append(new_row) | |
update_lines_complete(removed) | |
self.set_boarder() | |
return removed | |
def draw_grid(self): | |
for x in range(0,w): | |
for y in range(0,h): | |
paint_block("grid", x, y, self.grid[y][x]) | |
class Block(): | |
def __init__(self): | |
self.style = 0 | |
self.total_styles = 7 | |
self.rotation = 0 | |
# Select a sytle by random, no rotation | |
self.style = randint(0,self.total_styles-1) | |
# Prep grid for rotating blocks | |
self.grid = [[0 for x in range(4)] for y in range(4)] | |
self.sytle_grid() | |
self.x = w/2 - 2 | |
self.y = h - boarder_size | |
def sytle_grid(self): | |
# Rotation is counter-intuitive | |
# if rotate "true", its skips left to right | |
# So we precalculate the rotations so make them better | |
#I | |
if self.style == 0 and \ | |
(self.rotation == 0 or self.rotation == 2): | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, 0, 0, 0], | |
[ RED, RED, RED, RED], | |
[ 0, 0, 0, 0]] | |
if self.style == 0 and \ | |
(self.rotation == 1 or self.rotation == 3): | |
self.grid = [[ 0, RED, 0, 0], | |
[ 0, RED, 0, 0], | |
[ 0, RED, 0, 0], | |
[ 0, RED, 0, 0]] | |
# O | |
if self.style == 1: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, BLUE, BLUE, 0], | |
[ 0, BLUE, BLUE, 0], | |
[ 0, 0, 0, 0]] | |
#S | |
if self.style == 2 and \ | |
(self.rotation == 0 or self.rotation == 2): | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, 0, ORANGE, ORANGE], | |
[ 0, ORANGE, ORANGE, 0], | |
[ 0, 0, 0, 0]] | |
if self.style == 2 and \ | |
(self.rotation == 1 or self.rotation == 3): | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, ORANGE, 0, 0], | |
[ 0, ORANGE, ORANGE, 0], | |
[ 0, 0, ORANGE, 0]] | |
#Z | |
if self.style == 3 and \ | |
(self.rotation == 0 or self.rotation == 2): | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, 0, 0, 0], | |
[ 0, YELLOW, YELLOW, 0], | |
[ 0, 0, YELLOW, YELLOW]] | |
if self.style == 3 and \ | |
(self.rotation == 1 or self.rotation == 3): | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, 0, YELLOW, 0], | |
[ 0, YELLOW, YELLOW, 0], | |
[ 0, YELLOW, 0, 0]] | |
if self.style == 4 and self.rotation == 0: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, MAGENTA, 0, 0], | |
[MAGENTA, MAGENTA, MAGENTA, 0], | |
[ 0, 0, 0, 0]] | |
if self.style == 4 and self.rotation == 1: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, MAGENTA, 0, 0], | |
[MAGENTA, MAGENTA, 0, 0], | |
[ 0, MAGENTA, 0, 0]] | |
if self.style == 4 and self.rotation == 2: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, 0, 0, 0], | |
[MAGENTA, MAGENTA, MAGENTA, 0], | |
[ 0, MAGENTA, 0, 0]] | |
if self.style == 4 and self.rotation == 3: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, MAGENTA, 0, 0], | |
[ 0, MAGENTA, MAGENTA, 0], | |
[ 0, MAGENTA, 0, 0]] | |
# L | |
if self.style == 5 and self.rotation == 0: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, 0, CYAN, 0], | |
[CYAN, CYAN, CYAN, 0], | |
[ 0, 0, 0, 0]] | |
if self.style == 5 and self.rotation == 1: | |
self.grid = [[ 0, 0, 0, 0], | |
[CYAN, CYAN, 0, 0], | |
[ 0, CYAN, 0, 0], | |
[ 0, CYAN, 0, 0]] | |
if self.style == 5 and self.rotation == 2: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, 0, 0, 0], | |
[CYAN, CYAN, CYAN, 0], | |
[CYAN, 0, 0, 0]] | |
if self.style == 5 and self.rotation == 3: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, CYAN, 0, 0], | |
[ 0, CYAN, 0, 0], | |
[ 0, CYAN, CYAN, 0]] | |
if self.style == 6 and self.rotation == 0: | |
self.grid = [[ 0, 0, 0, 0], | |
[GREEN, 0, 0, 0], | |
[GREEN, GREEN, GREEN, 0], | |
[ 0, 0, 0, 0]] | |
if self.style == 6 and self.rotation == 1: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, GREEN, 0, 0], | |
[ 0, GREEN, 0, 0], | |
[GREEN, GREEN, 0, 0]] | |
if self.style == 6 and self.rotation == 2: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, 0, 0, 0], | |
[GREEN, GREEN, GREEN, 0], | |
[ 0, 0, GREEN, 0]] | |
if self.style == 6 and self.rotation == 3: | |
self.grid = [[ 0, 0, 0, 0], | |
[ 0, GREEN, GREEN, 0], | |
[ 0, GREEN, 0, 0], | |
[ 0, GREEN, 0, 0]] | |
def rotate_anticlock(self): | |
self.rotation = self.rotation -1 | |
if self.rotation == -1: | |
self.rotation = 3 | |
self.sytle_grid() | |
def rotate_clock(self): | |
self.rotation = self.rotation +1 | |
if self.rotation == 4: | |
self.rotation = 0 | |
self.sytle_grid() | |
def paint(self, canvas_name): | |
for x in range(0,4): | |
for y in range(0,4): | |
paint_block(canvas_name, x, y, self.grid[y][x]) | |
# Replace with function ? | |
def paint_block_on_grid(): | |
print("paint_block_on_grid") | |
for x in range(-1,5): | |
for y in range(-1,5): | |
if ((x == -1 or x == 4) \ | |
or (y == -1 or y == 4)) \ | |
or (current_block.grid[y][x]<=BLOCK_HARD): | |
n = play_grid.grid[int(current_block.y + y)][int(current_block.x + x)] | |
else: | |
n = current_block.grid[y][x] | |
paint_block("grid", int(x+current_block.x), int(y+current_block.y), n) | |
def clash_blocks(): | |
print("clash_blocks") | |
clash = False | |
for x in range(0,4): | |
for y in range(0,4): | |
b = current_block.grid[y][x] + play_grid.grid[int(y+current_block.y)][int(x+current_block.x)] | |
if b>CLASH: | |
clash = True | |
return clash | |
def freeze_current_block(): | |
print("freeze_current_block") | |
for x in range(0,4): | |
for y in range(0,4): | |
if current_block.grid[y][x] > BLOCK_HARD: | |
play_grid.grid[int(y+current_block.y)][int(x+current_block.x)] = current_block.grid[y][x] | |
def test_new_position(movement): | |
if movement == "left": | |
current_block.x = current_block.x -1 | |
elif movement == "right": | |
current_block.x = current_block.x +1 | |
elif movement == "down": | |
current_block.y = current_block.y -1 | |
elif movement == "rotate_c": | |
current_block.rotate_clock() | |
else: | |
pass | |
if clash_blocks(): | |
if movement == "left": | |
current_block.x = current_block.x +1 | |
return False | |
if movement == "right": | |
current_block.x = current_block.x -1 | |
return False | |
if movement == "down": | |
current_block.y = current_block.y +1 | |
return False | |
if movement == "rotate_c": | |
current_block.rotate_anticlock() | |
return False | |
else: | |
paint_block_on_grid() | |
return True | |
def key_code(ev): | |
# Debug | |
#trace = document["traceKeyCode"] | |
#trace.text = f'event {ev.type}, keyCode : {ev.keyCode}' | |
ev.stopPropagation() | |
# Key codes for Up, Down, Left, Right, wasd | |
if ev.keyCode == 37 or ev.keyCode == 65: | |
test_new_position("left") | |
if ev.keyCode == 39 or ev.keyCode == 68: | |
test_new_position("right") | |
if ev.keyCode == 40 or ev.keyCode == 83: | |
test_new_position("down") | |
if ev.keyCode == 38 or ev.keyCode == 87: | |
test_new_position("rotate_c") | |
def stop_timer(ev): | |
browser.timer.clear_interval(tick_timer) | |
def start_timer(ev): | |
tick_timer = browser.timer.set_interval(tick, 500) | |
def tick(): | |
global current_block, next_block, play_grid | |
if not test_new_position("down"): | |
freeze_current_block() | |
play_grid.remove_complete_lines(current_block.y) | |
if not play_grid.remove_complete_lines(current_block.y) and \ | |
not current_block.y < (h - boarder_size): | |
browser.timer.clear_interval(tick_timer) | |
alert("Game Over") | |
current_block = next_block | |
next_block = Block() | |
next_block.paint("next") | |
play_grid.draw_grid() | |
def init(): | |
global tick_timer | |
element = document["grid"] | |
element.width = w*block_size | |
element.height = h*block_size | |
element = document["next"] | |
element.width = block_size*6 | |
element.height = block_size*4 | |
if not document["grid"].getContext: | |
alert('An error occured creating a Canvas 2D context. ' | |
'This may be because you are using an old browser') | |
play_grid.draw_grid() | |
update_lines_complete(0) | |
next_block.paint("next") | |
tick_timer = browser.timer.set_interval(tick, 500) | |
document["stop"].bind('click',stop_timer) | |
document.onkeydown = key_code | |
play_grid = PlayingGrid() | |
play_grid.draw_grid() | |
current_block = Block() | |
next_block = Block() | |
init() |
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
# Ggame | |
from ggame import App, ImageAsset, Sprite, MouseEvent | |
from random import random, randint | |
from browser import document as doc | |
from browser import html | |
import math | |
# 引入既有的id="graphics-column" 標註 | |
graphics_column = doc["graphics-column"] | |
# 建立內定名稱為 "ggame-canvas" 的 canvas 標註 | |
canvas = html.CANVAS(width = 600, height = 400) | |
canvas.id = "ggame-canvas" | |
# 將 canvas 插入 gc 標註中 | |
graphics_column <= canvas | |
class Bunny(Sprite): | |
asset = ImageAsset("/images/bunny.png") | |
def __init__(self, position): | |
super().__init__(Bunny.asset, position) | |
# register mouse events | |
App.listenMouseEvent(MouseEvent.mousedown, self.mousedown) | |
App.listenMouseEvent(MouseEvent.mouseup, self.mouseup) | |
App.listenMouseEvent(MouseEvent.mousemove, self.mousemove) | |
self.dragging = True | |
self.deltax = 0 | |
self.deltay = 0 | |
def step(self): | |
# Every now and then a bunny hops... | |
if random() < 0.01: | |
self.x += randint(-20,20) | |
self.y += randint(-20,20) | |
def mousedown(self, event): | |
# capture any mouse down within 50 pixels | |
self.deltax = event.x - (self.x + self.width//2) | |
self.deltay = event.y - (self.y + self.height//2) | |
if abs(self.deltax) < 50 and abs(self.deltay) < 50: | |
self.dragging = True | |
# only drag one bunny at a time - consume the event | |
event.consumed = True | |
def mousemove(self, event): | |
if self.dragging: | |
self.x = event.x - self.deltax - self.width//2 | |
self.y = event.y - self.deltay - self.height//2 | |
event.consumed = True | |
def mouseup(self, event): | |
if self.dragging: | |
self.dragging = False | |
event.consumed = True | |
class DemoApp(App): | |
def __init__(self): | |
super().__init__() | |
for i in range(5): | |
Bunny((randint(50, 600), randint(50, 400))) | |
def step(self): | |
# Override step to perform action on each frame update | |
for bunny in self.spritelist: | |
bunny.step() | |
# Create the app | |
app = DemoApp() | |
# Run the app | |
app.run() |
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
# Spur Gear in Cango and gearUtils-09.js | |
from browser import document as doc | |
from browser import html | |
from browser import window | |
import browser.timer | |
import math | |
# 利用 html 建立一個 CANVAS 標註物件, 與變數 canvas 對應 | |
canvas = html.CANVAS(width = 600, height = 400) | |
# 將 canvas 標註的 id 設為 "cango_gear" | |
canvas.id = "cango_gear" | |
# 將 document 中 id 為 "brython_div" 的標註 | |
# 設為與 brython_div 變數對應 | |
brython_div = doc["brython_div"] | |
# 將 canvas 標註放入 brython_div 所在位置 | |
brython_div <= canvas | |
# 將頁面中 id 為 cango_gear 的 CANVAS 設為與 canvas 對應 | |
canvas = doc["cango_gear"] | |
# convert Javascript objects to Brython variables | |
cango = window.Cango.new | |
circle = window.circle.new | |
shape = window.Shape.new | |
path = window.Path.new | |
creategeartooth = window.createGearTooth.new | |
svgsegs = window.SVGsegs.new | |
# 經由 Cango 轉換成 Brython 的 cango | |
# 指定將圖畫在 id="cango_gear" 的 canvas 上 | |
cgo = cango("cango_gear") | |
# 以下將要使用 gearUtils-09.js 畫出正齒輪外形 | |
# 假設齒數為 25 | |
num = 25 | |
# 利用 gearUtils-09 產生單一齒輪外形資料 | |
tooth = creategeartooth(10, num, 20) | |
# 在 Cango 中, 只有 SVG 才能 rotate, appendPath 或 joinPath | |
# 將齒輪外形轉為 SVG segment | |
toothSVG = svgsegs(tooth) | |
path1 = path(toothSVG.scale(1), {"degs": 45, "x": 100, "y": 100, "strokeColor": "#606060"}) | |
#print(path1) | |
# SVG list | |
circle = circle(50) | |
#print(circle) | |
circleSVG = svgsegs(circle) | |
#print(circleSVG) | |
# 若將 circleSVG 轉為 Cango path, 則可以用 cgo.render() | |
#circlePath = path(circleSVG, {"x": 100, "y": 100, "strokeColor": "#606060"}) | |
#cgo.render(circlePath) | |
# svgsegs 資料可以 joinPath 或 appendPath | |
# joinPath 按照頭尾順序銜接 | |
# appendPath 則無順序銜接 | |
# 從 toothSVG 複製出單齒 SVG 資料 | |
one = toothSVG.dup() | |
# 以照齒數, 逐一複製並附加在原單齒資料中 | |
# 第一齒的資料已經在 toothSVG 中, 因此重複迴圈從 1 開始 | |
for i in range(1, num): | |
newSVG = one.rotate(360*i/num) | |
toothSVG = toothSVG.appendPath(newSVG) | |
# 將 SVG 轉為 path 資料 | |
#gear = path(toothSVG, {"x": 150, "y": 150, "strokeColor": "#606060"}) | |
# path 資料可以透過 cgo.render()顯示繪圖物件 | |
#cgo.render(gear) | |
# 當 circle 接外齒使用 appendPath | |
toothSVG = toothSVG.appendPath(circleSVG) | |
#print(toothSVG) | |
spurPath = path(toothSVG, {"x": 150, "y": 150, "strokeColor": "#606060"}) | |
cgo.render(spurPath) |
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
# Spur Gear in Cango and gearUtils-09.js | |
from browser import document as doc | |
from browser import html | |
from browser import window | |
import browser.timer | |
import math | |
# 利用 html 建立一個 CANVAS 標註物件, 與變數 canvas 對應 | |
canvas = html.CANVAS(width = 600, height = 400) | |
# 將 canvas 標註的 id 設為 "cango_gear" | |
canvas.id = "cango_gear" | |
# 將 document 中 id 為 "brython_div" 的標註 | |
# 設為與 brython_div 變數對應 | |
brython_div = doc["brython_div"] | |
# 將 canvas 標註放入 brython_div 所在位置 | |
brython_div <= canvas | |
# 將頁面中 id 為 cango_gear 的 CANVAS 設為與 canvas 對應 | |
canvas = doc["cango_gear"] | |
# convert Javascript objects to Brython variables | |
cango = window.Cango.new | |
circle = window.circle.new | |
shape = window.Shape.new | |
path = window.Path.new | |
creategeartooth = window.createGearTooth.new | |
svgsegs = window.SVGsegs.new | |
# 經由 Cango 轉換成 Brython 的 cango | |
# 指定將圖畫在 id="cango_gear" 的 canvas 上 | |
cgo = cango("cango_gear") | |
# 以下將要使用 gearUtils-09.js 畫出正齒輪外形 | |
# 假設齒數為 25 | |
num = 25 | |
# 利用 gearUtils-09 產生單一齒輪外形資料 | |
tooth = creategeartooth(10, num, 20) | |
# 在 Cango 中, 只有 SVG 才能 rotate, appendPath 或 joinPath | |
# 將齒輪外形轉為 SVG segment | |
toothSVG = svgsegs(tooth) | |
path1 = path(toothSVG.scale(1), {"degs": 45, "x": 100, "y": 100, "strokeColor": "#606060"}) | |
#print(path1) | |
# SVG list | |
circle = circle(50) | |
#print(circle) | |
circleSVG = svgsegs(circle) | |
#print(circleSVG) | |
# 若將 circleSVG 轉為 Cango path, 則可以用 cgo.render() | |
#circlePath = path(circleSVG, {"x": 100, "y": 100, "strokeColor": "#606060"}) | |
#cgo.render(circlePath) | |
# svgsegs 資料可以 joinPath 或 appendPath | |
# joinPath 按照頭尾順序銜接 | |
# appendPath 則無順序銜接 | |
# 從 toothSVG 複製出單齒 SVG 資料 | |
one = toothSVG.dup() | |
# 以照齒數, 逐一複製並附加在原單齒資料中 | |
# 第一齒的資料已經在 toothSVG 中, 因此重複迴圈從 1 開始 | |
for i in range(1, num): | |
newSVG = one.rotate(360*i/num) | |
toothSVG = toothSVG.appendPath(newSVG) | |
# 將 SVG 轉為 path 資料 | |
#gear = path(toothSVG, {"x": 150, "y": 150, "strokeColor": "#606060"}) | |
# path 資料可以透過 cgo.render()顯示繪圖物件 | |
#cgo.render(gear) | |
# 當 circle 接外齒使用 appendPath | |
toothSVG = toothSVG.appendPath(circleSVG) | |
#print(toothSVG) | |
spurPath = path(toothSVG, {"x": 150, "y": 150, "strokeColor": "#606060"}) | |
cgo.render(spurPath) |
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
# Cango gearUtils-0.9.js Spur Gears | |
from browser import document as doc | |
from browser import html | |
from browser import window | |
import browser.timer | |
import math | |
canvas = html.CANVAS(width = 600, height = 400) | |
canvas.id = "cango_gear" | |
brython_div = doc["brython_div"] | |
brython_div <= canvas | |
canvas = doc["cango_gear"] | |
# 此程式採用 Cango Javascript 程式庫繪圖, 因此無需 ctx | |
#ctx = canvas.getContext("2d") | |
cango = window.Cango.new | |
path = window.Path.new | |
creategeartooth = window.createGearTooth.new | |
circle = window.circle.new | |
svgsegs = window.SVGsegs.new | |
# 經由 Cango 轉換成 Brython 的 cango, 指定將圖畫在 id="cango_gear" 的 canvas 上 | |
cgo = cango("cango_gear") | |
###################################### | |
# 畫正齒輪輪廓 | |
##################################### | |
def cangoGear(n, m, pa, x=0, y=0, color="#606060"): | |
# n 為齒數 | |
#n = 17 | |
# pa 為壓力角 | |
#pa = 25 | |
# m 為模數, 根據畫布的寬度, 計算適合的模數大小 | |
# Module = mm of pitch diameter per tooth | |
#m = 0.8*canvas.width/n | |
# pr 為節圓半徑 | |
pr = n*m/2 # gear Pitch radius | |
# generate gear data | |
data = creategeartooth(m, n, pa) | |
toothSVG = svgsegs(data) | |
toothSVG.rotate(180/n) # rotate gear 1/2 tooth to mesh | |
# 單齒的齒形資料經過旋轉後, 將資料複製到 gear 物件中 | |
one = toothSVG.dup() | |
# 利用單齒輪廓旋轉, 產生整個正齒輪外形 | |
for i in range(1, n): | |
newSVG = one.rotate(360*i/n) | |
toothSVG = toothSVG.appendPath(newSVG) | |
# 建立軸孔 | |
# add axle hole, hr 為 hole radius | |
hr = 0.6*pr # diameter of gear shaft | |
shaft = circle(hr) | |
shaftSVG = svgsegs(shaft) | |
spurSVG = toothSVG.appendPath(shaftSVG) | |
gear = path(spurSVG, {"x": x, "y": y, "strokeColor": color}) | |
return gear | |
# 設定兩齒齒數 | |
n1 = 84 | |
n2 = 18 | |
n3 = 99 | |
# 使用 80% 的畫布寬度 | |
m = 0.8*canvas.width/((n1+n2+n3)) | |
# 設定共同的壓力角 | |
pa = 25 | |
# n 齒輪的節圓半徑 | |
pr1 = n1*m/2 | |
# n2 齒輪的節圓半徑 | |
pr2 = n2*m/2 | |
pr3 = n3*m/2 | |
cx = canvas.width/2 | |
cy = canvas.height/2 | |
# Determine the coord of the middle gears | |
mcx = cx + (pr1-pr3) | |
mcy = cy | |
# 建立 gears | |
gear1 = cangoGear(n1, m, pa, color="red") | |
gear2 = cangoGear(n2, m, pa, color="green") | |
gear3 = cangoGear(n3, m, pa, color="blue") | |
deg = math.pi/180 | |
rotate_speed = 0 | |
def draw(): | |
global rotate_speed | |
rotate_speed += 5*deg | |
cgo.clearCanvas() | |
theta1 = 0+rotate_speed | |
gear1.rotate(theta1) | |
gear1.translate(mcx-(pr1+pr2), mcy) | |
cgo.render(gear1) | |
theta2 = 180+(360/n2/2)-(rotate_speed)*n1/n2 | |
gear2.rotate(theta2) | |
gear2.translate(mcx, mcy) | |
cgo.render(gear2) | |
theta3 = 180+(360/n3/2)+(180+(360/n2/2))*n2/n3+(rotate_speed*n1/n2)*(n2/n3) | |
gear3.rotate(theta3) | |
gear3.translate(mcx+(pr2+pr3), mcy) | |
cgo.render(gear3) | |
browser.timer.set_interval(draw, 2) |
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
# 清除畫布 | |
from browser import document, html | |
brython_div = document["brython_div"] | |
brython_div.clear() |
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
# clock1 in Brython - 這是單行註解 | |
# 以下則是多行註解 | |
'''Code for the clock''' | |
# Line drawing | |
# 導入 doc | |
from browser import document as doc # 從模組 browser 導入 document 並且命名為 doc | |
from browser import html # 導入 html | |
import math # 導入數學模組 | |
import time # 導入時間模組 | |
import browser.timer # 導入用來製作 animation 動態模擬用的計時器 | |
# 以下有兩種方式在頁面建立 id 為 line_drawing 的標註 | |
# 假如網頁中已經存在 id 為 line_drawing 的 canvas, 則可以直接透過 document 指定 id 名稱取用 | |
# 若網頁中沒有事先建立此一 canvas, 則可以透過 Brython 的 html 類別建立 | |
canvas = html.CANVAS(width = 300, height = 200) | |
canvas.id = "line_drawing" | |
brython_div = doc["brython_div"] | |
brython_div <= canvas | |
# 準備繪圖畫布 | |
canvas = doc["line_drawing"] | |
ctx = canvas.getContext("2d") | |
sin, cos = math.sin, math.cos | |
width, height = 200, 200 # canvas dimensions | |
ray = 100 # clock ray | |
background = "SteelBlue" | |
digits = "#fff" | |
border = "blue" | |
def needle(angle, r1, r2): | |
'''Draw a needle at specified angle in specified color. | |
r1 and r2 are percentages of clock ray. | |
''' | |
x1 = width / 2 - ray * cos(angle) * r1 | |
y1 = height / 2 - ray * sin(angle) * r1 | |
x2 = width / 2 + ray * cos(angle) * r2 | |
y2 = height / 2 + ray * sin(angle) * r2 | |
ctx.beginPath() | |
ctx.strokeStyle = "#fff" | |
ctx.moveTo(x1, y1) | |
ctx.lineTo(x2, y2) | |
ctx.stroke() | |
def set_clock(): | |
# erase clock | |
ctx.beginPath() | |
ctx.fillStyle = background | |
ctx.arc(width / 2, height / 2, ray * 0.89, 0, 2 * math.pi) | |
ctx.fill() | |
# redraw hours | |
show_hours() | |
# print day | |
now_time = time.time() | |
now = time.localtime(now_time) | |
microsecs = now_time - int(now_time) | |
day = now.tm_mday | |
ctx.font = "bold 14px Arial" | |
ctx.textAlign = "center" | |
ctx.textBaseline = "middle" | |
ctx.fillStyle = "#000" | |
ctx.fillText(day, width * 0.7, height * 0.5) | |
# draw needles for hour, minute, seconds | |
ctx.lineWidth = 2 | |
hour = now.tm_hour % 12 + now.tm_min / 60 | |
angle = hour * 2 * math.pi / 12 - math.pi / 2 | |
needle(angle, 0.05, 0.45) | |
minute = now.tm_min | |
angle = minute * 2 *math.pi / 60 - math.pi / 2 | |
needle(angle, 0.05, 0.7) | |
ctx.lineWidth = 1 | |
second = now.tm_sec + microsecs | |
angle = second * 2 * math.pi / 60 - math.pi / 2 | |
needle(angle, 0.05, 0.8) | |
def show_hours(): | |
ctx.beginPath() | |
ctx.arc(width / 2, height / 2, ray * 0.05, 0, 2 * math.pi) | |
ctx.fillStyle = digits | |
ctx.fill() | |
for i in range(1, 13): | |
angle = i * math.pi / 6 - math.pi / 2 | |
x3 = width / 2 + ray * cos(angle) * 0.82 | |
y3 = height / 2 + ray * sin(angle) * 0.82 | |
ctx.font = "18px Arial" | |
ctx.textAlign = "center" | |
ctx.textBaseline = "middle" | |
ctx.fillText(i, x3, y3) | |
# cell for day | |
ctx.fillStyle = "#fff" | |
ctx.fillRect(width * 0.65, height * 0.47, width * 0.1, height * 0.06) | |
ctx.beginPath() | |
ctx.arc(width / 2, height / 2, ray, 0, 2 * math.pi) | |
ctx.fillStyle = background | |
ctx.fill() | |
# 每 100 micro seconds (0.1 second) 執行一次 set_clock 函式 | |
browser.timer.set_interval(set_clock, 100) | |
show_hours() |
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
# Temperature Conversion | |
# Temperature Conversion | |
''' | |
C to F: Celsius to Fahrenheit Conversion Formula. To convert temperatures in degrees Celsius to Fahrenheit, multiply by 1.8 (or 9/5) and add 32. | |
To convert temperatures in degrees Fahrenheit to Celsius, subtract 32 and multiply by .5556 (or 5/9). | |
Fahrenheit = Celsius*9/5 + 32 | |
Celsium = (Fahrenheit - 32)*5/9 | |
''' | |
from browser import document, html | |
brython_div = document["brython_div"] | |
def c2f(c): | |
f = round(c*9/5 + 32, 3) | |
return "Celsiusc: "+ str(c) + " degrees = Fahrenheit: " + str(f) + " degrees" | |
def f2c(f): | |
c = round((f - 32)*5/9, 3) | |
return "Fahrenheit: "+ str(f) + " degrees = Celsiusc: " + str(c) + " degrees" | |
choice = input("c2f or f2c") | |
if choice == "c2f": | |
''' | |
c = float(input("input Celsius in degrees")) | |
print(c2f(c)) | |
''' | |
for deg in range(100): | |
brython_div <= c2f(deg) | |
brython_div <= html.BR() | |
else: | |
''' | |
f = float(input("input Fahrenheit in degrees")) | |
print(f2c(f)) | |
''' | |
for deg in range(100): | |
brython_div <= f2c(deg) | |
brython_div <= html.BR() |
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
# source: https://github.com/clarketm/mergedeep | |
from collections import Counter | |
from collections.abc import Mapping | |
from copy import deepcopy | |
from enum import Enum | |
from functools import reduce, partial | |
from typing import MutableMapping | |
class Strategy(Enum): | |
# Replace `destination` item with one from `source` (default). | |
REPLACE = 0 | |
# Combine `list`, `tuple`, `set`, or `Counter` types into one collection. | |
ADDITIVE = 1 | |
# Alias to: `TYPESAFE_REPLACE` | |
TYPESAFE = 2 | |
# Raise `TypeError` when `destination` and `source` types differ. Otherwise, perform a `REPLACE` merge. | |
TYPESAFE_REPLACE = 3 | |
# Raise `TypeError` when `destination` and `source` types differ. Otherwise, perform a `ADDITIVE` merge. | |
TYPESAFE_ADDITIVE = 4 | |
def _handle_merge_replace(destination, source, key): | |
if isinstance(destination[key], Counter) and isinstance(source[key], Counter): | |
# Merge both destination and source `Counter` as if they were a standard dict. | |
_deepmerge(destination[key], source[key]) | |
else: | |
# If a key exists in both objects and the values are `different`, the value from the `source` object will be used. | |
destination[key] = deepcopy(source[key]) | |
def _handle_merge_additive(destination, source, key): | |
# Values are combined into one long collection. | |
if isinstance(destination[key], list) and isinstance(source[key], list): | |
# Extend destination if both destination and source are `list` type. | |
destination[key].extend(deepcopy(source[key])) | |
elif isinstance(destination[key], set) and isinstance(source[key], set): | |
# Update destination if both destination and source are `set` type. | |
destination[key].update(deepcopy(source[key])) | |
elif isinstance(destination[key], tuple) and isinstance(source[key], tuple): | |
# Update destination if both destination and source are `tuple` type. | |
destination[key] = destination[key] + deepcopy(source[key]) | |
elif isinstance(destination[key], Counter) and isinstance(source[key], Counter): | |
# Update destination if both destination and source are `Counter` type. | |
destination[key].update(deepcopy(source[key])) | |
else: | |
_handle_merge[Strategy.REPLACE](destination, source, key) | |
def _handle_merge_typesafe(destination, source, key, strategy): | |
# Raise a TypeError if the destination and source types differ. | |
if type(destination[key]) is not type(source[key]): | |
raise TypeError( | |
f'destination type: {type(destination[key])} differs from source type: {type(source[key])} for key: "{key}"' | |
) | |
else: | |
_handle_merge[strategy](destination, source, key) | |
_handle_merge = { | |
Strategy.REPLACE: _handle_merge_replace, | |
Strategy.ADDITIVE: _handle_merge_additive, | |
Strategy.TYPESAFE: partial(_handle_merge_typesafe, strategy=Strategy.REPLACE), | |
Strategy.TYPESAFE_REPLACE: partial(_handle_merge_typesafe, strategy=Strategy.REPLACE), | |
Strategy.TYPESAFE_ADDITIVE: partial(_handle_merge_typesafe, strategy=Strategy.ADDITIVE), | |
} | |
def _is_recursive_merge(a, b): | |
both_mapping = isinstance(a, Mapping) and isinstance(b, Mapping) | |
both_counter = isinstance(a, Counter) and isinstance(b, Counter) | |
return both_mapping and not both_counter | |
def _deepmerge(dst, src, strategy=Strategy.REPLACE): | |
for key in src: | |
if key in dst: | |
if _is_recursive_merge(dst[key], src[key]): | |
# If the key for both `dst` and `src` are both Mapping types (e.g. dict), then recurse. | |
_deepmerge(dst[key], src[key], strategy) | |
elif dst[key] is src[key]: | |
# If a key exists in both objects and the values are `same`, the value from the `dst` object will be used. | |
pass | |
else: | |
_handle_merge.get(strategy)(dst, src, key) | |
else: | |
# If the key exists only in `src`, the value from the `src` object will be used. | |
dst[key] = deepcopy(src[key]) | |
return dst | |
def merge(destination: MutableMapping, *sources: Mapping, strategy: Strategy = Strategy.REPLACE) -> MutableMapping: | |
""" | |
A deep merge function for 🐍. | |
:param destination: The destination mapping. | |
:param sources: The source mappings. | |
:param strategy: The merge strategy. | |
:return: | |
""" | |
return reduce(partial(_deepmerge, strategy=strategy), sources, destination) | |
# test the merge function | |
a = {"keyA": 1} | |
b = {"keyB": {"sub1": 10}} | |
c = {"keyB": {"sub2": 20}} | |
merged = merge({}, a, b, c) | |
print(merged) |
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
# not complete yet | |
# STL viewer 原始檔案來自 | |
# University of Wuppertal - http://mbi-wiki.uni-wuppertal.de/wordpress/ | |
# Modified by Uli Eggersmann | |
# Binary STL 資料讀取原始作者 Oliver Marks - http://www.linux.com | |
# 原始檔案僅讀取 Text STL 零件檔案 | |
# 2011 Fall 由 KMOL 新增 Binary STL 零件檔案讀取 | |
from visual import scene, color, materials, faces, points | |
import os, struct | |
#file ="ritzel.stl" | |
file ="binary.stl" | |
scene.width = 400 | |
scene.height = 400 | |
scene.background = color.white # black | |
# 視窗標題取自 cvisual.pyd, 不可使用中文 | |
scene.title = "STLViewer in VPython" | |
print ("利用滑鼠右鍵旋轉") | |
print ("滑鼠左右鍵同時按下後移動, 可以縮放畫面") | |
# Read STL file, only use vertex-line with xyz coordinates | |
list = [] | |
#load stl file detects if the file is a text file or binary file | |
def load_stl(filename): | |
#read start of file to determine if its a binay stl file or a ascii stl file | |
fp=open(filename,'rb') | |
header=fp.read(80) | |
filetype=header[0:5] | |
# 這裡必須要能夠分辨二位元字串與文字字串 | |
#print (type(filetype)) | |
#print (filetype) | |
fp.close() | |
# for Python 3 | |
if filetype==b'solid': | |
# for Python 2 | |
#if filetype=='solid': | |
print ("讀取文字檔案格式:"+str(filename)) | |
load_text_stl(filename) | |
else: | |
print ("讀取二位元檔案格式:"+str(filename,)) | |
load_binary_stl(filename) | |
#load binary stl file check wikipedia for the binary layout of the file | |
#we use the struct library to read in and convert binary data into a format we can use | |
def load_binary_stl(filename): | |
''' | |
二位元 STL 檔案格式如下: | |
檔案標頭共有 80 個字元(bytes), 內容通常省略, 但是內容不可使用 solid, 以免與文字檔案 STL 混淆 | |
UINT8[80] – Header | |
UINT32 – Number of triangles (I:佔 4 bytes 的 unsigned integer) | |
foreach triangle | |
REAL32[3] – Normal vector (f:每一座標分量為一佔 4 bytes 的 float, 共佔 12 bytes) | |
REAL32[3] – Vertex 1 | |
REAL32[3] – Vertex 2 | |
REAL32[3] – Vertex 3 | |
UINT16 – Attribute byte count (H:兩個 bytes 的 unsigned short, 表示 attribute byte count) | |
end | |
''' | |
global list | |
fp=open(filename,'rb') | |
header=fp.read(80) | |
triangle_number = struct.unpack('I',fp.read(4))[0] | |
count=0 | |
while True: | |
try: | |
p=fp.read(12) | |
if len(p)==12: | |
n=[struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]] | |
p=fp.read(12) | |
if len(p)==12: | |
p1=[struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]] | |
list.append(p1) | |
p=fp.read(12) | |
if len(p)==12: | |
p2=[struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]] | |
list.append(p2) | |
p=fp.read(12) | |
if len(p)==12: | |
p3=[struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]] | |
list.append(p3) | |
# 使用 count 來計算三角形平面個數 | |
# triangle_number 為 STL 檔案中的三角形個數 | |
count += 1 | |
# 在前面 12*4 個 bytes 的 normal 與三個點資料後, 為 | |
# 一個 2 bytes 長的 unsigned short, 其值為零, 為 attribute | |
fp.read(2) | |
# 讀完所有三角平面後, 即跳出 while | |
if count > triangle_number: | |
break | |
except EOFError: | |
break | |
fp.close() | |
def load_text_stl(filename): | |
global list | |
for dataline in open(filename,"r").readlines(): | |
if not dataline.strip(): # skip blank lines | |
continue | |
field = dataline.split() # split with no argument makes the right place! | |
if field[0] == "vertex": | |
list.append([float(x) for x in field[1:4]]) | |
#print (list) | |
#break | |
#for x in field[1:4]: | |
#print(x) | |
load_stl(os.path.abspath('')+'/'+file) | |
# Graphics | |
model = faces(pos=list, color=(0.8,0.8,0.8), | |
material=materials.plastic) # creates triangles | |
# 請注意, 這裡並沒有使用 STL 檔案中的平面 normal, 而是利用 VPython make_normals() 產生 | |
model.make_normals() # creates plane normals | |
model.smooth(0.93) # smooths the edges | |
# = AllepunkteSTL points (pos = list, size = 3, color = Color.Black) # generates points |
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
# Line drawing | |
# 導入 doc | |
from browser import document as doc | |
from browser import html | |
import math | |
canvas = html.CANVAS(width = 300, height = 200) | |
canvas.id = "line_drawing" | |
brython_div = doc["brython_div"] | |
brython_div <= canvas | |
# 準備繪圖畫布 | |
canvas = doc["line_drawing"] | |
ctx = canvas.getContext("2d") | |
# 進行座標轉換, x 軸不變, y 軸反向且移動 canvas.height 單位光點 | |
# ctx.setTransform(1, 0, 0, -1, 0, canvas.height) | |
# 以下採用 canvas 原始座標繪圖 | |
# 設定填圖顏色 | |
ctx.fillStyle = "rgb(200,0,0)" | |
# 設定畫筆顏色 | |
ctx.strokeStyle = "rgb(0,0,200)" | |
# 乘上 deg 可轉為徑度單位 | |
deg = math.pi / 180 | |
# 建立多邊形定點位置畫線函式 | |
def star(radius, xc, yc, n): | |
#radius = 100 | |
#xc = 200 | |
#yc = 200 | |
xi = xc + radius*math.cos((360/n)*deg+90*deg) | |
yi = yc - radius*math.sin((360/n)*deg+90*deg) | |
ctx.beginPath() | |
ctx.moveTo(xi,yi) | |
for i in range(2, n+1): | |
x = xc + radius*math.cos((360/n)*deg*i+90*deg) | |
y = yc - radius*math.sin((360/n)*deg*i+90*deg) | |
ctx.lineTo(x,y) | |
# 以下利用多邊形畫線函式呼叫執行畫框線或填入顏色 | |
# 畫五邊形框線 | |
star(50, 50, 50, 5) | |
ctx.closePath() | |
ctx.stroke() | |
# 填三角形色塊 | |
star(50, 150, 50, 3) | |
ctx.closePath() | |
ctx.fill() | |
# 改變畫線顏色後, 畫七邊形框線 | |
ctx.strokeStyle = "rgb(0,200,20)" | |
star(50, 250, 50, 7) | |
ctx.closePath() | |
ctx.stroke() |
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
# 導入 Ex1 原始碼 | |
a = 0 | |
def my_print(n, input_str): | |
print("以下將重覆列印 '", input_str + "' " + str(n) + "次") | |
for i in range(n): | |
print(i, input_str) | |
my_print(5, "Hello World!") | |
the_str = "開始學習 Python" | |
num = input("請輸入要列印的次數!") | |
my_print(int(num), the_str) | |
a = a + 1 | |
print("(" + str(a) + ")", "_" * 25) | |
def myfun(): | |
yield 1 | |
yield 2 | |
yield 3 | |
for i in myfun(): | |
print(i) | |
x = iter(myfun()) | |
y = list(myfun()) | |
a = a + 1 | |
print("(" + str(a) + ")", "_" * 25) | |
print(x.__next__()) | |
print(x.__next__()) | |
print(x.__next__()) | |
print(y) |
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
# Python 的內建資料型別 | |
import math | |
def f(): | |
print("This is a user-defined function") | |
return 42 | |
print("Some basic types in Python:") | |
print(type(2)) # int | |
print(type(2.2)) # float | |
print(type("2.2")) # str (string) | |
print(type(2 < 2.2)) # bool (boolean) | |
print(type(math)) # module | |
print(type(math.tan)) # builtin_function_or_method ("function" in Brython) | |
print(type(f)) # function (user-defined function) | |
print(type(type(42))) # type | |
print("#####################################################") | |
print("And some other types we will see later in the course...") | |
print(type(Exception())) # Exception | |
print(type(range(5))) # range | |
print(type([1,2,3])) # list | |
print(type((1,2,3))) # tuple | |
print(type({1,2})) # set | |
print(type({1:42})) # dict (dictionary or map) | |
print(type(2+3j)) # complex (complex number) (we may not see this type) |
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
# Python 的內建常數與函式 | |
# 內建常數 | |
print("Some builtin constants:") | |
print(True) | |
print(False) | |
print(None) | |
print("And some more constants in the math module:") | |
import math | |
print(math.pi) | |
print(math.e) | |
# 內建函式 | |
print("Type conversion functions:") | |
print(bool(0)) # convert to boolean (True or False) | |
print(float(42)) # convert to a floating point number | |
print(int(2.8)) # convert to an integer (int) | |
print("And some basic math functions:") | |
print(abs(-5)) # absolute value | |
print(max(2,3)) # return the max value | |
print(min(2,3)) # return the min value | |
print(pow(2,3)) # raise to the given power (pow(x,y) == x**y) | |
print(round(2.354, 1)) # round with the given number of digits | |
# other examples | |
print(3 * 2) | |
print(3 * "abc") | |
print(3 + 2) | |
print("abc" + "def") | |
print(3 + "def") | |
# Type Affect Semantics | |
print(3 * 2) | |
print(3 * "abc") | |
print(3 + 2) | |
print("abc" + "def") | |
print(3 + "def") | |
# Integer Division | |
print("The / operator does 'normal' float division:") | |
print(" 5/3 =", ( 5/3)) | |
print() | |
print("The // operator does integer division:") | |
print(" 5//3 =", ( 5//3)) | |
print(" 2//3 =", ( 2//3)) | |
print("-1//3 =", (-1//3)) | |
print("-4//3 =", (-4//3)) | |
# Modulus or Remainder Operator (%) | |
print(" 6%3 =", ( 6%3)) | |
print(" 5%3 =", ( 5%3)) | |
print(" 2%3 =", ( 2%3)) | |
print(" 0%3 =", ( 0%3)) | |
print("-4%3 =", (-4%3)) | |
print(" 3%0 =", ( 3%0)) | |
# Verify that (a%b) is equivalent to (a-(a//b)*b) | |
def mod(a, b): | |
return a - (a//b)*b | |
print(41%14, mod(41,14)) | |
print(14%41, mod(14,41)) | |
print(-32%9, mod(-32,9)) | |
print(32%-9, mod(32,-9)) | |
# Operator Order (Precedence and Associativity) | |
print("Precedence:") | |
print(2+3*4) # prints 14, not 20 | |
print(5+4%3) # prints 6, not 0 (% has same precedence as *, /, and //) | |
print(2**3*4) # prints 32, not 4096 (** has higher precedence than *, /, //, and %) | |
print() | |
print("Associativity:") | |
print(5-4-3) # prints -2, not 4 (- associates left-to-right) | |
print(4**3**2) # prints 262144, not 4096 (** associates right-to-left) | |
# Approximate Values of Floating-Point Numbers | |
print(0.1 + 0.1 == 0.2) # True, but... | |
print(0.1 + 0.1 + 0.1 == 0.3) # False! | |
print(0.1 + 0.1 + 0.1) # prints 0.30000000000000004 (uh oh) | |
print((0.1 + 0.1 + 0.1) - 0.3) # prints 5.55111512313e-17 (tiny, but non-zero!) | |
# Equality Testing with math.isclose | |
print("The problem....") | |
d1 = 0.1 + 0.1 + 0.1 | |
d2 = 0.3 | |
print(d1 == d2) # False (never use == with floats!) | |
print() | |
print("The solution...") | |
import math | |
print(math.isclose(d1, d2)) # True! | |
# math.isclose checks if the two numbers are ALMOST equal, within a small error | |
# Short-Circuit Evaluation | |
def yes(): | |
return True | |
def no(): | |
return False | |
def crash(): | |
return 1/0 # crashes! | |
print(no() and crash()) # Works! | |
print(crash() and no()) # Crashes! | |
print (yes() and crash()) # Never runs (due to crash), but would also crash (without short-circuiting) | |
# Or operator | |
def yes(): | |
return True | |
def no(): | |
return False | |
def crash(): | |
return 1/0 # crashes! | |
print(yes() or crash()) # Works! | |
print(crash() or yes()) # Crashes! | |
print(no() or crash()) # Never runs (due to crash), but would also crash (without short-circuiting) | |
# more examples | |
def isPositive(n): | |
result = (n > 0) | |
print("isPositive(",n,") =", result) | |
return result | |
def isEven(n): | |
result = (n % 2 == 0) | |
print("isEven(",n,") =", result) | |
return result | |
print("Test 1: isEven(-4) and isPositive(-4))") | |
print(isEven(-4) and isPositive(-4)) # Calls both functions | |
print("----------") | |
print("Test 2: isEven(-3) and isPositive(-3)") | |
print(isEven(-3) and isPositive(-3)) # Calls only one function! | |
# type vs isinstance | |
# Both type and isinstance can be used to type-check | |
# In general, (isinstance(x, T)) will be more robust than (type(x) == T) | |
print(type("abc") == str) | |
print(isinstance("abc", str)) | |
# We'll see better reasons for this when we cover OOP + inheritance later | |
# in the course. For now, here is one reason: say you wanted to check | |
# if a value is any kind of number (int, float, complex, etc). | |
# You could do: | |
def isNumber(x): | |
return ((type(x) == int) or | |
(type(x) == float)) # are we sure this is ALL kinds of numbers? | |
print(isNumber(1), isNumber(1.1), isNumber(1+2j), isNumber("wow")) | |
# But this is cleaner, and works for all kinds of numbers, including | |
# complex numbers for example: | |
import numbers | |
def isNumber(x): | |
return isinstance(x, numbers.Number) # works for any kind of number | |
print(isNumber(1), isNumber(1.1), isNumber(1+2j), isNumber("wow")) |
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
# Python 函式 | |
# Vocabulary | |
x = 5 | |
def f(y, z): | |
result = x + y + z | |
return result | |
print(f(1, 2)) # 8 | |
print(f(3, 4)) # 12 | |
# Vocabulary: | |
# variables: global vs. local | |
# statements vs. expressions | |
# function definitions vs. function calls | |
# parameters vs. arguments | |
# Return Statements | |
# Basic example | |
def isPositive(x): | |
return (x > 0) | |
print(isPositive(5)) # True | |
print(isPositive(-5)) # False | |
print(isPositive(0)) # False | |
# Return ends the function immediately | |
def isPositive(x): | |
print("Hello!") # runs | |
return (x > 0) | |
print("Goodbye!") # does not run ("dead code") | |
print(isPositive(5)) # prints Hello, then True | |
# No return statement --> return None | |
def f(x): | |
x + 42 | |
print(f(5)) # None | |
def f2(x): | |
result = x + 42 | |
print(f2(5)) # None | |
# Print versus Return | |
# This is a common early mistake (confusing print and return): | |
def cubed(x): | |
print(x**3) # Here is the error! | |
cubed(2) # seems to work! | |
print(cubed(3)) # sort of works (but prints None, which is weird) | |
print(2*cubed(4)) # Error! | |
# Once again (correctly) | |
def cubed2(x): | |
return (x**3) # That's better! | |
cubed2(2) # seems to be ignored (why?) | |
print(cubed2(3)) # works! | |
print(2*cubed2(4)) # works! | |
# Different Parameter and Return Types | |
def hypotenuse(a, b): | |
return ((a**2) + (b**2))**0.5 | |
print(hypotenuse(3, 4)) # 5.0 (not 5) | |
print("---------------------") | |
def xor(b1, b2): | |
return ((b1 and (not b2)) or (b2 and (not b1))) # same as (b1 != b2) | |
print(xor(True, True)) # False | |
print(xor(True, False)) # True | |
print(xor(False, True)) # True | |
print(xor(False, False)) # False | |
print("---------------------") | |
def isPositive(n): | |
return (n > 0) | |
print(isPositive(10)) # True | |
print(isPositive(-1.234)) # False | |
# Function Composition | |
def f(w): | |
return 10*w | |
def g(x, y): | |
return f(3*x) + y | |
def h(z): | |
return f(g(z, f(z+1))) | |
print(h(1)) # hint: try the "visualize" feature | |
# Helper Functions | |
def onesDigit(n): | |
return n%10 | |
def largerOnesDigit(x, y): | |
return max(onesDigit(x), onesDigit(y)) | |
print(largerOnesDigit(134, 672)) # 4 | |
print(largerOnesDigit(132, 674)) # Still 4 | |
# Test Functions | |
# A broken test function | |
def onesDigit(n): | |
return n%10 | |
def testOnesDigit(): | |
print("Testing onesDigit()...", end="") | |
assert(onesDigit(5) == 5) | |
assert(onesDigit(123) == 3) | |
assert(onesDigit(100) == 0) | |
assert(onesDigit(999) == 9) | |
print("Passed!") | |
testOnesDigit() # Passed! Why is this bad? | |
# A better version | |
def onesDigit2(n): | |
return n%10 | |
def testOnesDigit2(): | |
print("Testing onesDigit()...", end="") | |
assert(onesDigit2(5) == 5) | |
assert(onesDigit2(123) == 3) | |
assert(onesDigit2(100) == 0) | |
assert(onesDigit2(999) == 9) | |
assert(onesDigit2(-123) == 3) # Added this test | |
print("Passed!") | |
testOnesDigit2() # Crashed! So the test function worked! | |
# Local Variable Scope | |
def f(x): | |
print("In f, x =", x) | |
x += 5 | |
return x | |
def g(x): | |
return f(x*2) + f(x*3) | |
print(g(2)) | |
# Another example | |
def f(x): | |
print("In f, x =", x) | |
x += 7 | |
return round(x / 3) | |
def g(x): | |
x *= 10 | |
return 2 * f(x) | |
def h(x): | |
x += 3 | |
return f(x+4) + g(x) | |
print(h(f(1))) | |
# Global Variable Scope | |
# In general, you should avoid using global variables. | |
# You will even lose style points if you use them! | |
# Still, you need to understand how they work, since others | |
# will use them, and there may also be some very few occasions | |
# where you should use them, too! | |
g = 100 | |
def f(x): | |
return x + g | |
print(f(5)) # 105 | |
print(f(6)) # 106 | |
print(g) # 100 | |
# Another exampl | |
g = 100 | |
def f(x): | |
# If we modify a global variable, we must declare it as global. | |
# Otherwise, Python will assume it is a local variable. | |
global g | |
g += 1 | |
return x + g | |
print(f(5)) # 106 | |
print(f(6)) # 108 | |
print(g) # 102 | |
# Default arguments | |
# Sometimes, a function has a parameter that has a natural default | |
# We can specify that default value in the function definition, | |
# then choose whether or not to include it in the function call. | |
def f(x, y=10): | |
return x + y | |
print(f(5)) # 15 | |
print(f(5,1)) # 6 |
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
# import from downloads/py/fibo.py | |
import fibo | |
fibo.fib(5) | |
print(fibo.fib2(5)) |
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
# make canvas 600x400 | |
from browser import document as doc | |
from browser import window | |
from browser import timer | |
from browser import html | |
import math | |
# 建立 fourbar canvas | |
canvas = html.CANVAS(width = 600, height = 400) | |
canvas.id = "fourbar1" | |
brython_div = doc["brython_div"] | |
brython_div <= canvas | |
# 準備繪圖畫布 | |
canvas = doc["fourbar1"] | |
# 建立 buttons | |
brython_div <= html.BUTTON("啟動", id="power") | |
brython_div <= html.BUTTON("反向", id="reverse") | |
# 利用 window 擷取 PrairieDraw 程式庫變數物件, 然後以 JSConstructor 函式轉為 Brython 變數 | |
pdraw = window.PrairieDraw.new | |
# 利用 window 擷取 PrairieDrawAnim 程式庫變數物件, 然後以 JSConstructor 函式轉為 Brython 變數 | |
PrairieDrawAnim = window.PrairieDrawAnim.new | |
# 利用 window 擷取 sylvester 程式庫變數物件 Vector, 並將其 create 方法直接轉為 Brython 變數 | |
# 在 sylvester 中的 $V 簡化變數無法直接在 Brython 程式中引用 | |
vector = window.Vector.create.new | |
# 在 "fourbar" 畫布中建立 panim 動態模擬案例 | |
panim = PrairieDrawAnim("fourbar1") | |
# 平面連桿繪圖以 t = 0 起始 | |
t = 0 | |
# 控制轉動方向變數 | |
direction = True | |
# 繪製不同 t 時間下的平面連桿 | |
def draw(): | |
global t, direction, fast | |
# 設定模擬繪圖範圍 | |
panim.setUnits(6, 6) | |
# 設定箭頭線寬 | |
panim.setProp("arrowLineWidthPx",2) | |
# 起始變數設定 | |
omega = 1 | |
length_bar1 = 1 | |
length_bar2 = 26/18 | |
length_bar3 = 2 | |
length_base = 40/18 | |
time = 0 | |
# 畫出地面直線 | |
G = vector([0, -0.5]) | |
panim.ground(G, vector([0, 1]), 10) | |
# 連桿長度與角度計算 | |
A = t*omega # "theta" | |
AD = length_bar1 #length of left bar | |
AB = length_base #distance between two stationary pivots | |
BC = length_bar3 #length of right bar | |
CD = length_bar2 #length of middle bar | |
BD = math.sqrt(AD*AD + AB*AB - 2*AD*AB*math.cos(A)) | |
C = math.acos((BC*BC + CD*CD - BD*BD)/(2*BC*CD)) | |
ABD = math.asin(CD * math.sin(C) / BD) | |
DBC = math.asin(AD * math.sin(A) / BD) | |
B = ABD + DBC | |
D = math.pi - B - C | |
# draw pivot | |
pivot_left = vector([AB/-2, 0]) | |
pivot_right = vector([AB/2, 0]) | |
panim.pivot(vector([pivot_left.e(1), -0.5]), pivot_left, 0.5) | |
panim.pivot(vector([pivot_right.e(1), -0.5]), pivot_right, 0.5) | |
# 儲存轉換矩陣 | |
panim.save() | |
#FIRST BAR | |
panim.translate(pivot_left) | |
panim.rotate(A) | |
panim.rod(vector([0,0]), vector([AD,0]), 0.25) | |
panim.point(vector([0,0])) | |
#SECOND BAR | |
panim.translate(vector([AD,0])) | |
panim.rotate(A*-1) #"undo" the original A rotation | |
panim.rotate(D) #rotate by D only | |
panim.rod(vector([0,0]), vector([CD,0]), 0.25) | |
panim.point(vector([0,0])) | |
#THIRD BAR | |
panim.translate(vector([CD,0])) | |
panim.rotate(math.pi+C) | |
panim.rod(vector([0,0]), vector([BC,0]), 0.25) | |
panim.point(vector([0,0])) | |
# 回復原先的轉換矩陣 | |
panim.restore() | |
panim.point(vector([pivot_right.e(1), 0])) | |
# 時間增量 | |
if direction == True: | |
t += 0.08 | |
else: | |
t += -0.08 | |
# 先畫出 t = 0 的連桿機構 | |
draw() | |
# 將 anim 設為 None | |
anim = None | |
def launchAnimation(ev): | |
global anim | |
# 初始啟動, anim 為 None | |
if anim is None: | |
# 每 0.08 秒執行一次 draw 函式繪圖 | |
anim = timer.set_interval(draw, 80) | |
# 初始啟動後, 按鈕文字轉為"暫停" | |
doc['power'].text = '暫停' | |
elif anim == 'hold': | |
# 當 anim 為 'hold' 表示曾經暫停後的啟動, 因此持續以 set_interval() 持續旋轉, 且將 power 文字轉為"暫停" | |
anim = timer.set_interval(draw, 80) | |
doc['power'].text = '暫停' | |
else: | |
# 初始啟動後, 使用者再按 power, 此時 anim 非 None 也不是 'hold', 因此會執行 clear_interval() 暫停 | |
# 且將 anim 變數設為 'hold', 且 power 文字轉為"繼續" | |
timer.clear_interval(anim) | |
anim = 'hold' | |
doc['power'].text = '繼續' | |
def reverse(ev): | |
global anim, direction | |
# 當 anim 為 hold 時, 按鈕無效 | |
if anim != "hold": | |
if direction == True: | |
direction = False | |
else: | |
direction = True | |
doc["power"].bind("click", launchAnimation) | |
doc["reverse"].bind("click", reverse) |
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
# 2a w3 grouping program, 與 2b 處理架構相同 | |
from browser import html | |
from browser import document | |
import random | |
brython_div = document["brython_div"] | |
# 根據 href 與 content 將 html 元件中的 anchor 插入頁面 | |
def makeLink(href, content): | |
brython_div <= html.A(content, href=href) | |
#brython_div <= html.BR() | |
# 2a | |
course_num = "0752" | |
# 2b | |
#course_num = "0764" | |
reg_url = "https://nfulist.herokuapp.com/?semester=1102&courseno="+ course_num + "&column=True" | |
reg_data = open(reg_url).read().split("\n")[:-1] | |
#print(reg_data) | |
aorb = "a" | |
url = "https://mde.tw/studlist/2022spring/2a.txt" | |
course = "cd2022" | |
# 從 url 讀取資料後, 以跳行符號分割資料進入數列後 | |
# 去除數列中的第一筆與最後一筆資料後可得每位學員所填的資料 | |
data = open(url).read().split("\n")[1:-1] | |
#print(data) | |
# 再以 \t 分割每位學員的資料, | |
#可以取得每位學員的學號, github 帳號與組別 | |
big = [] | |
num_github = {} | |
num_grp = {} | |
for i in data: | |
stud_no, github, grp_no = i.split("\t") | |
#print(stud_no, github, grp_no) | |
# 因為納入新成員, 所以 big 必須之後才可組成 | |
#big.append([stud_no, github, grp_no]) | |
if github != "": | |
num_github[stud_no] = github | |
else: | |
num_github[stud_no] = stud_no | |
num_grp[stud_no] = grp_no | |
#print(num_grp) | |
# 根據最新註冊資料更新 studlist 中的內容 | |
for i in reg_data: | |
# 納入新加選的學員或從 data 中移除已經退選者 | |
# 假如最新修課學員學號並不在原名單中, 則屬加選者 | |
if not(i in num_github): | |
#print(i) | |
# 先以學號作為帳號, 分組欄位空白 | |
num_github[i] = i | |
num_grp[i] = "" | |
# 因為隨後查詢 num_github 與 num_grp 會以 reg_data 為主 | |
# 在實作中可以無需從 num_github 或 num_grp 中移除退選者 | |
for i in data: | |
# 表示該 i 學號已經退選 | |
if not(i in reg_data): | |
# 將 i 學號分別從 num_gihub 與 num_grp 移除 | |
try: | |
del num_github[i] | |
del num_grp[i] | |
except: | |
# 表示沒有退選者 | |
pass | |
#print(num_github) | |
for i in reg_data: | |
big.append([i, num_github[i], num_grp[i]]) | |
#print(big) | |
# 根據每一 element 的第三個 element sort | |
big.sort(key = lambda x: x[2]) | |
# big 已經按照組別排序 | |
#print(big) | |
ungrouped = [] | |
grouped = [] | |
for i in big: | |
if i[2] == "": | |
ungrouped.append(i[0]) | |
else: | |
# 將組別放到第一位置 | |
grouped.append([i[2], i[0]]) | |
#print(grouped) | |
#print(ungrouped) | |
d = {} | |
# 逐一檢視 grouped 數列 | |
for i in grouped: | |
# 若該組序已存在 d dict 中, | |
# 則以 extend() 納入除組序之外的組員學號 | |
if i[0] in d: | |
d[i[0]].extend(i[1:]) | |
#print("i[0] in d:",i[0], "d:", d) | |
else: | |
# 若已納分組的 element 中之組序為全新組序, | |
# 則將該已納分組的 element 放入 dict 首位元素 | |
# 準備透過 extend() 納入其他組員學號 | |
d[i[0]] = i | |
#print("i i[0] not in d:", i, "d:", d) | |
#print("finally d:", d, "d.values():", d.values()) | |
group_member = list(d.values()) | |
# 針對 2a.txt 處理第一時間大組人數超過 8 人者 | |
# 將亂數留下 8 名成員, 其餘組員納入 ungrouped 數列 | |
# grouped 重新回歸空數列 | |
grouped = [] | |
for i in group_member: | |
# 連同組序大於 9 表示組員總數大於 8 | |
if len(i) > 9: | |
temp_member = i[1:] | |
# 以 shuffle 處理 temp_member | |
# 目的在隨機留下 8 位組員, 其餘納入 ungrouped | |
random.shuffle(temp_member) | |
# i[0] 為組序, temp_member[:8] 為前 8 位組員 | |
grouped.append([i[0]] + temp_member[:8]) | |
ungrouped = ungrouped + temp_member[8:] | |
else: | |
grouped.append(i) | |
#print(grouped) | |
#print(ungrouped) | |
d = {} | |
# 逐一檢視 grouped 數列 | |
for i in grouped: | |
# 若該組序已存在 d dict 中, | |
# 則以 extend() 納入除組序之外的組員學號 | |
if i[0] in d: | |
d[i[0]].extend(i[1:]) | |
#print("i[0] in d:",i[0], "d:", d) | |
else: | |
# 若已納分組的 element 中之組序為全新組序, | |
# 則將該已納分組的 element 放入 dict 首位元素 | |
# 準備透過 extend() 納入其他組員學號 | |
d[i[0]] = i | |
#print("i i[0] not in d:", i, "d:", d) | |
#print("finally d:", d, "d.values():", d.values()) | |
group_member = list(d.values()) | |
# group_member 第一位為組序, 隨後為組員學號 | |
#print(group_member) | |
random.shuffle(ungrouped) | |
#print("ungrouped:" + str(len(ungrouped))) | |
grp = 1 | |
group = [] | |
for i in group_member: | |
#print("grp " + str(i[0]) + ": num, " + str(len(i[1:]))) | |
if len(i[1:]) < 8: | |
#print("can take " + str(8 - len(i[1:])) + "members") | |
# 若仍有學員未納組, 則可根據缺額補入學員學號 | |
try: | |
#print("add " + str(ungrouped[:8-len(i[1:])])) | |
i.extend(list(ungrouped[:8-len(i[1:])])) | |
# 拿掉已經分配組別的學員學號 | |
ungrouped = ungrouped[8-len(i[1:]):] | |
except: | |
#print("no member to add!") | |
pass | |
else: | |
#print("full") | |
pass | |
# 根據增量決定組序 | |
i[0] = str(grp) | |
group.append(i) | |
grp += 1 | |
# 假如各組已經全部補滿 8 人, 但 ungrouped 仍有學員 | |
# 則依序從第一組依序補滿 | |
ord = 0 | |
#print(len(ungrouped)) | |
if len(ungrouped) > 0: | |
for i in ungrouped: | |
group[ord].append(i) | |
ord += 1 | |
#print(group) | |
# 根據最新的 group 資料更新 num_grp | |
# 先清空 num_grp | |
num_grp.clear() | |
for i in group: | |
# 組序為 element one | |
grp_order = i[0] | |
stud_list = i[1:] | |
for j in stud_list: | |
# j 為該組組員學號 | |
num_grp[j] = grp_order | |
# 列出已經完成分組的結果, 準備更新至 mdecourse/studlist | |
newstud = [] | |
print("2" + aorb + "\tgithub 帳號\t組別") | |
for i in reg_data: | |
#print(i) | |
# i 為學號 | |
try: | |
print(i + "\t" + num_github[i] + "\t" + num_grp[i]) | |
except: | |
newstud.append(i) | |
print("new: " + str(newstud)) | |
for i in group: | |
brython_div <= "第" + str(i[0]) + "組:" + html.BR() | |
grp_repo = course + aorb + "g" + str(i[0]) | |
for num in i[1:]: | |
# num 為各組組員學號 | |
#print(num) | |
studhref = "https://"+ str(num_github[num]) + ".github.io/" + course | |
repohref = "https://github.com/"+ str(num_github[num]) +"/"+course | |
grphref = "https://"+ str(num_github[num]) + ".github.io/" + grp_repo | |
grp_repohref = "https://github.com/"+ str(num_github[num]) +"/" + grp_repo | |
brython_div <= "repo: " | |
makeLink(repohref, str(num)) | |
brython_div <= " www: " | |
makeLink(studhref, str(num)) | |
brython_div <= " " + grp_repo + "-repo: " | |
makeLink(grp_repohref, str(num)) | |
brython_div <= " " + grp_repo + "-www: " | |
makeLink(grphref, str(num)) | |
brython_div <= html.BR() | |
print("done") |
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
# 2b w3 grouping program, 與 2a 處理架構相同 | |
from browser import html | |
from browser import document | |
import random | |
brython_div = document["brython_div"] | |
# 根據 href 與 content 將 html 元件中的 anchor 插入頁面 | |
def makeLink(href, content): | |
brython_div <= html.A(content, href=href) | |
#brython_div <= html.BR() | |
# 2a | |
#course_num = "0752" | |
# 2b | |
course_num = "0764" | |
reg_url = "https://nfulist.herokuapp.com/?semester=1102&courseno="+ course_num + "&column=True" | |
reg_data = open(reg_url).read().split("\n")[:-1] | |
#print(reg_data) | |
aorb = "b" | |
url = "https://mde.tw/studlist/2022spring/2b.txt" | |
course = "cd2022" | |
# 從 url 讀取資料後, 以跳行符號分割資料進入數列後 | |
# 去除數列中的第一筆與最後一筆資料後可得每位學員所填的資料 | |
data = open(url).read().split("\n")[1:-1] | |
#print(data) | |
# 再以 \t 分割每位學員的資料, | |
#可以取得每位學員的學號, github 帳號與組別 | |
big = [] | |
num_github = {} | |
num_grp = {} | |
for i in data: | |
stud_no, github, grp_no = i.split("\t") | |
#print(stud_no, github, grp_no) | |
# 因為納入新成員, 所以 big 必須之後才可組成 | |
#big.append([stud_no, github, grp_no]) | |
if github != "": | |
num_github[stud_no] = github | |
else: | |
num_github[stud_no] = stud_no | |
num_grp[stud_no] = grp_no | |
#print(num_grp) | |
# 根據最新註冊資料更新 studlist 中的內容 | |
for i in reg_data: | |
# 納入新加選的學員或從 data 中移除已經退選者 | |
# 假如最新修課學員學號並不在原名單中, 則屬加選者 | |
if not(i in num_github): | |
#print(i) | |
# 先以學號作為帳號, 分組欄位空白 | |
num_github[i] = i | |
num_grp[i] = "" | |
# 因為隨後查詢 num_github 與 num_grp 會以 reg_data 為主 | |
# 在實作中可以無需從 num_github 或 num_grp 中移除退選者 | |
for i in data: | |
# 表示該 i 學號已經退選 | |
if not(i in reg_data): | |
# 將 i 學號分別從 num_gihub 與 num_grp 移除 | |
try: | |
del num_github[i] | |
del num_grp[i] | |
except: | |
# 表示沒有退選者 | |
pass | |
#print(num_github) | |
for i in reg_data: | |
big.append([i, num_github[i], num_grp[i]]) | |
#print(big) | |
# 根據每一 element 的第三個 element sort | |
big.sort(key = lambda x: x[2]) | |
# big 已經按照組別排序 | |
#print(big) | |
ungrouped = [] | |
grouped = [] | |
for i in big: | |
if i[2] == "": | |
ungrouped.append(i[0]) | |
else: | |
# 將組別放到第一位置 | |
grouped.append([i[2], i[0]]) | |
#print(grouped) | |
#print(ungrouped) | |
d = {} | |
# 逐一檢視 grouped 數列 | |
for i in grouped: | |
# 若該組序已存在 d dict 中, | |
# 則以 extend() 納入除組序之外的組員學號 | |
if i[0] in d: | |
d[i[0]].extend(i[1:]) | |
#print("i[0] in d:",i[0], "d:", d) | |
else: | |
# 若已納分組的 element 中之組序為全新組序, | |
# 則將該已納分組的 element 放入 dict 首位元素 | |
# 準備透過 extend() 納入其他組員學號 | |
d[i[0]] = i | |
#print("i i[0] not in d:", i, "d:", d) | |
#print("finally d:", d, "d.values():", d.values()) | |
group_member = list(d.values()) | |
# 針對 2a.txt 處理第一時間大組人數超過 8 人者 | |
# 將亂數留下 8 名成員, 其餘組員納入 ungrouped 數列 | |
# grouped 重新回歸空數列 | |
grouped = [] | |
for i in group_member: | |
# 連同組序大於 9 表示組員總數大於 8 | |
if len(i) > 9: | |
temp_member = i[1:] | |
# 以 shuffle 處理 temp_member | |
# 目的在隨機留下 8 位組員, 其餘納入 ungrouped | |
random.shuffle(temp_member) | |
# i[0] 為組序, temp_member[:8] 為前 8 位組員 | |
grouped.append([i[0]] + temp_member[:8]) | |
ungrouped = ungrouped + temp_member[8:] | |
else: | |
grouped.append(i) | |
#print(grouped) | |
#print(ungrouped) | |
d = {} | |
# 逐一檢視 grouped 數列 | |
for i in grouped: | |
# 若該組序已存在 d dict 中, | |
# 則以 extend() 納入除組序之外的組員學號 | |
if i[0] in d: | |
d[i[0]].extend(i[1:]) | |
#print("i[0] in d:",i[0], "d:", d) | |
else: | |
# 若已納分組的 element 中之組序為全新組序, | |
# 則將該已納分組的 element 放入 dict 首位元素 | |
# 準備透過 extend() 納入其他組員學號 | |
d[i[0]] = i | |
#print("i i[0] not in d:", i, "d:", d) | |
#print("finally d:", d, "d.values():", d.values()) | |
group_member = list(d.values()) | |
# group_member 第一位為組序, 隨後為組員學號 | |
#print(group_member) | |
random.shuffle(ungrouped) | |
#print("ungrouped:" + str(len(ungrouped))) | |
grp = 1 | |
group = [] | |
for i in group_member: | |
#print("grp " + str(i[0]) + ": num, " + str(len(i[1:]))) | |
if len(i[1:]) < 8: | |
#print("can take " + str(8 - len(i[1:])) + "members") | |
# 若仍有學員未納組, 則可根據缺額補入學員學號 | |
try: | |
#print("add " + str(ungrouped[:8-len(i[1:])])) | |
i.extend(list(ungrouped[:8-len(i[1:])])) | |
# 拿掉已經分配組別的學員學號 | |
ungrouped = ungrouped[8-len(i[1:]):] | |
except: | |
#print("no member to add!") | |
pass | |
else: | |
#print("full") | |
pass | |
# 根據增量決定組序 | |
i[0] = str(grp) | |
group.append(i) | |
grp += 1 | |
# 假如各組已經全部補滿 8 人, 但 ungrouped 仍有學員 | |
# 則依序從第一組依序補滿 | |
ord = 0 | |
#print(len(ungrouped)) | |
if len(ungrouped) > 0: | |
for i in ungrouped: | |
group[ord].append(i) | |
ord += 1 | |
#print(group) | |
# 根據最新的 group 資料更新 num_grp | |
# 先清空 num_grp | |
num_grp.clear() | |
for i in group: | |
# 組序為 element one | |
grp_order = i[0] | |
stud_list = i[1:] | |
for j in stud_list: | |
# j 為該組組員學號 | |
num_grp[j] = grp_order | |
# 列出已經完成分組的結果, 準備更新至 mdecourse/studlist | |
newstud = [] | |
print("2" + aorb + "\tgithub 帳號\t組別") | |
for i in reg_data: | |
#print(i) | |
# i 為學號 | |
try: | |
print(i + "\t" + num_github[i] + "\t" + num_grp[i]) | |
except: | |
newstud.append(i) | |
print("new: " + str(newstud)) | |
for i in group: | |
brython_div <= "第" + str(i[0]) + "組:" + html.BR() | |
grp_repo = course + aorb + "g" + str(i[0]) | |
for num in i[1:]: | |
# num 為各組組員學號 | |
#print(num) | |
studhref = "https://"+ str(num_github[num]) + ".github.io/" + course | |
repohref = "https://github.com/"+ str(num_github[num]) +"/"+course | |
grphref = "https://"+ str(num_github[num]) + ".github.io/" + grp_repo | |
grp_repohref = "https://github.com/"+ str(num_github[num]) +"/" + grp_repo | |
brython_div <= "repo: " | |
makeLink(repohref, str(num)) | |
brython_div <= " www: " | |
makeLink(studhref, str(num)) | |
brython_div <= " " + grp_repo + "-repo: " | |
makeLink(grp_repohref, str(num)) | |
brython_div <= " " + grp_repo + "-www: " | |
makeLink(grphref, str(num)) | |
brython_div <= html.BR() | |
print("done") |
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
# 猜數字遊戲 | |
from browser import document, html, alert | |
import random | |
# 跳出文字說明視窗 | |
alert("開始玩猜數字遊戲") | |
# 利用 random 模組中的 randint 取 1~100 間的亂數 | |
標準答案 = random.randint(1, 100) | |
# 利用 input 函式視窗, 取使用者所猜的數字, 轉為整數 | |
你猜的數字 = int(input("請輸入您所猜 1~100 間的整數:")) | |
# 猜測次數起始值設為 1 | |
猜測次數 = 1 | |
# 進入重複迴圈, 直到猜對數字 | |
while 標準答案 != 你猜的數字: | |
# 根據使用者所猜的數字, 與答案比較後, 給出提示 | |
if 標準答案 < 你猜的數字: | |
alert("猜第" + str(猜測次數) + "次, 太大了,再猜 :)加油") | |
else: | |
alert("猜第" + str(猜測次數) + "次, 太小了,再猜 :)加油") | |
你猜的數字 = int(input("請輸入您所猜 1~100 間的整數:")) | |
# 猜測次數累加 | |
猜測次數 += 1 | |
# 跳出迴圈表示猜對, 給出最後文字說明視窗 | |
alert("猜對了!答案為" + str(標準答案) + ", 總共猜了" + str(猜測次數) + "次") |
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
# 從 browser 導入 html | |
from browser import html | |
# 從 browser 導入 document 並且對應為 doc | |
from browser import document as doc | |
# 導入 browser.timer | |
import browser.timer | |
# 定義一個 game() 函式 | |
def game(): | |
""" | |
利用 global 關鍵字 將 px, py 與 speed | |
設為可在函式內改變對應內容 | |
(意即, 這三個定義在函式外的全域變數, | |
在函式中分別位於等號左邊) | |
""" | |
global px, py, speed | |
ctx.clearRect(px, py, width, height) | |
ctx.fillStyle = "red" | |
if px < canvas.width/2: | |
px += speed | |
else: | |
py -= speed | |
if px < 0 or (px + width) > canvas.width: | |
speed = -speed | |
if py < 0 or (py + height) > canvas.height: | |
speed = -speed | |
ctx.fillRect(px, py, width, height) | |
""" | |
a variable declared outside of the function or | |
in global scope is known as a global variable. | |
This means that a global variable can be accessed | |
inside or outside of the function. | |
""" | |
canvas = html.CANVAS(width = 600, height = 600) | |
canvas.id = "game-board" | |
brython_div = doc["brython_div"] | |
brython_div <= canvas | |
ctx = canvas.getContext("2d") | |
px = 0 | |
py = 50 | |
width = 20 | |
height = 20 | |
speed = 2 | |
browser.timer.set_interval(game, 10) |
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
from browser import document as doc | |
from browser import timer | |
from browser import html | |
import math | |
# 建立 game-board canvas | |
canvas = html.CANVAS(width = 300, height = 300) | |
canvas.id = "game-board" | |
brython_div = doc["brython_div"] | |
brython_div <= canvas | |
ctx = canvas.getContext("2d") | |
px = 0 | |
py = 50 | |
width = 20 | |
height = 20 | |
speed = 2 | |
# 建立 button | |
brython_div <= html.BUTTON("啟動", id="power") | |
def game(): | |
global px, py, speed | |
ctx.clearRect(px, py, width, height) | |
ctx.fillStyle = "red" | |
if px < canvas.width/2: | |
px += speed | |
else: | |
py -= speed | |
if px < 0 or (px + width) > canvas.width: | |
speed = -speed | |
if py < 0 or (py + height) > canvas.height: | |
speed = -speed | |
ctx.fillRect(px, py, width, height) | |
# 將 anim 設為 None | |
anim = None | |
def launchAnimation(ev): | |
global anim | |
# 初始啟動, anim 為 None | |
if anim is None: | |
# 每 0.1 秒執行一次 draw 函式繪圖 | |
anim = timer.set_interval(game, 10) | |
# 初始啟動後, 按鈕文字轉為"暫停" | |
doc['power'].text = '暫停' | |
elif anim == 'hold': | |
# 當 anim 為 'hold' 表示曾經暫停後的啟動, 因此持續以 set_interval() 持續旋轉, 且將 power 文字轉為"暫停" | |
anim = timer.set_interval(game, 10) | |
doc['power'].text = '暫停' | |
else: | |
# 初始啟動後, 使用者再按 power, 此時 anim 非 None 也不是 'hold', 因此會執行 clear_interval() 暫停 | |
# 且將 anim 變數設為 'hold', 且 power 文字轉為"繼續" | |
timer.clear_interval(anim) | |
anim = 'hold' | |
doc['power'].text = '繼續' | |
doc["power"].bind("click", launchAnimation) |
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
from browser import document as doc | |
from browser import html | |
# get brython_div | |
brython_div = doc["brython_div"] | |
# 插入輸入表單 | |
form = html.FORM() | |
input = html.INPUT(type="text", id="input") | |
output = html.DIV(id="output") | |
form <= "Keydown: " + input + html.BR() | |
brython_div <= form + html.BR() | |
brython_div <= output + html.BR() | |
def keyCode(ev): | |
trace = doc["output"] | |
trace.text = f"event: {ev.type}, code: {ev.code}" | |
print(ev.keyCode) | |
ev.stopPropagation() | |
doc["input"].bind("keydown", keyCode) | |
#document["codeKeypress"].bind("keypress", keyCode) | |
#document["codeKeyup"].bind("keyup", keyCode) |
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
# Konva1 繪圖 | |
# 引用 https://konvajs.github.io/ 繪圖 | |
from browser import document, html, window | |
width = 600 | |
height = 400 | |
konva = window.Konva | |
# Konva 必須在 canvas 繪圖, 從上方設定, canvas id 為 "container" | |
stage = konva.Stage.new({ | |
"container": 'brython_div', | |
"width": width, | |
"height": height | |
}) | |
layer = konva.Layer.new() | |
rectX = stage.getWidth() / 2 - 50 | |
rectY = stage.getHeight() / 2 - 25 | |
box = konva.Rect.new({ | |
"x": rectX, | |
"y": rectY, | |
"width": 100, | |
"height": 50, | |
"fill": '#00D2FF', | |
"stroke": 'black', | |
"strokeWidth": 4, | |
"draggable": True | |
}) | |
def f1(): | |
document.body.style.cursor = 'pointer' | |
def f2(): | |
document.body.style.cursor = 'default' | |
# add cursor styling | |
box.on('mouseover', f1()) | |
box.on('mouseout', f2()) | |
layer.add(box) | |
stage.add(layer) |
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
# source: https://github.com/breezy-team/merge3 | |
class CantReprocessAndShowBase(Exception): | |
"""Can't reprocess and show base.""" | |
def intersect(ra, rb): | |
"""Given two ranges return the range where they intersect or None. | |
>>> intersect((0, 10), (0, 6)) | |
(0, 6) | |
>>> intersect((0, 10), (5, 15)) | |
(5, 10) | |
>>> intersect((0, 10), (10, 15)) | |
>>> intersect((0, 9), (10, 15)) | |
>>> intersect((0, 9), (7, 15)) | |
(7, 9) | |
""" | |
# preconditions: (ra[0] <= ra[1]) and (rb[0] <= rb[1]) | |
sa = max(ra[0], rb[0]) | |
sb = min(ra[1], rb[1]) | |
if sa < sb: | |
return sa, sb | |
else: | |
return None | |
def compare_range(a, astart, aend, b, bstart, bend): | |
"""Compare a[astart:aend] == b[bstart:bend], without slicing. | |
""" | |
if (aend-astart) != (bend-bstart): | |
return False | |
for ia, ib in zip(range(astart, aend), range(bstart, bend)): | |
if a[ia] != b[ib]: | |
return False | |
else: | |
return True | |
class Merge3(object): | |
"""3-way merge of texts. | |
Given BASE, OTHER, THIS, tries to produce a combined text | |
incorporating the changes from both BASE->OTHER and BASE->THIS. | |
All three will typically be sequences of lines.""" | |
def __init__(self, base, a, b, is_cherrypick=False, sequence_matcher=None): | |
"""Constructor. | |
:param base: lines in BASE | |
:param a: lines in A | |
:param b: lines in B | |
:param is_cherrypick: flag indicating if this merge is a cherrypick. | |
When cherrypicking b => a, matches with b and base do not conflict. | |
:param sequence_matcher: Sequence matcher to use (defaults to | |
difflib.SequenceMatcher) | |
""" | |
if sequence_matcher is None: | |
import difflib | |
sequence_matcher = difflib.SequenceMatcher | |
self.base = base | |
self.a = a | |
self.b = b | |
self.is_cherrypick = is_cherrypick | |
self.sequence_matcher = sequence_matcher | |
def _uses_bytes(self): | |
if len(self.a) > 0: | |
return isinstance(self.a[0], bytes) | |
elif len(self.base) > 0: | |
return isinstance(self.base[0], bytes) | |
elif len(self.b) > 0: | |
return isinstance(self.b[0], bytes) | |
else: | |
return False | |
def merge_lines(self, | |
name_a=None, | |
name_b=None, | |
name_base=None, | |
start_marker='<<<<<<<', | |
mid_marker='=======', | |
end_marker='>>>>>>>', | |
base_marker=None, | |
reprocess=False): | |
"""Return merge in cvs-like form. | |
""" | |
if base_marker and reprocess: | |
raise CantReprocessAndShowBase() | |
if self._uses_bytes(): | |
if len(self.a) > 0: | |
if self.a[0].endswith(b'\r\n'): | |
newline = b'\r\n' | |
elif self.a[0].endswith(b'\r'): | |
newline = b'\r' | |
else: | |
newline = b'\n' | |
else: | |
newline = b'\n' | |
if isinstance(start_marker, str): | |
start_marker = start_marker.encode() | |
if isinstance(end_marker, str): | |
end_marker = end_marker.encode() | |
if isinstance(mid_marker, str): | |
mid_marker = mid_marker.encode() | |
if base_marker is not None and isinstance(base_marker, str): | |
base_marker = base_marker.encode() | |
if name_a: | |
if isinstance(name_a, str): | |
name_a = name_a.encode() | |
start_marker = start_marker + b' ' + name_a | |
if name_b: | |
if isinstance(name_b, str): | |
name_b = name_b.encode() | |
end_marker = end_marker + b' ' + name_b | |
if name_base and base_marker: | |
if isinstance(name_base, str): | |
name_base = name_base.encode() | |
base_marker = base_marker + b' ' + name_base | |
else: | |
if len(self.a) > 0: | |
if self.a[0].endswith('\r\n'): | |
newline = '\r\n' | |
elif self.a[0].endswith('\r'): | |
newline = '\r' | |
else: | |
newline = '\n' | |
else: | |
newline = '\n' | |
if name_a: | |
start_marker = start_marker + ' ' + name_a | |
if name_b: | |
end_marker = end_marker + ' ' + name_b | |
if name_base and base_marker: | |
base_marker = base_marker + ' ' + name_base | |
merge_regions = self.merge_regions() | |
if reprocess is True: | |
merge_regions = self.reprocess_merge_regions(merge_regions) | |
for t in merge_regions: | |
what = t[0] | |
if what == 'unchanged': | |
for i in range(t[1], t[2]): | |
yield self.base[i] | |
elif what == 'a' or what == 'same': | |
for i in range(t[1], t[2]): | |
yield self.a[i] | |
elif what == 'b': | |
for i in range(t[1], t[2]): | |
yield self.b[i] | |
elif what == 'conflict': | |
yield start_marker + newline | |
for i in range(t[3], t[4]): | |
yield self.a[i] | |
if base_marker is not None: | |
yield base_marker + newline | |
for i in range(t[1], t[2]): | |
yield self.base[i] | |
yield mid_marker + newline | |
for i in range(t[5], t[6]): | |
yield self.b[i] | |
yield end_marker + newline | |
else: | |
raise ValueError(what) | |
def merge_annotated(self): | |
"""Return merge with conflicts, showing origin of lines. | |
Most useful for debugging merge. | |
""" | |
UNCHANGED = 'u' | |
SEP = ' | ' | |
CONFLICT_START = '<<<<\n' | |
CONFLICT_MID = '----\n' | |
CONFLICT_END = '>>>>\n' | |
WIN_A = 'a' | |
WIN_B = 'b' | |
if self._uses_bytes(): | |
UNCHANGED = UNCHANGED.encode() | |
SEP = SEP.encode() | |
CONFLICT_START = CONFLICT_START.encode() | |
CONFLICT_MID = CONFLICT_MID.encode() | |
CONFLICT_END = CONFLICT_END.encode() | |
WIN_A = WIN_A.encode() | |
WIN_B = WIN_B.encode() | |
for t in self.merge_regions(): | |
what = t[0] | |
if what == 'unchanged': | |
for i in range(t[1], t[2]): | |
yield UNCHANGED + SEP + self.base[i] | |
elif what == 'a' or what == 'same': | |
for i in range(t[1], t[2]): | |
yield WIN_A.lower() + SEP + self.a[i] | |
elif what == 'b': | |
for i in range(t[1], t[2]): | |
yield WIN_B.lower() + SEP + self.b[i] | |
elif what == 'conflict': | |
yield CONFLICT_START | |
for i in range(t[3], t[4]): | |
yield WIN_A.upper() + SEP + self.a[i] | |
yield CONFLICT_MID | |
for i in range(t[5], t[6]): | |
yield WIN_B.upper() + SEP + self.b[i] | |
yield CONFLICT_END | |
else: | |
raise ValueError(what) | |
def merge_groups(self): | |
"""Yield sequence of line groups. Each one is a tuple: | |
'unchanged', lines | |
Lines unchanged from base | |
'a', lines | |
Lines taken from a | |
'same', lines | |
Lines taken from a (and equal to b) | |
'b', lines | |
Lines taken from b | |
'conflict', base_lines, a_lines, b_lines | |
Lines from base were changed to either a or b and conflict. | |
""" | |
for t in self.merge_regions(): | |
what = t[0] | |
if what == 'unchanged': | |
yield what, self.base[t[1]:t[2]] | |
elif what == 'a' or what == 'same': | |
yield what, self.a[t[1]:t[2]] | |
elif what == 'b': | |
yield what, self.b[t[1]:t[2]] | |
elif what == 'conflict': | |
yield (what, | |
self.base[t[1]:t[2]], | |
self.a[t[3]:t[4]], | |
self.b[t[5]:t[6]]) | |
else: | |
raise ValueError(what) | |
def merge_regions(self): | |
"""Return sequences of matching and conflicting regions. | |
This returns tuples, where the first value says what kind we | |
have: | |
'unchanged', start, end | |
Take a region of base[start:end] | |
'same', astart, aend | |
b and a are different from base but give the same result | |
'a', start, end | |
Non-clashing insertion from a[start:end] | |
Method is as follows: | |
The two sequences align only on regions which match the base | |
and both descendents. These are found by doing a two-way diff | |
of each one against the base, and then finding the | |
intersections between those regions. These "sync regions" | |
are by definition unchanged in both and easily dealt with. | |
The regions in between can be in any of three cases: | |
conflicted, or changed on only one side. | |
""" | |
# section a[0:ia] has been disposed of, etc | |
iz = ia = ib = 0 | |
for (zmatch, zend, amatch, aend, bmatch, | |
bend) in self.find_sync_regions(): | |
matchlen = zend - zmatch | |
# invariants: | |
# matchlen >= 0 | |
# matchlen == (aend - amatch) | |
# matchlen == (bend - bmatch) | |
len_a = amatch - ia | |
len_b = bmatch - ib | |
# len_base = zmatch - iz | |
# invariants: | |
# assert len_a >= 0 | |
# assert len_b >= 0 | |
# assert len_base >= 0 | |
# print 'unmatched a=%d, b=%d' % (len_a, len_b) | |
if len_a or len_b: | |
# try to avoid actually slicing the lists | |
same = compare_range(self.a, ia, amatch, | |
self.b, ib, bmatch) | |
if same: | |
yield 'same', ia, amatch | |
else: | |
equal_a = compare_range(self.a, ia, amatch, | |
self.base, iz, zmatch) | |
equal_b = compare_range(self.b, ib, bmatch, | |
self.base, iz, zmatch) | |
if equal_a and not equal_b: | |
yield 'b', ib, bmatch | |
elif equal_b and not equal_a: | |
yield 'a', ia, amatch | |
elif not equal_a and not equal_b: | |
if self.is_cherrypick: | |
for node in self._refine_cherrypick_conflict( | |
iz, zmatch, ia, amatch, | |
ib, bmatch): | |
yield node | |
else: | |
yield ( | |
'conflict', iz, zmatch, ia, amatch, ib, bmatch) | |
else: | |
raise AssertionError( | |
"can't handle a=b=base but unmatched") | |
ia = amatch | |
ib = bmatch | |
iz = zmatch | |
# if the same part of the base was deleted on both sides | |
# that's OK, we can just skip it. | |
if matchlen > 0: | |
# invariants: | |
# assert ia == amatch | |
# assert ib == bmatch | |
# assert iz == zmatch | |
yield 'unchanged', zmatch, zend | |
iz = zend | |
ia = aend | |
ib = bend | |
def _refine_cherrypick_conflict(self, zstart, zend, astart, aend, bstart, | |
bend): | |
"""When cherrypicking b => a, ignore matches with b and base.""" | |
# Do not emit regions which match, only regions which do not match | |
matcher = self.sequence_matcher( | |
None, self.base[zstart:zend], self.b[bstart:bend]) | |
matches = matcher.get_matching_blocks() | |
last_base_idx = 0 | |
last_b_idx = 0 | |
last_b_idx = 0 | |
yielded_a = False | |
for base_idx, b_idx, match_len in matches: | |
# conflict_z_len = base_idx - last_base_idx | |
conflict_b_len = b_idx - last_b_idx | |
# There are no lines in b which conflict, so skip it | |
if conflict_b_len == 0: | |
pass | |
else: | |
if yielded_a: | |
yield ('conflict', | |
zstart + last_base_idx, zstart + base_idx, | |
aend, aend, bstart + last_b_idx, bstart + b_idx) | |
else: | |
# The first conflict gets the a-range | |
yielded_a = True | |
yield ( | |
'conflict', zstart + last_base_idx, zstart + base_idx, | |
astart, aend, bstart + last_b_idx, bstart + b_idx) | |
last_base_idx = base_idx + match_len | |
last_b_idx = b_idx + match_len | |
if last_base_idx != zend - zstart or last_b_idx != bend - bstart: | |
if yielded_a: | |
yield ('conflict', zstart + last_base_idx, zstart + base_idx, | |
aend, aend, bstart + last_b_idx, bstart + b_idx) | |
else: | |
# The first conflict gets the a-range | |
yielded_a = True | |
yield ('conflict', zstart + last_base_idx, zstart + base_idx, | |
astart, aend, bstart + last_b_idx, bstart + b_idx) | |
if not yielded_a: | |
yield ('conflict', zstart, zend, astart, aend, bstart, bend) | |
def reprocess_merge_regions(self, merge_regions): | |
"""Where there are conflict regions, remove the agreed lines. | |
Lines where both A and B have made the same changes are | |
eliminated. | |
""" | |
for region in merge_regions: | |
if region[0] != "conflict": | |
yield region | |
continue | |
type, iz, zmatch, ia, amatch, ib, bmatch = region | |
a_region = self.a[ia:amatch] | |
b_region = self.b[ib:bmatch] | |
matches = self.sequence_matcher( | |
None, a_region, b_region).get_matching_blocks() | |
next_a = ia | |
next_b = ib | |
for region_ia, region_ib, region_len in matches[:-1]: | |
region_ia += ia | |
region_ib += ib | |
reg = self.mismatch_region(next_a, region_ia, next_b, | |
region_ib) | |
if reg is not None: | |
yield reg | |
yield 'same', region_ia, region_len+region_ia | |
next_a = region_ia + region_len | |
next_b = region_ib + region_len | |
reg = self.mismatch_region(next_a, amatch, next_b, bmatch) | |
if reg is not None: | |
yield reg | |
@staticmethod | |
def mismatch_region(next_a, region_ia, next_b, region_ib): | |
if next_a < region_ia or next_b < region_ib: | |
return 'conflict', None, None, next_a, region_ia, next_b, region_ib | |
def find_sync_regions(self): | |
"""Return a list of sync regions, where both descendents match the base. | |
Generates a list of (base1, base2, a1, a2, b1, b2). There is | |
always a zero-length sync region at the end of all the files. | |
""" | |
ia = ib = 0 | |
amatches = self.sequence_matcher( | |
None, self.base, self.a).get_matching_blocks() | |
bmatches = self.sequence_matcher( | |
None, self.base, self.b).get_matching_blocks() | |
len_a = len(amatches) | |
len_b = len(bmatches) | |
sl = [] | |
while ia < len_a and ib < len_b: | |
abase, amatch, alen = amatches[ia] | |
bbase, bmatch, blen = bmatches[ib] | |
# there is an unconflicted block at i; how long does it | |
# extend? until whichever one ends earlier. | |
i = intersect((abase, abase+alen), (bbase, bbase+blen)) | |
if i: | |
intbase = i[0] | |
intend = i[1] | |
intlen = intend - intbase | |
# found a match of base[i[0], i[1]]; this may be less than | |
# the region that matches in either one | |
# assert intlen <= alen | |
# assert intlen <= blen | |
# assert abase <= intbase | |
# assert bbase <= intbase | |
asub = amatch + (intbase - abase) | |
bsub = bmatch + (intbase - bbase) | |
aend = asub + intlen | |
bend = bsub + intlen | |
# assert self.base[intbase:intend] == self.a[asub:aend], \ | |
# (self.base[intbase:intend], self.a[asub:aend]) | |
# assert self.base[intbase:intend] == self.b[bsub:bend] | |
sl.append((intbase, intend, | |
asub, aend, | |
bsub, bend)) | |
# advance whichever one ends first in the base text | |
if (abase + alen) < (bbase + blen): | |
ia += 1 | |
else: | |
ib += 1 | |
intbase = len(self.base) | |
abase = len(self.a) | |
bbase = len(self.b) | |
sl.append((intbase, intbase, abase, abase, bbase, bbase)) | |
return sl | |
def find_unconflicted(self): | |
"""Return a list of ranges in base that are not conflicted.""" | |
am = self.sequence_matcher( | |
None, self.base, self.a).get_matching_blocks() | |
bm = self.sequence_matcher( | |
None, self.base, self.b).get_matching_blocks() | |
unc = [] | |
while am and bm: | |
# there is an unconflicted block at i; how long does it | |
# extend? until whichever one ends earlier. | |
a1 = am[0][0] | |
a2 = a1 + am[0][2] | |
b1 = bm[0][0] | |
b2 = b1 + bm[0][2] | |
i = intersect((a1, a2), (b1, b2)) | |
if i: | |
unc.append(i) | |
if a2 < b2: | |
del am[0] | |
else: | |
del bm[0] | |
return unc | |
m3 = Merge3(['common\n', 'base\n'],['common\n', 'a\n'],['common\n', 'b\n']) | |
print(list(m3.merge_annotated())) |
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
# 威力彩電腦選號 | |
# weleadlottery | |
from browser import document, html, alert | |
import random | |
try: | |
total = int(input("請問要出幾張威力彩卷號碼?")) | |
except: | |
alert("請輸入要選擇威力彩電腦選號數量的'整數'") | |
total = int(input("請問要出幾張威力彩卷號碼?")) | |
# 準備將電腦選出的號碼, 輸出到內定 id="brython_div" 的標註區域 | |
output_div = document["brython_div"] | |
output_div <= "以下將出 " + str(total) + " 張威力彩電腦選號彩卷:" + html.BR() | |
for i in range(1, total + 1): | |
# 利用 list(range()) 產生第一區 1 到 38 , 第二區 1 到 8 的 population list | |
# 然後再透過 random.sample(population, k) | |
# 從 population, 產生 k 個不同的數字 | |
section1_numbers = random.sample(list(range(1, 38)), 6) | |
section2_number = random.sample(list(range(1, 8)), 1) | |
output_div <= str(i) + ". 電腦選號第一區為: " + str(section1_numbers) + html.BR() | |
output_div <= ". 電腦選號第二區為: " + str(section2_number) + html.BR() |
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
# from https://levelup.gitconnected.com/writing-tetris-in-python-2a16bddb5318 | |
# 暫時關閉 system proxy 設定後, pip install pygame | |
#import pygame | |
import random | |
# 以下為 Brython 新增 | |
from browser import document as doc | |
from browser import html | |
import browser.timer | |
# 利用 html 建立一個 CANVAS 標註物件, 與變數 canvas 對應 | |
canvas = html.CANVAS(width = 400, height = 500, id="canvas") | |
brython_div = doc["brython_div"] | |
brython_div <= canvas | |
ctx = canvas.getContext("2d") | |
colors = [ | |
(0, 0, 0), | |
(120, 37, 179), | |
(100, 179, 179), | |
(80, 34, 22), | |
(80, 134, 22), | |
(180, 34, 22), | |
(180, 34, 122), | |
] | |
class Figure: | |
x = 0 | |
y = 0 | |
figures = [ | |
[[1, 5, 9, 13], [4, 5, 6, 7]], | |
[[4, 5, 9, 10], [2, 6, 5, 9]], | |
[[6, 7, 9, 10], [1, 5, 6, 10]], | |
[[1, 2, 5, 9], [0, 4, 5, 6], [1, 5, 9, 8], [4, 5, 6, 10]], | |
[[1, 2, 6, 10], [5, 6, 7, 9], [2, 6, 10, 11], [3, 5, 6, 7]], | |
[[1, 4, 5, 6], [1, 4, 5, 9], [4, 5, 6, 9], [1, 5, 6, 9]], | |
[[1, 2, 5, 6]], | |
] | |
def __init__(self, x, y): | |
self.x = x | |
self.y = y | |
self.type = random.randint(0, len(self.figures) - 1) | |
self.color = random.randint(1, len(colors) - 1) | |
self.rotation = 0 | |
def image(self): | |
return self.figures[self.type][self.rotation] | |
def rotate(self): | |
self.rotation = (self.rotation + 1) % len(self.figures[self.type]) | |
class Tetris: | |
level = 2 | |
score = 0 | |
state = "start" | |
field = [] | |
height = 0 | |
width = 0 | |
x = 100 | |
y = 60 | |
zoom = 20 | |
figure = None | |
def __init__(self, height, width): | |
self.height = height | |
self.width = width | |
self.field = [] | |
self.score = 0 | |
self.state = "start" | |
for i in range(height): | |
new_line = [] | |
for j in range(width): | |
# 起始時每一個都填入 0 | |
new_line.append(0) | |
self.field.append(new_line) | |
def new_figure(self): | |
self.figure = Figure(3, 0) | |
def intersects(self): | |
intersection = False | |
for i in range(4): | |
for j in range(4): | |
if i * 4 + j in self.figure.image(): | |
# block 到達底部, 左右兩邊界, 或該座標有其他 block | |
if i + self.figure.y > self.height - 1 or \ | |
j + self.figure.x > self.width - 1 or \ | |
j + self.figure.x < 0 or \ | |
self.field[i + self.figure.y][j + self.figure.x] > 0: | |
intersection = True | |
return intersection | |
def break_lines(self): | |
lines = 0 | |
for i in range(1, self.height): | |
zeros = 0 | |
for j in range(self.width): | |
if self.field[i][j] == 0: | |
zeros += 1 | |
if zeros == 0: | |
lines += 1 | |
for i1 in range(i, 1, -1): | |
for j in range(self.width): | |
self.field[i1][j] = self.field[i1 - 1][j] | |
self.score += lines ** 2 | |
def go_space(self): | |
while not self.intersects(): | |
self.figure.y += 1 | |
self.figure.y -= 1 | |
self.freeze() | |
def go_down(self): | |
self.figure.y += 1 | |
if self.intersects(): | |
self.figure.y -= 1 | |
self.freeze() | |
def freeze(self): | |
for i in range(4): | |
for j in range(4): | |
if i * 4 + j in self.figure.image(): | |
self.field[i + self.figure.y][j + self.figure.x] = self.figure.color | |
self.break_lines() | |
self.new_figure() | |
if self.intersects(): | |
self.state = "gameover" | |
def go_side(self, dx): | |
old_x = self.figure.x | |
self.figure.x += dx | |
if self.intersects(): | |
self.figure.x = old_x | |
def rotate(self): | |
old_rotation = self.figure.rotation | |
self.figure.rotate() | |
if self.intersects(): | |
self.figure.rotation = old_rotation | |
# Define some colors | |
# from https://stackoverflow.com/questions/3380726/converting-a-rgb-color-tuple-to-a-six-digit-code | |
BLACK = '#%02x%02x%02x' % (0, 0, 0) | |
WHITE = '#%02x%02x%02x' % (255, 255, 255) | |
GRAY = '#%02x%02x%02x' % (128, 128, 128) | |
done = False | |
fps = 25 | |
game = Tetris(20, 10) | |
counter = 0 | |
pressing_down = False | |
def key_down(eve): | |
key = eve.keyCode | |
#if event.type == pygame.QUIT: | |
# 32 is pause | |
if key == 32: | |
done = True | |
# 82 is r key to rotate | |
if key == 82: | |
game.rotate() | |
# 40 is down key | |
if key == 40: | |
pressing_down = True | |
# 37 is left key | |
if key == 37: | |
game.go_side(-1) | |
# 39 is right key | |
if key == 39: | |
game.go_side(1) | |
# 68 is d key to move block to bottom | |
if key == 68: | |
game.go_space() | |
# 27 is escape | |
# reset the game | |
if key == 27: | |
game.__init__(20, 10) | |
def key_up(eve): | |
key = eve.keyCode | |
# 40 is down key | |
if key == 40: | |
pressing_down = False | |
#while not done: | |
def do_game(): | |
global counter | |
if game.figure is None: | |
game.new_figure() | |
counter += 1 | |
if counter > 100000: | |
counter = 0 | |
if counter % (fps // game.level // 2) == 0 or pressing_down: | |
if game.state == "start": | |
game.go_down() | |
for i in range(game.height): | |
for j in range(game.width): | |
ctx.fillStyle = WHITE | |
#ctx.scale(game.zoom, game.zoom) | |
ctx.fillRect(game.x + game.zoom * j, game.y + game.zoom * i, game.zoom, game.zoom) | |
if game.field[i][j] > 0: | |
ctx.fillStyle = '#%02x%02x%02x' % colors[game.field[i][j]] | |
ctx.fillRect(game.x + game.zoom * j + 1, game.y + game.zoom * i + 1, game.zoom - 2, game.zoom - 1) | |
ctx.lineWidth = 1 | |
ctx.strokeStyle = GRAY | |
ctx.beginPath() | |
ctx.rect(game.x + game.zoom * j, game.y + game.zoom * i, game.zoom, game.zoom) | |
ctx.stroke() | |
if game.figure is not None: | |
for i in range(4): | |
for j in range(4): | |
p = i * 4 + j | |
if p in game.figure.image(): | |
ctx.fillStyle = '#%02x%02x%02x' % colors[game.figure.color] | |
ctx.fillRect(game.x + game.zoom * (j + game.figure.x) + 1, | |
game.y + game.zoom * (i + game.figure.y) + 1, | |
game.zoom - 2, game.zoom - 2) | |
doc.addEventListener("keydown", key_down) | |
doc.addEventListener("keyup", key_up) | |
browser.timer.set_interval(do_game, fps) |
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
# Cango gearUtils-0.9.js Spur Gears | |
from browser import document as doc | |
from browser import html | |
from browser import window | |
import browser.timer | |
import math | |
canvas = html.CANVAS(width = 600, height = 400) | |
canvas.id = "cango_gear" | |
brython_div = doc["brython_div"] | |
brython_div <= canvas | |
canvas = doc["cango_gear"] | |
# 此程式採用 Cango Javascript 程式庫繪圖, 因此無需 ctx | |
#ctx = canvas.getContext("2d") | |
cango = window.Cango.new | |
path = window.Path.new | |
creategeartooth = window.createGearTooth.new | |
circle = window.circle.new | |
svgsegs = window.SVGsegs.new | |
# 經由 Cango 轉換成 Brython 的 cango, 指定將圖畫在 id="cango_gear" 的 canvas 上 | |
cgo = cango("cango_gear") | |
###################################### | |
# 畫正齒輪輪廓 | |
##################################### | |
def cangoGear(n, m, pa, x=0, y=0, color="#606060"): | |
# n 為齒數 | |
#n = 17 | |
# pa 為壓力角 | |
#pa = 25 | |
# m 為模數, 根據畫布的寬度, 計算適合的模數大小 | |
# Module = mm of pitch diameter per tooth | |
#m = 0.8*canvas.width/n | |
# pr 為節圓半徑 | |
pr = n*m/2 # gear Pitch radius | |
# generate gear data | |
data = creategeartooth(m, n, pa) | |
toothSVG = svgsegs(data) | |
toothSVG.rotate(180/n) # rotate gear 1/2 tooth to mesh | |
# 單齒的齒形資料經過旋轉後, 將資料複製到 gear 物件中 | |
one = toothSVG.dup() | |
# 利用單齒輪廓旋轉, 產生整個正齒輪外形 | |
for i in range(1, n): | |
newSVG = one.rotate(360*i/n) | |
toothSVG = toothSVG.appendPath(newSVG) | |
# 建立軸孔 | |
# add axle hole, hr 為 hole radius | |
hr = 0.6*pr # diameter of gear shaft | |
shaft = circle(hr) | |
shaftSVG = svgsegs(shaft) | |
spurSVG = toothSVG.appendPath(shaftSVG) | |
gear = path(spurSVG, {"x": x, "y": y, "strokeColor": color}) | |
return gear | |
# 設定兩齒齒數 | |
n1 = 84 | |
n2 = 18 | |
n3 = 99 | |
# 使用 80% 的畫布寬度 | |
m = 0.8*canvas.width/((n1+n2+n3)) | |
# 設定共同的壓力角 | |
pa = 25 | |
# n 齒輪的節圓半徑 | |
pr1 = n1*m/2 | |
# n2 齒輪的節圓半徑 | |
pr2 = n2*m/2 | |
pr3 = n3*m/2 | |
cx = canvas.width/2 | |
cy = canvas.height/2 | |
# Determine the coord of the middle gears | |
mcx = cx + (pr1-pr3) | |
mcy = cy | |
# 建立 gears | |
gear1 = cangoGear(n1, m, pa, color="red") | |
gear2 = cangoGear(n2, m, pa, color="green") | |
gear3 = cangoGear(n3, m, pa, color="blue") | |
deg = math.pi/180 | |
rotate_speed = 0 | |
def draw(): | |
global rotate_speed | |
rotate_speed += 5*deg | |
cgo.clearCanvas() | |
theta1 = 0+rotate_speed | |
gear1.rotate(theta1) | |
gear1.translate(mcx-(pr1+pr2), mcy) | |
cgo.render(gear1) | |
theta2 = 180+(360/n2/2)-(rotate_speed)*n1/n2 | |
gear2.rotate(theta2) | |
gear2.translate(mcx, mcy) | |
cgo.render(gear2) | |
theta3 = 180+(360/n3/2)+(180+(360/n2/2))*n2/n3+(rotate_speed*n1/n2)*(n2/n3) | |
gear3.rotate(theta3) | |
gear3.translate(mcx+(pr2+pr3), mcy) | |
cgo.render(gear3) | |
browser.timer.set_interval(draw, 2) |
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
# Draw single Spur Gear | |
from browser import document as doc | |
from browser import html | |
import math | |
# 利用 Brython 建立 canvas 標註元件 | |
canvas = html.CANVAS(width = 600, height = 400) | |
# 將此 canvas 的 id 設為 "spur" | |
canvas.id = "gear" | |
# 將 brython_div 變數設為 id 為 "brython_div 的 doc 物件 | |
brython_div = doc["brython_div"] | |
# 將此 canvas 物件插入網頁 | |
brython_div <= canvas | |
# 利用 canvas 代表 id="spur" 標註元件 | |
# 表示要將 ctx 2d 繪圖至 canvas | |
canvas = doc["gear"] | |
ctx = canvas.getContext("2d") | |
# 插入輸入表單 | |
form = html.FORM() | |
gearNumInput = html.INPUT(type="text", id="gearnum", value="23") | |
button = html.BUTTON("設定齒數", id="set_num") | |
form <= "齒數: " + gearNumInput + html.BR() | |
brython_div <= form + button + html.BR() | |
#print(html.BUTTON("設定齒數", id="set_num").outerHTML) | |
# 以下建立正齒輪繪圖物件與設定齒數函式 | |
# deg 為角度轉為徑度的轉換因子 | |
deg = math.pi/180. | |
# 定義 Spur 類別 | |
class Spur: | |
def __init__(self, ctx): | |
self.ctx = ctx | |
def create_line(self, x1, y1, x2, y2, width=1, fill="red"): | |
self.ctx.beginPath() | |
self.ctx.lineWidth = width | |
self.ctx.moveTo(x1, y1) | |
self.ctx.lineTo(x2, y2) | |
self.ctx.strokeStyle = fill | |
self.ctx.stroke() | |
# 定義一個繪正齒輪的繪圖函式 | |
# midx 為齒輪圓心 x 座標 | |
# midy 為齒輪圓心 y 座標 | |
# rp 為節圓半徑, n 為齒數 | |
# pa 為壓力角 (deg) | |
# rot 為旋轉角 (deg) | |
# 針對 n 大於等於 52 齒時 base circle 與齒根圓大小必須進行判斷 | |
def Gear(self, midx, midy, rp, n=20, pa=20, color="black"): | |
# 齒輪漸開線分成 15 線段繪製 | |
imax = 15 | |
# 在輸入的畫布上繪製直線, 由圓心到節圓 y 軸頂點畫一直線 | |
self.create_line(midx, midy, midx, midy-rp) | |
# a 為模數 (代表公制中齒的大小), 模數為節圓直徑(稱為節徑)除以齒數 | |
# 模數也就是齒冠大小 | |
a=2*rp/n | |
# d 為齒根大小, 為模數的 1.157 或 1.25倍, 這裡採 1.25 倍 | |
d=2.5*rp/n | |
# ra 為齒輪的外圍半徑 | |
ra=rp+a | |
# rb 則為齒輪的基圓半徑 | |
# 基圓為漸開線長齒之基準圓 | |
rb=rp*math.cos(pa*deg) | |
# rd 為齒根圓半徑 | |
rd=rp-d | |
# 當 rd 大於 rb 時, 漸開線並非畫至 rb, 而是 rd | |
# dr 則為基圓到齒頂圓半徑分成 imax 段後的每段半徑增量大小 | |
# 將圓弧分成 imax 段來繪製漸開線 | |
# 當 rd 大於 rb 時, 漸開線並非畫至 rb, 而是 rd | |
if rd>rb: | |
dr = (ra-rd)/imax | |
else: | |
dr=(ra-rb)/imax | |
# tan(pa*deg)-pa*deg 為漸開線函數 | |
sigma=math.pi/(2*n)+math.tan(pa*deg)-pa*deg | |
for j in range(n): | |
ang=-2.*j*math.pi/n+sigma | |
ang2=2.*j*math.pi/n+sigma | |
lxd=midx+rd*math.sin(ang2-2.*math.pi/n) | |
lyd=midy-rd*math.cos(ang2-2.*math.pi/n) | |
for i in range(imax+1): | |
# 當 rd 大於 rb 時, 漸開線並非畫至 rb, 而是 rd | |
if rd>rb: | |
r=rd+i*dr | |
else: | |
r=rb+i*dr | |
theta=math.sqrt((r*r)/(rb*rb)-1.) | |
alpha=theta-math.atan(theta) | |
xpt=r*math.sin(alpha-ang) | |
ypt=r*math.cos(alpha-ang) | |
xd=rd*math.sin(-ang) | |
yd=rd*math.cos(-ang) | |
# i=0 時, 繪線起點由齒根圓上的點, 作為起點 | |
if(i==0): | |
last_x = midx+xd | |
last_y = midy-yd | |
# 由左側齒根圓作為起點, 除第一點 (xd,yd) 齒根圓上的起點外, 其餘的 (xpt,ypt)則為漸開線上的分段點 | |
self.create_line((midx+xpt),(midy-ypt),(last_x),(last_y),fill=color) | |
# 最後一點, 則為齒頂圓 | |
if(i==imax): | |
lfx=midx+xpt | |
lfy=midy-ypt | |
last_x = midx+xpt | |
last_y = midy-ypt | |
# the line from last end of dedendum point to the recent | |
# end of dedendum point | |
# lxd 為齒根圓上的左側 x 座標, lyd 則為 y 座標 | |
# 下列為齒根圓上用來近似圓弧的直線 | |
self.create_line((lxd),(lyd),(midx+xd),(midy-yd),fill=color) | |
for i in range(imax+1): | |
# 當 rd 大於 rb 時, 漸開線並非畫至 rb, 而是 rd | |
if rd>rb: | |
r=rd+i*dr | |
else: | |
r=rb+i*dr | |
theta=math.sqrt((r*r)/(rb*rb)-1.) | |
alpha=theta-math.atan(theta) | |
xpt=r*math.sin(ang2-alpha) | |
ypt=r*math.cos(ang2-alpha) | |
xd=rd*math.sin(ang2) | |
yd=rd*math.cos(ang2) | |
# i=0 時, 繪線起點由齒根圓上的點, 作為起點 | |
if(i==0): | |
last_x = midx+xd | |
last_y = midy-yd | |
# 由右側齒根圓作為起點, 除第一點 (xd,yd) 齒根圓上的起點外, 其餘的 (xpt,ypt)則為漸開線上的分段點 | |
self.create_line((midx+xpt),(midy-ypt),(last_x),(last_y),fill=color) | |
# 最後一點, 則為齒頂圓 | |
if(i==imax): | |
rfx=midx+xpt | |
rfy=midy-ypt | |
last_x = midx+xpt | |
last_y = midy-ypt | |
# lfx 為齒頂圓上的左側 x 座標, lfy 則為 y 座標 | |
# 下列為齒頂圓上用來近似圓弧的直線 | |
self.create_line(lfx,lfy,rfx,rfy,fill=color) | |
# 以 button 驅動的事件函式 | |
def setgearnumber(e): | |
global ctx | |
ctx.clearRect(0, 0, canvas.width, canvas.height) | |
x = (canvas.width)/2 | |
y = (canvas.height)/2 | |
if doc["gearnum"].value.isdigit(): | |
n1 = int(doc["gearnum"].value) | |
else: | |
n1= 26 | |
# 設定齒輪參數 | |
x = (canvas.width)/2 | |
y = (canvas.height)/2 | |
r = 0.8*(canvas.height/2) | |
pa = 20 | |
# 繪出正齒輪 | |
spur = Spur(ctx) | |
spur.Gear(x, y, r, n1, pa, "blue") | |
#判定 button | |
setgearnumber(True) | |
doc['set_num'].bind('click',setgearnumber) |
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
# try to generate binary or ascii stl part file and shown on browser - not complete yet | |
import struct | |
class StLFacet: | |
def __init__(self, normal, v1, v2, v3, att_bc=0): | |
self.coords = [normal, v1, v2, v3] | |
self.att_bc = att_bc | |
class StL: | |
def __init__(self, header): | |
self.header = header | |
self.facets = [] | |
def add_facet(self, facet): | |
self.facets.append(facet) | |
def get_binary(self): | |
# 原先 2.0 的版本 | |
#out = ['%-80.80s' % self.header] | |
# 改為 Python 3.0 格式 | |
# 第一行標頭的格式 | |
header = ['%-80.80s' % self.header][0] | |
# 利用 bytes() 將標頭字串轉為二位元資料 | |
out = [bytes(header,encoding="utf-8")] | |
# 接著則計算三角形面的數量, 並以二位元長整數格式存檔 | |
out.append(struct.pack('L',len(self.facets))) | |
# 接著則依照法線向量與三個點座標的格式, 分別以浮點數格式進行資料附加 | |
for f in self.facets: | |
for coord in f.coords: | |
out.append(struct.pack('3f', *coord)) | |
# att_bc 則內定為 0 | |
out.append(struct.pack('H', f.att_bc)) | |
return b"".join(out) | |
def test(): | |
stl=StL('Header ...') | |
stl.add_facet(StLFacet((0.,0.,1.),(0.,0.,0.),(1.,0.,0.),(0.,1.,0.))) | |
stl.add_facet(StLFacet((0.,0.,1.),(1.,0.,0.),(1.,1.,0.),(0.,1.,0.))) | |
# 第二個平面 | |
stl.add_facet(StLFacet((0.,-1.,0.),(0.,0.,0.),(0.,0.,-1.),(1.,0.,-1.))) | |
stl.add_facet(StLFacet((0.,-1.,0.),(0.,0.,0.),(1.,0.,-1.),(1.,0.,0.))) | |
return stl.get_binary() | |
# 指定存為 binary 格式檔案 | |
#stlfile = open("test.stl", "wb") | |
stlcontent = test() | |
#stlfile.write(stlcontent) | |
# 以下將 binary stlcontent 轉為 ASCII stl | |
normals = [] | |
points = [] | |
triangles = [] | |
triangle_number = 0 | |
def load_binary_stl(fp): | |
''' | |
二位元 STL 檔案格式如下: | |
檔案標頭共有 80 個字元(bytes), 內容通常省略, 但是內容不可使用 solid, 以免與文字檔案 STL 混淆 | |
UINT8[80] – Header | |
UINT32 – Number of triangles (I:佔 4 bytes 的 unsigned integer) | |
foreach triangle | |
REAL32[3] – Normal vector (f:每一座標分量為一佔 4 bytes 的 float, 共佔 12 bytes) | |
REAL32[3] – Vertex 1 | |
REAL32[3] – Vertex 2 | |
REAL32[3] – Vertex 3 | |
UINT16 – Attribute byte count (H:兩個 bytes 的 unsigned short, 表示 attribute byte count) | |
end | |
''' | |
# 已經在外部開檔 | |
#fp=open(filename,'rb') | |
header=fp.read(80) | |
triangle_number = struct.unpack('I',fp.read(4))[0] | |
#print(triangle_number) | |
count=0 | |
while True: | |
try: | |
p=fp.read(12) | |
if len(p)==12: | |
n=[struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]] | |
normals.append(n) | |
l = len(points) | |
#print(n) | |
p=fp.read(12) | |
if len(p)==12: | |
p1=[struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]] | |
points.append(p1) | |
#print(p1) | |
p=fp.read(12) | |
if len(p)==12: | |
p2=[struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]] | |
points.append(p2) | |
p=fp.read(12) | |
if len(p)==12: | |
p3=[struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]] | |
points.append(p3) | |
triangles.append((l, l+1, l+2)) | |
# 使用 count 來計算三角形平面個數 | |
# triangle_number 為 STL 檔案中的三角形個數 | |
count += 1 | |
#print(count) | |
# 在前面 12*4 個 bytes 的 normal 與三個點資料後, 為 | |
# 一個 2 bytes 長的 unsigned short, 其值為零, 為 attribute | |
fp.read(2) | |
# 讀完所有三角平面後, 即跳出 while | |
if count > triangle_number: | |
break | |
except EOFError: | |
break | |
#fp.close() | |
def read_length(f): | |
length = struct.unpack("@i", f.read(4)) | |
return length[0] | |
def read_header(f): | |
f.seek(f.tell()+80) | |
def write_as_ascii(outfilename): | |
f = open(outfilename, "w") | |
f.write ("solid "+outfilename+"\n") | |
for n in range(len(triangles)): | |
f.write ("facet normal {} {} {}\n".format(normals[n][0],normals[n][1],normals[n][2])) | |
f.write ("outer loop\n") | |
f.write ("vertex {} {} {}\n".format(points[triangles[n][0]][0],points[triangles[n][0]][1],points[triangles[n][0]][2])) | |
f.write ("vertex {} {} {}\n".format(points[triangles[n][1]][0],points[triangles[n][1]][1],points[triangles[n][1]][2])) | |
f.write ("vertex {} {} {}\n".format(points[triangles[n][2]][0],points[triangles[n][2]][1],points[triangles[n][2]][2])) | |
f.write ("endloop\n") | |
f.write ("endfacet\n") | |
f.write ("endsolid "+outfilename+"\n") | |
f.close() | |
infilename = "ss1.stl" | |
outfilename = "ss2.stl" | |
try: | |
f = open(infilename, "rb") | |
#read_header(f) | |
#l = read_length(f) | |
try: | |
load_binary_stl(f) | |
l = len(normals) | |
except Exception as e: | |
print("Exception",e) | |
print(len(normals), len(points), len(triangles), l) | |
write_as_ascii(outfilename) | |
print("done") | |
except Exception as e: | |
print(e) |
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
# http://mde.tw/2016fallcadp/blog/2016fall-dian-nao-fu-zhu-she-ji-shi-xi-ke-cheng-zong-jie-yi.html | |
#coding:utf-8 | |
# source: http://code.activestate.com/recipes/578246-stl-writer/ | |
import struct | |
ASCII_FACET = """facet normal 0 0 0 | |
outer loop | |
vertex {face[0][0]:.4f} {face[0][1]:.4f} {face[0][2]:.4f} | |
vertex {face[1][0]:.4f} {face[1][1]:.4f} {face[1][2]:.4f} | |
vertex {face[2][0]:.4f} {face[2][1]:.4f} {face[2][2]:.4f} | |
endloop | |
endfacet | |
""" | |
BINARY_HEADER ="80sI" | |
BINARY_FACET = "12fH" | |
class ASCII_STL_Writer: | |
""" Export 3D objects build of 3 or 4 vertices as ASCII STL file. | |
""" | |
def __init__(self, stream): | |
self.fp = stream | |
self._write_header() | |
def _write_header(self): | |
self.fp.write("solid python\n") | |
def close(self): | |
self.fp.write("endsolid python\n") | |
def _write(self, face): | |
self.fp.write(ASCII_FACET.format(face=face)) | |
def _split(self, face): | |
p1, p2, p3, p4 = face | |
return (p1, p2, p3), (p3, p4, p1) | |
def add_face(self, face): | |
""" Add one face with 3 or 4 vertices. """ | |
if len(face) == 4: | |
face1, face2 = self._split(face) | |
self._write(face1) | |
self._write(face2) | |
elif len(face) == 3: | |
self._write(face) | |
else: | |
raise ValueError('only 3 or 4 vertices for each face') | |
def add_faces(self, faces): | |
""" Add many faces. """ | |
for face in faces: | |
self.add_face(face) | |
class Binary_STL_Writer(ASCII_STL_Writer): | |
""" Export 3D objects build of 3 or 4 vertices as binary STL file. | |
""" | |
def __init__(self, stream): | |
self.counter = 0 | |
super(Binary_STL_Writer, self).__init__(stream) | |
def close(self): | |
self._write_header() | |
def _write_header(self): | |
self.fp.seek(0) | |
self.fp.write(struct.pack(BINARY_HEADER, b'Python Binary STL Writer', self.counter)) | |
def _write(self, face): | |
self.counter += 1 | |
data = [ | |
0., 0., 0., | |
face[0][0], face[0][1], face[0][2], | |
face[1][0], face[1][1], face[1][2], | |
face[2][0], face[2][1], face[2][2], | |
0 | |
] | |
self.fp.write(struct.pack(BINARY_FACET, *data)) | |
def example(): | |
def get_cube(): | |
# cube corner points | |
s = 3. | |
p1 = (0, 0, 0) | |
p2 = (0, 0, s) | |
p3 = (0, s, 0) | |
p4 = (0, s, s) | |
p5 = (s, 0, 0) | |
p6 = (s, 0, s) | |
p7 = (s, s, 0) | |
p8 = (s, s, s) | |
# define the 6 cube faces | |
# faces just lists of 3 or 4 vertices | |
return [ | |
[p1, p5, p7, p3], | |
[p1, p5, p6, p2], | |
[p5, p7, p8, p6], | |
[p7, p8, p4, p3], | |
[p1, p3, p4, p2], | |
[p2, p6, p8, p4], | |
] | |
''' | |
for writing ASCII STL cube file | |
with open('cube_ascii.stl', 'w') as fp: | |
writer = ASCII_STL_Writer(fp) | |
writer.add_faces(get_cube()) | |
writer.close() | |
''' | |
with open('cube_bin.stl', 'wb') as fp: | |
writer = Binary_STL_Writer(fp) | |
writer.add_faces(get_cube()) | |
writer.close() | |
if __name__ == '__main__': | |
example() |
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
# Turtle1 繪圖 | |
from browser import window, html | |
from browser import document as doc | |
import turtle | |
turtle.set_defaults( | |
turtle_canvas_wrapper = doc['brython_div'] | |
) | |
t = turtle.Turtle() | |
t.width(5) | |
for c in ['red', '#00ff00', '#fa0', 'rgb(0,0,200)']: | |
t.color(c) | |
t.forward(100) | |
t.left(90) | |
# dot() and write() do not require the pen to be down | |
t.penup() | |
t.goto(-30, -100) | |
t.dot(40, 'rgba(255, 0, 0, 0.5') | |
t.goto(30, -100) | |
t.dot(40, 'rgba(0, 255, 0, 0.5') | |
t.goto(0, -70) | |
t.dot(40, 'rgba(0, 0, 255, 0.5') | |
t.goto(0, 125) | |
t.color('purple') | |
t.write("這就是 Brython, 網頁上的 Python", font=("Arial", 15, "normal")) | |
turtle.done() |
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
# Turtle2 繪圖 | |
from browser import document as doc | |
import turtle | |
turtle.set_defaults( | |
turtle_canvas_wrapper = doc['brython_div'] | |
) | |
star = turtle.Turtle() | |
for i in range(5): | |
star.forward(250) | |
star.right(144) | |
turtle.done() |
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
# Turtle3 繪圖 | |
# https://michael0x2a.com/blog/turtle-examples | |
from browser import document as doc | |
import turtle | |
turtle.set_defaults( | |
turtle_canvas_wrapper = doc['brython_div'] | |
) | |
painter = turtle.Turtle() | |
painter.pencolor("blue") | |
for i in range(50): | |
painter.forward(50) | |
painter.left(123) # Let's go counterclockwise this time | |
painter.pencolor("red") | |
for i in range(50): | |
painter.forward(100) | |
painter.left(123) | |
turtle.done() |
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
# Turtle4 繪圖 | |
# https://docs.python.org/3.7/library/turtle.html?highlight=turtle | |
# https://fiftyexamples.readthedocs.io/en/latest/turtle.html | |
from browser import document as doc | |
import turtle | |
turtle.set_defaults( | |
turtle_canvas_wrapper = doc['brython_div'] | |
) | |
# 輸入 "turtle" 字串, 表示要使用內建的烏龜圖示 | |
t = turtle.Turtle("turtle") | |
# 設定繪圖尺寸 | |
screen_x = 500-20 | |
screen_y = 300 | |
# 提筆, 將烏龜移動到畫布中心 | |
t.penup() | |
t.home() | |
# 內定方向為右, 前進 screen_x/2 | |
t.forward(screen_x / 2) | |
# 將方向往右轉 90 度 | |
t.right(90) | |
# 此時方向向下, 前進 screen_y/2 | |
t.forward(screen_y / 2) | |
# 令烏龜方向轉絕對角度 180, 等同轉相對角度 90 度, 即 t.right(90) | |
t.setheading(180) | |
# 將畫筆顏色設為紅色 | |
t.pencolor('red') | |
# 下筆準備繪圖 | |
t.pendown() | |
# 設筆寬度為 10 | |
t.pensize(10) | |
# 進入重複迴圈, 此時方向向右, 分別 | |
# 前進 screen_x, 之後轉 90 度, 方向朝上 | |
# 再前進 screen_y, 之後再轉 90 度, 方向朝右 | |
# 再前進 screen_x, 之後轉 90 度, 方向朝下 | |
# 最後再前進 screen_y 後, 將方向轉為向左 | |
for distance in (screen_x, screen_y, screen_x, screen_y): | |
t.forward(distance) | |
t.right(90) | |
# 提筆後, 將烏龜轉回內定方向回到畫布中心 | |
t.penup() | |
t.home() | |
# 完成 turtle 繪圖 | |
turtle.done() |
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
# Turtle5 繪圖 | |
# https://brython.info/gallery/turtle.html | |
from browser import document as doc | |
import turtle | |
import math | |
turtle.set_defaults( | |
turtle_canvas_wrapper = doc['brython_div'] | |
) | |
t = turtle.Turtle("turtle") | |
t.speed(1) | |
t.forward(50) | |
print("Should be (50, 0):", t.position()) | |
print("Should be 50: ", t.xcor()) | |
print("Should be 0: ", t.ycor()) | |
t.left(90) | |
t.color("blue") | |
t.speed(2) | |
t.fd(50) | |
print("Should be (50, 50):", t.pos()) | |
print("Should be 225: ", t.towards(0, 0)) | |
print("Should be 90: ", t.heading()) | |
print("Should be approximately 71:", t.distance(0, 0)) | |
# Draw the same square in three different angle modes | |
t.width(4) | |
print("Drawing using degrees - the default") | |
print("Heading should be 90: ", t.heading()) | |
for i in range(4): | |
t.forward(100) | |
t.left(90) | |
print("Drawing using radians") | |
t.radians() | |
print("Heading should be pi/2: ", t.heading()) | |
for i in range(4): | |
t.forward(100) | |
t.left(math.pi/2) | |
print("Drawing using gradients") | |
t.degrees(400) | |
print("Heading should be 100: ", t.heading()) | |
for i in range(4): | |
t.forward(100) | |
t.left(100) | |
t.degrees() | |
t.width(1) | |
t.lt(90) | |
t.color("orange") | |
t.backward(50) | |
t.right(90) | |
t.color("green") | |
t.back(50) | |
t.rt(90) | |
t.color("red") | |
t.bk(50) | |
t.stamp() | |
t.speed(4) | |
t.color("black", "white") | |
t.goto(-100, 100) | |
t.stamp() | |
t.color("blue", "yellow") | |
t.setposition(0, 100) | |
t.stamp() | |
t.color("green", "white") | |
t.setpos(100, 100) | |
t.stamp() | |
t.speed(10) | |
t.color("orange") | |
t.sety(-100) | |
t.setx(-100) | |
t.stamp() | |
t.color("cyan") | |
t.home() | |
t.stamp() | |
t.color("green") | |
t.width(4) | |
t.setheading(180) | |
t.forward(150) | |
t.seth(90) | |
t.fd(20) | |
t.dot(30, "rgba(255, 0, 0, 0.2)") | |
t.color("red") | |
t.speed(0) | |
t.forward(30) | |
t.left(90) | |
t.circle(30) | |
turtle.done() |
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
# Turtle6 繪圖 | |
from browser import document as doc | |
import turtle | |
import math | |
turtle.set_defaults( | |
turtle_canvas_wrapper = doc['brython_div'] | |
) | |
t = turtle.Turtle("turtle") | |
t.speed(10) | |
colors = ['red', 'purple', 'blue', 'green', 'orange'] | |
for x in range(150): | |
t.pencolor(colors[x % 5]) | |
t.width(x/10 + 1) | |
t.forward(x) | |
t.left(59) | |
turtle.done() |
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
# Turtle7 繪圖 | |
from browser import document as doc | |
import turtle | |
import math | |
turtle.set_defaults( | |
turtle_canvas_wrapper = doc['brython_div'] | |
) | |
screen=turtle.Screen() #making a canvas for drawing | |
screen.bgcolor('black') #making canvas black | |
trtl=turtle.Turtle() #making a turtle | |
trtl.pencolor('red') #making colour of the pen red | |
trtl.pensize(5) #choosing the size of pen nib | |
trtl.speed(10) #choosing the speed of drawing | |
# shape should be ‘arrow’, ‘classic’, ‘turtle’ or ‘circle’ | |
trtl.shape('turtle') #choosing the shape of pen nib | |
trtl.forward(150) #drawing a line of 150 pixels | |
trtl.right(90) #asking turtle to turn 90 degrees | |
trtl.forward(150) #drawing a line of 150 pixels | |
trtl.penup() # preparing for moving pen without drawing | |
trtl.setpos(-140,-120) # making the new position of the turtle | |
trtl.pendown() # bringing the pen down for drawing again | |
trtl.pencolor('green') # choosin the pen colour as green | |
trtl.write('Brython 烏龜繪圖', font=("Arial", 20, "bold")) # chosing the font | |
trtl.penup() | |
trtl.ht() # hiding the turtle from the screen | |
turtle.done() |
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
# Turtle8 繪圖 | |
from browser import document as doc | |
import turtle | |
import math | |
turtle.set_defaults( | |
turtle_canvas_wrapper = doc['brython_div'] | |
) | |
wn = turtle.Screen() | |
wn.bgcolor("black") | |
skk = turtle.Turtle() | |
skk.speed(10) | |
skk.shape("circle") | |
skk.color("blue") | |
def sqrfunc(size): | |
for i in range(4): | |
skk.fd(size) | |
skk.left(90) | |
size = size-5 | |
sqrfunc(146) | |
sqrfunc(126) | |
sqrfunc(106) | |
sqrfunc(86) | |
sqrfunc(66) | |
sqrfunc(46) | |
sqrfunc(26) | |
turtle.done() |
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
# for acos, atan2 and sin | |
import math | |
import sys | |
# radian to degree | |
deg = 180/math.pi | |
# link 1 length | |
a1 = 10 | |
# link 2 length | |
a2 = 10 | |
# derivated based up https://www.youtube.com/watch?v=IKOGwoJ2HLk&t=311s | |
def ik(x, y): | |
# (x, y) need to be located inside the circle with radius a1+a2 | |
if (x**2 + y**2) <= (a1+ a2)**2: | |
q2 = -math.acos((x**2+y**2-a1**2-a2**2)/(2*a1*a2)) | |
q1 = math.atan2(y, x) + math.atan2((a2*math.sin(q2)), (a1+a2*math.cos(q2))) | |
# The decimal point of number is rounded to the 4th place | |
return [round(q1*deg, 4), round(q2*deg, 4)] | |
else: | |
print("Over range!") | |
# end the script execution | |
sys.exit() | |
theta = ik(15, 1) | |
print(theta[0], theta[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
# 2a w3 grouping program, 與 2b 處理架構相同 | |
from browser import html | |
from browser import document | |
import random | |
brython_div = document["brython_div"] | |
# 根據 href 與 content 將 html 元件中的 anchor 插入頁面 | |
def makeLink(href, content): | |
brython_div <= html.A(content, href=href) | |
#brython_div <= html.BR() | |
aorb = "a" | |
url = "https://mde.tw/studlist/2022spring/2a.txt" | |
course = "cd2022" | |
# 從 url 讀取資料後, 以跳行符號分割資料進入數列後 | |
# 去除數列中的第一筆與最後一筆資料後可得每位學員所填的資料 | |
data = open(url).read().split("\n")[1:-1] | |
#print(data) | |
# 再以 \t 分割每位學員的資料, | |
#可以取得每位學員的學號, github 帳號與組別 | |
big = [] | |
num_github = {} | |
num_grp = {} | |
for i in data: | |
stud_no, github, grp_no = i.split("\t") | |
#print(stud_no, github, grp_no) | |
big.append([stud_no, github, grp_no]) | |
if github != "": | |
num_github[stud_no] = github | |
else: | |
num_github[stud_no] = stud_no | |
num_grp[stud_no] = grp_no | |
#print(big) | |
# 根據每一 element 的第三個 element sort | |
big.sort(key = lambda x: x[2]) | |
# big 已經按照組別排序 | |
#print(big) | |
grouped = [] | |
for i in big: | |
grouped.append([i[2], i[0]]) | |
#print(grouped) | |
d = {} | |
# 逐一檢視 grouped 數列 | |
for i in grouped: | |
# 若該組序已存在 d dict 中, | |
# 則以 extend() 納入除組序之外的組員學號 | |
if i[0] in d: | |
d[i[0]].extend(i[1:]) | |
#print("i[0] in d:",i[0], "d:", d) | |
else: | |
# 若已納分組的 element 中之組序為全新組序, | |
# 則將該已納分組的 element 放入 dict 首位元素 | |
# 準備透過 extend() 納入其他組員學號 | |
d[i[0]] = i | |
#print("i i[0] not in d:", i, "d:", d) | |
#print("finally d:", d, "d.values():", d.values()) | |
group_member = list(d.values()) | |
# group_member 第一位為組序, 隨後為組員學號 | |
#print(group_member) | |
for i in group_member: | |
brython_div <= "第" + str(i[0]) + "組:" + html.BR() | |
grp_repo = course + aorb + "g" + str(i[0]) | |
for num in i[1:]: | |
# num 為各組組員學號 | |
#print(num) | |
studhref = "https://"+ str(num_github[num]) + ".github.io/" + course | |
repohref = "https://github.com/"+ str(num_github[num]) +"/"+course | |
grphref = "https://"+ str(num_github[num]) + ".github.io/" + grp_repo | |
grp_repohref = "https://github.com/"+ str(num_github[num]) +"/" + grp_repo | |
brython_div <= "repo: " | |
makeLink(repohref, str(num)) | |
brython_div <= " www: " | |
makeLink(studhref, str(num)) | |
brython_div <= " " + grp_repo + "-repo: " | |
makeLink(grp_repohref, str(num)) | |
brython_div <= " " + grp_repo + "-www: " | |
makeLink(grphref, str(num)) | |
brython_div <= html.BR() | |
print("done") |
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
# 參考: https://usefulangle.com/post/352/javascript-capture-image-from-camera | |
# 參考: https://usefulangle.com/post/353/javascript-canvas-image-upload | |
from browser import html, document, window | |
# 建立 video tag, 並且插入既有的 brython_div 標註中 | |
# autoplay=True for phone camera, 480X640 for iphone | |
videotag = html.VIDEO(autoplay=True,id='video', width='480', height='640') | |
# 建立 canvas tag | |
canvas = html.CANVAS(width = 480, height = 640, id="canvas") | |
# 建立 button tag | |
button = html.BUTTON("Save Image", id="save") | |
# 分別將上列 tags 插入 id="brython_div" 之位置 | |
brython_div = document['brython_div'] | |
brython_div <= videotag + html.BR() | |
brython_div <= button + html.BR() | |
brython_div <= canvas | |
ctx = canvas.getContext("2d") | |
# 定義 OnSuccess 函式在 video 標註中播放 Webcam 串流影像 | |
def OnSuccess(stream): | |
video = document['video'] | |
video.srcObject = stream | |
video.play() | |
# 透過瀏覽器取得使用者同意後傳送 Webcam 串流資料 | |
# 'facingMode': 'environment' for rear camera | |
window.navigator.mediaDevices.getUserMedia( | |
{"video": {"facingMode": 'environment'}, "audio": False} | |
).then(OnSuccess) | |
# 建立儲存串流影像至圖檔函式 | |
def save_image(e): | |
#print(canvas.width) | |
video = document['video'] | |
ctx.drawImage(video, 0, 0, canvas.width, canvas.height) | |
image_data_url = canvas.toDataURL('image/jpeg') | |
print(image_data_url) | |
# click id="save" 按鈕後, 執行 save_image | |
# 此 image_data_url 可以用於將影像檔案送到 server | |
document["save"].bind("click", save_image) |
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
# Brython websocket example | |
""" | |
# Python WebSocket server | |
# pip install asyncio websockets | |
import asyncio | |
import websockets | |
async def hello(websocket, path): | |
name = await websocket.recv() | |
print(f"< {name}") | |
greeting = f"Hello {name}!" | |
await websocket.send(greeting) | |
print(f"> {greeting}") | |
start_server = websockets.serve(hello, "localhost", 8765) | |
asyncio.get_event_loop().run_until_complete(start_server) | |
asyncio.get_event_loop().run_forever() | |
""" | |
from browser import document | |
from browser import html, window, websocket | |
# 將 brython_div 變數設為 id 為 "brython_div 的 doc 物件 | |
brython_div = document["brython_div"] | |
# 插入輸入表單 | |
form = html.FORM() | |
gearNumInput = html.INPUT(type="text", id="data", value="特斯拉") | |
button = html.BUTTON("Run Websocket", id="run") | |
button3 = html.BUTTON("Close Connection", id="close") | |
form <= "Name: " + gearNumInput + html.BR() | |
brython_div <= form + button + html.BR() | |
brython_div <= button3 + html.BR() | |
def on_open(evt): | |
# Web Socket is connected, send data using send() | |
data = document["data"].value | |
if data: | |
ws.send(data) | |
alert("Message is sent") | |
def on_message(evt): | |
# message received from server | |
alert("Message received : %s" %evt.data) | |
def on_close(evt): | |
# websocket is closed | |
alert("Connection is closed") | |
ws = None | |
def _test(_): | |
global ws | |
# open a web socket | |
# ws 為一般連線, wss 為 secure 連線 | |
ws = websocket.WebSocket("ws://localhost:8765") | |
# attach functions to web sockets events | |
ws.bind("open", on_open) | |
ws.bind("message", on_message) | |
ws.bind("close", on_close) | |
def close_connection(_): | |
ws.close() | |
def hello(ev): | |
alert("Hello !") | |
# 假如不導入 websocket, 也可以執行 Javascript 的 WebSocket | |
#websocket = window.WebSocket.new | |
document["run"].bind("click", _test) | |
document["close"].bind("click", close_connection) |
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
# Ycombinator quicksort example | |
Y = lambda f: lambda *args: f(Y(f))(*args) | |
quicksort = Y(lambda f: | |
lambda x: ( | |
f([item for item in x if item < x[0]]) | |
+ [y for y in x if x[0] == y] | |
+ f([item for item in x if item > x[0]]) | |
) if x else []) | |
print(quicksort([1, 3, 5, 4, 1, 3, 2])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment