Turtle Graphics 烏龜繪圖 Turtle Graphics改為 DA在 IoTtalk 假裝成 Ball-trow1    
  複習 Recursive function       網頁上挑選顏色複製#十六進位代碼       Color picker    
  * 「刻意練習」是一種專注、一致並且以目標為導向的訓練,它重質量而不是數量。  
Tkinter OnLine with Python 3
Trinker.io - Interactive Python Anywhere(這好像比較快)

  REPL.it 線上撰寫與執行Python; 進入選 start coding > Python > Create REPL
*** 以下 DAI777.py 是 整合 Turtle Graphics 與 DAI2.py (Dummy Device)
      ==> 成為 IoTtalk 的 DA, 假裝為 Ball-throw1 (你可以試著自己建立新 DM 搭配任何 Turtle Graphics)

06/23 課程影片 https://youtu.be/7_MOm4V2uh0  (Turtle Graphics + IoTtalk DA)
關於更多 Turtle Graphics 範例, 可點這到 iottalk.vip/6/#turtle
* 以下可以搭配 IoTtalk 上的 Ball-throw1 從 IoTtalk 遙控器控制;
    也可以直接從鍵盤輸入控制; 會圖時可以故意按 ENTER 鍵看看(或亂打一個字再按看看)
    多研究別人程式(這程式用到 兩個 thread), 可讓你程式功力大增 :-)
* 注意這 DAI777.py 需要用到 Dummy Device 的 DAN.py 和 csmapi.py (連接 IoTtalk 伺服器用)
- 
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
---
===
#This DAI777.py uses coding: utf-8 ; 整合 Turtle Graphics 與 DAI2.py; by tsaiwn@cs.nctu.edu.tw
import time, DAN, requests, random 
import threading, sys # for using a Thread to read keyboard INPUT  

dm_name = "Ball-throw1"       ## DM (Device Model) 的名稱
odfs = ["Angle", "Height", "Speed"]   #ODF list; Output Device Features
funs = ""  # [Angle, Height, Speed ]  ## functions; 必須寫在函數出現之後 ! 所以故意先寫 ""

ServerURL = 'https://demo.iottalk.tw'    ## with SSL(https) secure connection

DAN.profile['dm_name']= dm_name   # you can change this but should also add the DM in server
DAN.profile['df_list']= odfs  # Check IoTtalk to see what IDF/ODF the DM has
DAN.profile['d_name']= "TWN_TTL."+ str( random.randint(100,999 ) ) +"_"+ DAN.profile['dm_name'] # None

Reg_addr = None  ##if None, Reg_addr = MAC address #(在 DAN.py 會這樣做, 會用 UUID 生出唯一ID )  
# Note that Reg_addr 在以下三句會被換掉! # thus the mac_addr in DAN.py is NOT used
mac_addr = "C77700D38" + str( random.randint(100,999 ) )  # put here for easy to modify :-)
## 若希望每次執行這程式都被認為同一個 Dummy_Device, 要把上列 mac_addr 寫死(或寫 None), 不要用亂數。
Reg_addr = mac_addr   ## Note that the mac_addr generated in DAN.py always be the same cause using UUID 

####### 參數改變:  Angle, Height, Speed ==> angle, pensize, steps  ###/////////////////
### Turtle Graphics, coding: utf-8 # 畫正方型 --  改參數然後測試看畫出啥 -- by tsaiwn@cs.nctu.edu.tw
angle, pensize, steps = (59, 3, 11) ## (59, 3, 11); (29, 3, 11); (89, 3, 11)   
## # angle: 每次旋轉角度; steps: How many steps to repeat draw? 
length = 150    ## 線段長度, 正方形的邊長 
import turtle 
pen = turtle.Turtle( )    
turtle.Screen( ).bgcolor("black")    # 畫面底色 
pen.speed(11)   ##  11 == 0 == fastest;;  1 == slowest
colors = [ "red","blue","green","orange","purple","yellow",]     # 紅藍綠 橙紫黃; Cyan = 湛藍
colorsLen = len(colors)
######### = = = = = = = = == = = = = == = = = == = = = = == = ======= ######## 
def register( ):  
    DAN.device_registration_with_retry(ServerURL, Reg_addr) 
    print("dm_name is ", DAN.profile['dm_name']) ; 
    print("Server is ", ServerURL);

## 這是原先入門手冊(五)裡面 DAI2.py 負責讀取鍵盤的 thread
# global gotInput, theInput, allDead    ## 主程式不必宣告 globel, 但寫了也 OK
gotInput = allDead = False
theInput="haha"  
def doRead( ):    ## thread 負責讀取鍵盤  
    global gotInput, theInput, allDead
    while True:  
        while gotInput:   # 老闆(主執行緒)還沒把資料拿走
           time.sleep(0.1)    # 小睡一下把 CPU 暫時讓給別人
           continue  # go back to while  
        try:     ## 準備讀取資料, 注意程式會卡在這等 User 輸入, 所以要用 Thread
           theInput = input("Give me data: ")
        except KeyboardInterrupt:   #  except Exception:
           allDead = True    ## 告訴大家說要收工囉 :-) 
           break;   # Leave while True
        if theInput =='quit' or theInput == "exit":
           allDead = True    ## 也是告訴大家說要收工囉 :-) 
        else:
           ## print("Data give to Main Thread: " + theInput, end="   , ") 
           gotInput=True   # YES, we got data 
        if allDead: break;
    return   # means break from while LOOP; # 這是 doRead( ) 最後, 不寫也 OK

import threading, sys # for using a Thread to read keyboard INPUT 
#creat a thread to do Input data from keyboard, by tsaiwn@cs.nctu.edu.tw 
threadx = threading.Thread(target=doRead)     ## Python 的 thread 就這麼簡單
threadx.daemon = True   #  表示若把我start叫起來的 thread  死了,則我必須立即自殺殉葬 !
######################################################
def sayWeGot(arg):   # 後來 arg 沒用到  (1, 2, 3 代表 angle, pensize, steps)
    global gotPull
    gotPull = True  ##讓主執行緒在叫用 checkPull( ) 時可以知道我們幫忙從 IoTtalk 那邊 PULL 到資料了。
angleNew = None   ## 網路傳來 (pull 到的)  資料先放 *New, 再由 main thread 主執行緒 拿走
pensizeNew = stepsNew = None    ## 三個都先放 None 表示沒從網路 PULL 到資料
####### 以下三個函數其實是從 IoTtalk 的 VPython DA 抄來的, 故意儘量保持原來樣貌
### 這三個函數會被 doPull( ) 在 PULL 到資料時用 funs[i](data) 叫用 (LINE 120) 
# 當 Gravity 旋鈕/滑桿 收到新值時;; ## Ball-throw1 的 ODF ["Angle", "Height", "Speed"]
def Angle(data):
    global angleNew    ## shift angle; 每畫好一回合要左轉幾度
    if data != None:
        angleNew = int( data[0] )   # [0, 360] 
        sayWeGot(1)    # 這樣我們可以判斷抓來啥新的資料

# 當 Radius 旋鈕/滑桿 收到新值時  ## 原先在 Edutalk 這是 Radius
def Height(data):
    global pensizeNew    ## 筆粗細
    if data != None:
        pensizeNew = int( data[0] )      #  建議限制 [0, 15] 
        if pensizeNew > 15: pensizeNew = 15   ## 防呆一下
        sayWeGot(2)

# 當 Speed 旋鈕/滑桿 收到新值時 ## 原先在 Edutalk 並沒有 Speed(data)
def Speed(data):
    global stepsNew    ## new repeat steps; 要 repeat 多少次 
    if data != None:
        stepsNew = int( data[0] )   # 
        sayWeGot(3)
###
funs = [Angle, Height, Speed]    ## 在函數寫完之後才可寫這; 用在 doPull( )
funs = [Angle, Height, Speed]    #
funs = [Angle, Height, Speed]    ## 寫三次也不會怎樣  :-)
############################################################################
### 以下只是故意透過  funs[i] 調用 Angles( ), Height( ), Speed( ) 
### 否則, 實際上可以直接處理 pull 到的資料改變 angleNew, pensizeNew, stepsNew
import threading, sys  #  重複 import 並不會怎樣, 也不會執行  
## 以下是負責去 PULL 網路資料的 thread (執行緒)  
allDead = False   ## 用來看是否不要做了 
def doPull( ):     ## thread 負責 PULL IoTtalk 的資料 
  global allDead    ## 其實這句不必, 因這函數內並沒去改 allDead 
  while True:
    data = None
    if allDead: break;    ## 通常是因為 doRead( ) 從鍵盤讀到了說要 quit
    for i in range(len(odfs)):     ## Ball-throw1 的 odfs[ ] 有三個
       ## print("try Pull ", odfs[i], funs[i])
       try:   
          data = DAN.pull(odfs[i])    ## odfs[ ] 裡面是 "Angle", "Height", "Speed" 
          pass   #  這裡看要不要寫些成功 PULL 資料...
       except:    ## 有錯好像也沒辦法怎樣 :-)
          pass
          print("? DAN pull error: when pulling ", odfs[i])
       # print(" got pull data = ", data) 
       if data != None:   
          if not type(data) is list: data = [data]   # 確保傳 [LIST] 過去 ! 
          funs[i](data)  # 叫用對應的函數  Angle, Height, Speed  
       time.sleep(0.125)   # 每做完一個 pull 資料, 就休息一下下 
    time.sleep(0.25)   # every for Loop (已經 pull 完 "Angle", "Height", "Speed" 一回合) 
  print("Leave while Loop in doPull()")

## thread to do Pull jobs   (執行緒)
thready = threading.Thread(target=doPull)     ## Python 的 thread 就這麼簡單
thready.daemon = True   ##  表示若把我start叫起來的 thread  死了則我必須立即自殺殉葬 !
## 主執行緒要進入 Loop 之前(接進最後處)再把 thread (執行緒) start 起來!
########=========== #  ##  === from KEYBOARD === #  ##  ====     #  ##  ====== ========
########   !!! 會被 main Thread 直接調用  !!! 別跟 doRead( ) 搞混喔 !
##  ==>  查看 doRead( ) 有幫忙讀到資料放  theInput 裡面嗎?
## 可以輸入三個參數, 用空白隔開 或 逗號隔開 
def checkInput( ):    # 會被 main Thread 直接調用  
    global gotInput, theInput, allDead
    global angle, pensize, steps, isRunning
    checkHelp( )
    if not gotInput:
        return False  # 沒輸入
    if theInput =='quit' or theInput == "exit":
        allDead = True
        return True   
    if theInput == "go" or theInput == "GO":   ##  秘技 :-) 
       theInput = "-1 -1 " + str(steps)     ## 假裝第三個參數有變化
    xx = theInput + ", -1, -1,-1"    # 最多三個輸入值
    xx = xx.replace(" ", ",")       # 空白轉為逗號
    xx = xx.split(",")      ## 依據 逗號 切開
    xx = [x for x in xx if x!=""]    ## 去掉空字串
    xx,yy,zz, *_ = xx    ## 取出前三個 (仍為字串)
    ## print("Got from keyboard: ", xx, yy, zz)
    try:
        xx = float(xx)
        yy = float(yy)
        zz = float(zz)
    except:
        print("What? ", theInput)
        gotInput = False
        return  False   # 算沒讀到東西
    if(xx != -1): angle = int(xx)    # 這例子只需要整數
    if(yy>=0): pensize = int(yy)
    if(zz>=0): 
        steps = int(zz)  
        isRunning = True    ## 只 steps 改變才重畫
    gotInput = False    # 表示拿走了所以可再次輸入囉
    return True  # 有讀到資料

def checkHelp( ):     ## 看有沒輸入要求看 HELP 訊息 
    global gotInput, theInput, allDead
    if not gotInput: return  # 沒輸入
    if theInput == "help" or theInput == "HELP" or theInput == "?":
        print("\r\nInput 輸入 Angle, pensize, steps (空白或逗號隔開, -1 表示不變)")
        print("quit 結束, show 或直接按 ENTER 看參數, go 立即畫!", " "*12) 
        theInput = "show"   # 偷吃步 :-) 
    if theInput == "show" or theInput == "" or theInput.startswith("-1 -1 -1") :
        print("\nServer is ", ServerURL, " "*28) ## IoTtalk server
        print("My Name is ", DAN.profile["d_name"], " "*33)
        print("Angle, pensize, steps = ", angle, pensize, steps)
        gotInput = False
    return

##------- checkPull( ) ------ check to see doPull( ) had PULLed data from NETWORK ------- ----------
########   !!! checkPull( ) 也是會被 main Thread 直接調用  !!! 別跟 doPull( ) 搞混了!
##  ==>  checkPull( ) 查看 doPull( ) 有 pull 到資料嗎?
gotPull = False
angleNew = None      # 之前 doPull( ) pull 到的先放這些有 *New 的變數 (調用函數放的)
pensizeNew = None
stepsNew = None     ## 新的 steps
def checkPull( ):    ## 會被 main Thread 直接調用 
    global angle, pensize, steps   # 有寫在等號 = 左邊的才須 global
    global angleNew, pensizeNew, stepsNew  ## 所以, 這三個也要 global 喔 ! 
    global gotPull, isRunning   
    if not gotPull:
        return    # 沒網路資料過來, 立即返回
    if angleNew != None:
        angle = angleNew
        angleNew = None
        print("got IoTtalk new shift Angle = ", angle)
        if(angle==0): angle = -11   # 旋轉 0 等於畫在原處, 故意改為 -11 右璇
    if pensizeNew != None:
        pensize = pensizeNew
        pensizeNew = None
        print("got IoTtalk new Pensize = ", pensize)
        if(pensize==0): pensize = 6  # 故意
    if stepsNew != None:
        steps = stepsNew
        stepsNew = None
        print("got IoTtalk new Steps = ", steps)
        time.sleep(0.123)  ## 故意
        isRunning = True    ### 只 steps 改變才重畫
    gotPull = False    # 表示我拿走了
    setMsg( )  # message to show; 弄好要顯示的參數在 msg, msg2 之後會印成兩列
    time.sleep(0.125)  ## 故意 Delay 一下

################################################################################
pen3 = turtle.Turtle( )   ## 第三支筆用來顯示進度 (後來加入的)
pen3.width(5); pen3.speed(0); pen3.st( )     # 進度條筆粗 5
x3Orig, y3Orig = (-250, 320)   ##  進度條放在 文字的上方 
def initPen3( ):     ## pen3 用來畫進度條(progress bar)
  global x3, y3 
  p3xxx = 0; x3=x3Orig; y3=y3Orig; pen3.color("red"); 
  pen3.up( ); pen3.goto(x3-6, y3); pen3.down( )
  pen3.fd(1);  pen3.fd(2);   pen3.fd(3); turtle.update( )   #
def pgsBar( ):    ##  畫進度條(progress bar)的程式碼
    global x3, y3
    x3 += 9; pen3.color("cyan"); pen3.st( ); 
    if(x3 > 233):  ## 太右邊就換一列 
       x3 = x3Orig; y3 += 16
       pen3.up( ); pen3.goto(x3, y3); pen3.down( )
    pen3.fd(6);  pen3.color("yellow");  pen3.fd(3); 

######## //////////    myText( )  to display message msg, msg2 on the Screen
oldmsg = oldmsg2 = ""
######## //////////   setMsg( ) + myText( )   ////////// ######## //////////
def setMsg( ):    ## 準備好 msg, msg2
    global msg, msg2
    msg="Angle: " + str(angle)
    msg2 = "pensize=" + str(pensize)
    msg2 += "; steps " + str(steps)    

pen2 = turtle.Turtle( )     ## pen2 負責 write 文字在圖畫上方
x2Orig, y2Orig = (-250, 270)   ## 文字寫在圖的上方
def myText(x= x2Orig, y=y2Orig):    
    global oldmsg, oldmsg2    
    setMsg( )   # construct(prepare) msg, msg2  
    if msg == oldmsg and msg2==oldmsg2:
        return
    style = ('Courier', 24, 'bold')
    pen2.color(turtle.bgcolor( ) )   ## 用背景色清除以前文字  # 'black' 
    if oldmsg != "":   ## 先清除以前文字
        pen2.setposition(x, y)    
        pen2.write(oldmsg, font=style, align='left')   ## 擦掉舊的文字
        pen2.setposition(x, y-32)    
        pen2.write(oldmsg2, font=style, align='left')  
    pen2.color('pink')   # deep pink
    pen2.setposition(x, y)  
    pen2.write(msg, font=style, align='left')  
    pen2.setposition(x, y-32)  
    pen2.write(msg2, font=style, align='left')    
    pen2.hideturtle()   # pen2.ht( )
    oldmsg = msg      ## 記住舊文字, 之後才能清除
    oldmsg2 = msg2

gotInput = gotPull = False   #
###############    是否要打斷畫圖 ?    ######################
def giveup( ):
    if allDead: return True    ## 已經說要收工就不要做了 :-) 
    if gotInput:   ## 鍵盤有按下 ENTER;  或 輸入 以下這些 都不打斷畫圖
        if(theInput == ""): return False   # 只按 ENTER, 繼續畫畫 if 正在畫
        if(theInput == "show" or theInput == "?"): return False  
        if(theInput == "help" or theInput == "HELP"): return False 
        return True  # 其他輸入要打斷畫圖
    if gotPull:    # 網路送資料來; 也可再細分送啥資料, 現在偷懶一律打斷畫圖
        return True    
    return False     ## 啥都沒收到當然不打斷啊

######## ///////////////////////////////////////////////////////////////// 
# Turtle Graphics, 畫正方型 -
def rect(length):    # 畫一個正方型
  for i in range(4):
    pen.fd(length)
    pen.left(90)

def drawTurtle( ):    ## 這才是 Turtle Graphics 要畫的  ###  ###
    global angle, steps   ## 這裡要防呆可能改掉 angle, steps 這兩個
    if angle == 0: angle = 1    # 防呆 :-)
    if 1 > steps: steps = 1    # 防呆 :-)  不讓 steps 小於等於 0
    colorsThis = [ ]   ## 讓顏色順序與 steps 有關, 重新弄一個顏色組合, 也可考慮亂數亂調換
    for i in range(steps, steps+colorsLen, 1):
        colorsThis.append( colors[ i % colorsLen ] )   ## colorsThis[ ] 放顏色
    for i in range(steps):  ##  Repeat steps 次
        if giveup( ):    ## 這樣不用寫 generator 或  coroutine  
            return       ##  參看前面 giveup( ) 函數 
        pgsBar( )    ### draw progress Bar 進度條
        for c in colorsThis: 
            checkHelp( )     ## 看是否需要處理鍵盤 help, 但仍會繼續畫
            pen.color( c )  
            rect(length)    # 畫一個方型, 邊長 length
            if(angle > 0) : pen.left(angle)   # 往左旋  (其實好像不用管 angle 正負:-)
            else: pen.right(-angle)    # 往右旋; 但不可以 -1 因 -1 已經用來表示不改該參數了 
    pen.ht( )   # Hide turtle  
    if pensize > 3:     # 如果線比較粗..
        pen.width( int(pensize/2) )    # 因最後一個方型太顯眼所以...
        if(angle > 0) : pen.right(angle)   ## 回頭偷畫個灰色較細的
        else: pen.left(-angle)   # 要注意原先左旋還是右旋 !
        pen.color("gray")    ## 偷畫一個灰色的方型
        rect(length)
    return

def drawPicture( ): 
    turtle.Screen( ).clear( )
    turtle.Screen( ).bgcolor("black")
    pen.reset( )  # turtle.reset( )
    pen.st( )     # show Turtle
    pen.speed(1)   #故意先放慢速度
    pen.penup( )   #其實不必做這
    pen.setheading(0)  # head 往右邊; pen.reset( ) 已經做這了
    pen.right(60)  #  Right-Down corner
    pen.pendown( )  # 筆放下
    pen.pensize(pensize)  ##筆粗細 pen.width(pensize)
    pen.speed(10)   #  故意用 10 不要畫太快; 最快是 11 == 0 == fastest
    if(steps > 17) : pen.speed(0) # do faster if too many steps to draw; 1 最慢, 11 和 0 最快
    if(3 >= angle):  pen.speed(0) ## shift angle 太小也畫快點
    if(steps%2 == 0): pen.speed(0) ## 偶數步驟也故意畫快點
    myText( ); initPen3( );   ## 負責顯示參數文字與進度條 
    timeStart = time.time( )    
    drawTurtle( )   ## 這才是真正 Turtle Graphics 的核心工作 :-) 
    print("\r\nElasp time = {:.8f}".format( time.time( ) - timeStart) )  #印到小數點後8位就好
    print("Give me data: ", end="", flush=True)      ## 讓 CMD 視窗有輸入的提示 :-)

# start( ) function to (1)register to IoTtalk; (2) start two threads 
def startBrother( ):  
    register( )  # to IoTtalk; see LINE 33 in this DAI777.py
    time.sleep(0.1)
    threadx.start()   ## 讀取鍵盤的小弟 
    thready.start()   ## 讀取網路(Pull)的小弟 
    ## print("Thread started !")

startBrother( )    ## 註冊, 並啟動兩個 thread (執行緒) 
isRunning = True  
msg = "Turtle Graphics"   # 沒事  :-)
while True:    ## 這是 main thread 主執行緒的核心工作: 畫圖 + 查看鍵盤資料 + 查看網路資料
  try:   
    while not isRunning:
        pen.ht( )   # hide Turtle
        myText( )
        turtle.update( )
        time.sleep(0.2)   
        ggyy = checkInput( )    # 查看鍵盤輸入 
        if(allDead): break;     # 離開 while not isRunning 
        if(not ggyy):
            checkPull( )  # 沒鍵盤輸入才查看網路來信息 
        if isRunning:   # 即將離開這 while not isRunning
            oldmsg += " "    # 故意讓 它與 msg 不相同, 這樣會重新印文字  
    if(allDead): break;    ## 離開 while True
    gotInput = gotPull = False    
    drawPicture( )      ## 畫圖  Turtle Graphics
    time.sleep(0.2)  # 故意
    if(allDead): break;
    isRunning = False   
  except KeyboardInterrupt:    ## 他敲了 CTRL_C  
    allDead = True
    break;  
## turtle.exitonclick( )
try:
  DAN.deregister( )     ## 解除註冊 
  print("\n\nDeregister " + DAN.profile['d_name'] + " !!!\n",  flush=True)
except:
  pass    # 若無法解除註冊.. 也只能不鳥它囉
print("Bye bye!")
* 建議進入以下這網站, 稍微看看並測試, 然後修改第二個程式的一些參數再試試!!
https://www.101computing.net/python-turtle-spirograph/
   (  建議改參數玩看看! )
    
   (市面上有賣該網頁內程式用到數學原理的文具, 叫做 "萬花尺", Design Ruler)

 
* 非廣告:這 "萬花尺", 一套, 一個圈圈尺加三個圈圈片, 才 NT$ 8元

Spirograph 這個字查字典會發現叫作"呼吸描記器", 但在這要翻譯作"萬花尺",俗稱Design Ruler,也叫繁花曲線規。
萬花尺所畫出的圖案,與外圖板圓圈半徑、內圓圖板半徑及筆洞位置有相關性。圖案令人聯想到萬花筒,故名萬花尺。
萬花尺由英國工程師丹尼斯•費歇爾(Denys Fisher)於1965年研發並銷售。(參考 Wikipedia)
    Turtle Graphics 最開始出現在 1967年專為小孩子設計的 Logo 程式語言。
是由 Wally Feurzeig, Seymour Papert, 和 Cynthia Solomon 三位共同設計研發的。
  * Tkinter OnLine with Python 3
  * Trinker.io - Interactive Python Anywhere(這好像比較快)
  * 推薦初學者用這個REPL.it 線上撰寫與執行 Python 程式碼做練習;
          進入選 start coding > Python > Create REPL(免費註冊; 不註冊也能用)
CMoreTV:  https://play.google.com/store/search?q=cmoretvhttps://demo.iottalk.tw「分享」按鈕- 社交外掛程式 - Facebook for Developers

請按  幫忙分享喔 !
有時候看起來對的其實是錯的!(我很久以前寫的網誌:-) * 不能反攻大陸的真正理由!(也是以前寫的, 其實是給大一學生的習題:-) * 何以1752年9月只有19天 ? 參考 Unix 的 cal 命令 ..(也是大一習題:-) * 為什麼中國(清朝)的 1911年 12 月只有 18 天 ?!(還是以前寫的:-) * [茶餘飯後] 魑魅魍魎 鬼話連篇(大一計概介紹802.11無線網路:-) * [很小的數]何處惹塵埃? 沙漠中是塵埃!(大一計概:-) * [很大的數]再談關於 Google 與 Googol(大一計概:-) * [也是很大的數]佛曰不可說不可說 比一個 googol 還大!(大一計概:-) * 物聯網、IoTtalk、薑黃、免疫力...(兩個月前寫的:-) * 請注意..感冒其實沒有藥     大家要顧好身體, 否則沒機會實現你的創意!我也有粉絲專頁ㄟ:-) 呵呵 (據說 "呵呵" 是北宋蘇東坡的口頭禪 :-)
你不懂的內容農場取妻當娶李子柒? 7 min.   ( 館長也哈她  ) * 台灣百大 Youtuber 收入排行全球10大最高收入华人YouTuber, 2019.1203, by 小楠ngrok 讓外部能夠連到 Intranet 內 Localhost的網站及服務Facebook Messenger Bot 範例 https://developers.facebook.com/docs/messenger-platform/getting-started/sample-apps/?translation用Python 寫一個 fb Messenger Bot手把手教你搭建 LINE 聊天機器人LineBot+Python,輕鬆建立聊天機器人(北科大程式設計研究社) * https://developers.line.biz/en/services/messaging-api/(LINE 關方網站教學文件) * 防詐騙、防詐騙、防詐騙 南寧詐騙案全台灣有 25萬人被騙 !小心詐騙 !小心詐騙 !小心詐騙 !投資自己,讓今天的自己 比 昨天的自己 更值錢 ! ( 建議每天 15分鐘在 voiceTube.tw ) *

* 提醒 IoTtalk 新手入門應用手冊在這: https://iottalk.vip/000/;
   >=== ==> 還沒用過 IoTtalk 物聯網平台請看這 12分鐘影片 關於 IoTtalk 的使用也請先大概看看IoTtalk的使用手冊:
    http://liny.cs.nctu.edu.tw/#IoTtalk(林一平教授網頁) 
  ==> 點入後在 Document 下方, 有中文版和英文版;   也可點這看更多手冊
 * 如想用NodeMCU-ESP8266連接 IoTtalk, 建議也 先看看 ArduTalk 操作手冊 
  


Network Latency 網路延遲 -- 延遲主要受到光速的限制,它在真空中的速度為299,792,458米/秒,這等同於每公里路徑長度需3.33µs。
Network Latency: How to Test, Measure, and Troubleshoot + Best Network Latency Testing Tools of 2020(2019.1007)
2020 Guide to Network Latency – How to Check, Measure, and Reduce Network Latency(2019.0819)
Network Latency Guide & 10 Best Network Latency Test Tools(2019.0301)
What is Network Latency + Using CDNs to Reduce Latency
What is network latency (and how do you use a latency calculator to calculate throughput)?

測試 VM 網路延遲(Microsoft 微軟, 2019.1029)
Azure 網路來回行程延遲統計資料(Microsoft 微軟, 2020.0310)
遊戲觀點 看 網路延遲(Garena 客服)
Faster Low-Latency 5G Mobile Networks(Anritsu, 安立知股份有限公司)

5G通訊將顛覆網路邊緣(2019.03.14 EDN, Taiwan)
What is the Latency of 5G?(2020.02.02, Verizon, USA)
 
台鐵火車查詢
You are the website counter -th visitors.             The W3C Markup Validation Service
* 點這看如何快速安裝 IoTtalk 系統 (要先花錢取得交大授權才可以喔:-)
* 點這看如何選擇 VPS ?(建議用 Hostwinds.com 或流量小可以先用免費的 AWS EC2)

* PuTTY official site to Download PuTTY   PieTTY project official site   Download Pietty0400b14.zip
 
  整理 by 蔡文能 tsaiwn@cs.nctu.edu.tw     交大資工系     tsaiwn.weebly.com     LINE ID: tsaiwn     FB: fb.me/tsaiwn     幾個英文字讀音   TOP
  TOP   Find your FB ID: https://findmyfbid.com/ if you want to Find your Facebook ID for your fb:admins