Discord bot

名詞解析

  • bot
  • API

Common app with bots

Set up

Finish it first!

pip install -U discord.py

step 0 - pip install

step 1 - Register & install

step 2

step 3

  • 以新名字創建app

step 4

step 5

step 6

step 7

  • In discord app
  • 新建一個伺服器

step 8

step 9

step 10

step 11

  • 複製生成出來的網址,貼到瀏覽器上

step 12

  • 選擇剛剛創建的伺服器

step 12.5

step 13

  • 複製bot的token,重要!
  • 之後會用到
  • 不要給別人看到~

step 14

step 15

  • 執行後anaconda prompt會出現兩行,discord會顯示上線,就可以在聊天室輸入$covid19囉

Decorator

裝飾器

Let's see an example

def up(shot):
    maps = shot2map(shot)
    match = get_everything(shot, maps)
    maps = move(match, shot, maps, [-1, 0])
    shot = map2shot(maps, shot)
    match = get_everything(shot, maps)
    maps, shot = change(shot, maps)
    shot = check_win(shot, match)
    return shot

def down(shot):
    maps = shot2map(shot)
    match = get_everything(shot, maps)
    maps = move(match, shot, maps, [1, 0])
    shot = map2shot(maps, shot)
    match = get_everything(shot, maps)
    maps, shot = change(shot, maps)
    shot = check_win(shot, match)
    return shot
def left(shot):
    maps = shot2map(shot)
    match = get_everything(shot, maps)
    maps = move(match, shot, maps, [0, -1])
    shot = map2shot(maps, shot)
    match = get_everything(shot, maps)
    maps, shot = change(shot, maps)
    shot = check_win(shot, match)
    return shot
def right(shot):
    maps = shot2map(shot)
    match = get_everything(shot, maps)
    maps = move(match, shot, maps, [0, 1])
    shot = map2shot(maps, shot)
    match = get_everything(shot, maps)
    maps, shot = change(shot, maps)
    shot = check_win(shot, match)
    return shot

SAME!

def init(func):
    def with_logging(*args, **kwargs):
        shot = args[0]
        maps = shot2map(shot)
        match = get_everything(shot, maps)
        maps = move(match, shot, maps)
        shot = map2shot(maps, shot)
        match = get_everything(shot, maps)
        maps, shot = change(shot, maps)
        shot = check_win(shot, match)
        return func(shot)
    return with_logging

@init
def up(shot):
    return shot

@init
def down(shot):
    return shot

@init
def left(shot):
    return shot

@init
def right(shot):
    return shot

When?

  • 很多類似的函數
    • 參數格式一樣
    • 函數開頭有一樣的statement

Simple example

def logged(func): 
    def with_logging(*args, **kwargs): 
        print(func.__name__)
        return func(args[0], args[0]*2) 
    return with_logging

@logged 
def f(x,y):
    return x**y

@logged 
def g(x,y):
    return x*y

print(f(3))

your turn : 3049

def gcd(a,b): 
    if(b==0): 
        return a 
    else: 
        return gcd(b,a%b)
def lcm(a,b):
    c = gcd(a,b)
    return b*a//c
def f(x,y):
    a = gcd(x,y)
    b = lcm(x,y)
    return a**b

def g(x,y):
    a = gcd(x,y)
    b = lcm(x,y)
    return a*b

x = int(input())
y = int(input())
print(f(x,y))
print(g(x,y))

sync VS async

同步 VS 異步

目前大家學過的程式

  • 按照順序執行每一行程式碼
  • 執行完當前一行程式碼後才會執行下一行

試想一個情況

  • 我們的程式打算跟第三方溝通
  • 第三方需要很多時間處理
    • 可是這時我們想做其他事
  • 程式碼卡在某一行?

試想一個情況

server = Server()
result = server.handle(task) #花很多時間
print(result)

解法一

server = Server()
server.send(task) #先送工作
while not server.ok(): #檢查工作完成與否
    do_other_thing() #還沒完成前可以先做其他事
result = server.recv()
print(result)

解法一

  • 第三方不一定支援以下API類型
    • 先送工作
    • 檢查工作是否完成

解法二 - async IO

  • 語法:async, await
  • 在被認爲會花時間的指令前,可以加上await
    • 在等待該指令完成的時間中,程式可以執行其他指令

For example

  • 每個事件會標上編號
  • 每個事件會以隨機順序送給你
  • 編號x的事件要等編號x-1的事件做完後才能做

For example

import asyncio

async def f(done, a):
    while not done[a-1]:
        await asyncio.sleep(1)
    done[a] = 1
    return
loop = asyncio.get_event_loop()
tasks = []
done = [1,0,0,0]

l = [3,1,2]
for i in l:
    tasks.append(loop.create_task(f(done, i)))
loop.run_until_complete(asyncio.wait(tasks))
print(done)

課堂練習

日記bot

add diary

  • 時間、標題、內容
async def add_diary(ctx, date, title, content):

view

  • 查看特定title的日記
  • 查看特定日期的日記

search

  • 尋找內容有出現過甚麼甚麼

存檔

  • bot重開後還是保有之前上傳過的日記
  • file I/O

小作業

圖片管理系統+自訂功能

圖片管理系統(60%)

  • 上傳圖片
  • 每個圖片有tag、日期
    • tag : 風景、人物、食物...
    • 日期 : 2020/05/17
  • 目標 : 搜尋特定tag或日期的所有圖片
@bot.command()
async def upload(ctx):
    response = requests.get(ctx.message.attachments[0].url)
    file = open("sample_image.png", "wb")
    file.write(response.content)
    file.close()
@bot.command()
async def show_pic(ctx):
    with open('sample_image.png', 'rb') as f:
        picture = discord.File(f)
        await ctx.send(file = picture)

上傳圖片&用bot傳送圖片之範例

自訂功能(50%)

  • 發揮創意,小遊戲、搜尋...
    • 可運用二階其他課程內容
  • 每個功能請超過15行程式碼,且不允許冗言贅字。
  • 一個功能5%

繳交內容

  • 繳交方式 : 以表單發布在課程網
  • 內容 : 
    • 影片 : 請以錄製螢幕的方式,從頭呈現你所寫的所有功能。
    • 程式碼 : 與影片一併繳交

discord_bot

By piepie01

discord_bot

  • 1,242