Scratch × Python 組み合わせて学ぶプログラミング
前の記事でScratch3.0の拡張機能として新しいブロックを制作してPythonサーバとFirmataを挟んでArduinoを制御しました。 しかし、いろいろな機能を盛り込みすぎたせいで、きなり難しくなっているようなイメージでした。今回は新しく同じようなブロックを追加したうえで、そこからサーバを挟んでPythonのプログラムを実行できるようにしてみたいと思います。
- 注意:前回の記事通りにScratchの拡張機能を作成していることを前提に話しますので、合わせて読んで頂けると同じ操作で問題なく動作します。
前回作成したブロックに加えて今回作成するブロックが既に入っているスクラッチを誰でも起動できるようにしてあります。自分で作るのと細かい説明は軽く読んで理解するのは後回しにして以下のURLから最初に試してみるのもいいかもしれません。前回の記事に載せたものと同じURLですがどうぞ。
拡張機能の有効化は以前の記事で紹介しているので説明は省きます。
最初にまずは試したい!という方は以下に示す項と手順で進めることによってほんの少しだけ説明を省略して試すことが出来ます。
- 上記のこちらが用意したScratchをURLから起動
- python サーバ側(pythonコードをコピペ&実行のみ*必要に応じてモジュールのインストール)
- 追加したブロックの説明と実行例を呼んで進める
以上で簡単に試すことが出来ます。
プログラム
Python サーバ側
前回の記事でモジュールをインストールしていなければ以下を実行してください。
pip install requests
まずはPythonのサーバプログラムです。
from http.server import BaseHTTPRequestHandler, HTTPServer import urllib.parse as p import requests def trim(path): url_n_par = p.urlparse(path).query pre_text = path.replace('/?URL=', '') par_pre = p.urlparse(pre_text).query par = p.parse_qs(par_pre) params = {k: par[k][0] for k in par} URL_pre = path.replace('/?' + par_pre, '') URL_pre = p.urlparse(URL_pre).query URL_pre_d = p.parse_qs(URL_pre) URL = URL_pre_d['URL'][0] return params, URL class Server(BaseHTTPRequestHandler): def do_GET(self): try: self.send_response(200) self.send_header('Content-type', 'text/html') self.send_header('Access-Control-Allow-Origin', '*')#これがないとリクエストに答えられない。js側エラー内容( No 'Access-Control-Allow-Origin' header is present on the requested resource.) self.end_headers() params, URL = trim(self.path) result = None#念のため一度Noneで初期化 res = requests.get(URL)#URLにGETする func_text = '''{}'''.format(res.text)#三連引用符を使うことで複数行の文を実行可能にする print(func_text)#Gist更新が遅い時があるのでどんなコードを実行するか確認 print() d = {} exec(func_text)#Gistのプログラムを実行、第3引数locals()でもdict型の変数でも大丈夫 result = locals()['func'](params) # result = d['func'](paramater)#第3引数dict型変数の場合、()がとれて少しだけわかりやすい print(result) print() self.wfile.write(str(result).encode('utf-8'))#Scratchへの値渡し用 except Exception as e: print("An error occured") print("The information of error is as following") print(type(e)) print(e.args) print(e) print() def run(server_class=HTTPServer, handler_class=Server, server_name='', port=8000): server = server_class((server_name, port), handler_class) server.serve_forever() print('start') run(server_name='', port=8000)
実行する際は単純にコマンドプロンプトで保存したディレクトリまで移動して
python つけた名前.py
で大丈夫です。
例:python exec_gist.py
サーバの大部分は前の記事と大して変わっていません。
しかし、今回はこのプログラム自体は大きく書き換えることなく、別のところに置いてあるPythonのプログラムをブロックから呼び出せるようにしてあります。
それを実現するのが組み込み関数のexec関数です。
同じような関数としてeval関数がありますが、今回の用途には使いづらかったのでexec関数を使いました。
参考にさせて頂いた記事を以下に載せておきます。
このサーバプログラムから実行するプログラムはGitHubのサービスの一つであるGistに実行したいプログラムを載せておきます。
Gistの細かい説明は省きますが、プログラムを共有するためのものです。
使い方は簡単で、
↑URLを開いて、コードとファイル名を書いたら右下緑色のボタンを押すと保存されます。この時create secret gist
create public gist
の2つを選ぶことが出来ます。
URLを知っている人以外から見られたくない場合は前者にしてください。
後者は誰でも見られるような設定になります。
Git Hubのアカウントと連携していない場合はURLを忘れると探しようがないので気を付けてください。
面倒な方は後述するURLを使うことによって、こちらが用意したものを使うこともできます。その説明は適所で行います。
Gistのプログラムを2種類用意しました。
パスワード判定
1~nの総和
Gistでは関数を定義して、exec関数でその関数を読み込み、実行するような仕組みにしています。
Scratch サーバ側
次はScratchの拡張機能の編集です。
下記のファイルの内容をすべて消して、下のプログラムを全コピぺしてください。
scratch-vm\src\extensions\scratch3_halakeblocks\index.js
const ArgumentType = require('../../extension-support/argument-type'); const BlockType = require('../../extension-support/block-type'); const Cast = require('../../util/cast'); const log = require('../../util/log'); const nets = require('nets'); /** * Icon svg to be displayed at the left edge of each extension block, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const blockIconURI = 'data:image/png;base64,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'; /** * Icon svg to be displayed in the category menu, encoded as a data URI. * @type {string} */ // eslint-disable-next-line max-len const menuIconURI = 'data:image/png;base64,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'; /** * Class for the new blocks in Scratch 3.0 * @param {Runtime} runtime - the runtime instantiating this block package. * @constructor */ class Scratch3HaLakeBlocks { constructor (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; //this._onTargetCreated = this._onTargetCreated.bind(this); //this.runtime.on('targetWasCreated', this._onTargetCreated); } /** * @returns {object} metadata for this extension and its blocks. */ getInfo () { return { id: 'halakeblocks', name: 'HaLake Blocks', menuIconURI: menuIconURI, blockIconURI: blockIconURI, blocks: [ { opcode: 'fetchURL', blockType: BlockType.COMMAND, text: '[TEXT] にアクセスする', arguments: { TEXT: { type: ArgumentType.STRING, defaultValue: "http://192.168.x.xx:8000/?ON=0" } } }, { opcode: 'reqURL', blockType: BlockType.REPORTER, text: '[URL] にアクセスして値を取ってくる', arguments: { URL: { type: ArgumentType.STRING, defaultValue: "http://192.168.x.xx:8000/?READ=0" } } }, { opcode: 'reqGistPython', blockType: BlockType.REPORTER, text: ' [URL]', arguments: { URL: { type: ArgumentType.STRING, defaultValue: "https://gist.github.com/M-Shinoda/73d1b4fb557d5efa76a1405b347809f1/raw/?param=asdfghjk" } } }, { opcode: 'paramValue', blockType: BlockType.REPORTER, text: ' [onlyURL] /? [parNAME] = [parVAL] & [parPLUS]', arguments: { onlyURL: { type: ArgumentType.STRING, defaultValue: "https://gist.github.com/M-Shinoda/73d1b4fb557d5efa76a1405b347809f1/raw" }, parNAME: { type: ArgumentType.STRING, defaultValue: "param" }, parVAL: { type: ArgumentType.STRING, defaultValue: "hogehoge" }, parPLUS: { type: ArgumentType.STRING, defaultValue: " " } } }, { opcode: 'paramValuePlus', blockType: BlockType.REPORTER, text: '[parNAME] = [parVAL] & [parPLUS]', arguments: { parNAME: { type: ArgumentType.STRING, defaultValue: "param" }, parVAL: { type: ArgumentType.STRING, defaultValue: "hogehoge" }, parPLUS: { type: ArgumentType.STRING, defaultValue: " " } } }, { opcode: 'encode', blockType: BlockType.REPORTER, text: '[text]をエンコード', arguments: { text: { type: ArgumentType.STRING, defaultValue: "文字" } } } ], menus: { } }; } /** * Fetch URL. * @param {object} args - the block arguments. * @property {number} TEXT - the text. */ fetchURL (args) { const text = Cast.toString(args.TEXT); fetch(text, { method: 'GET', mode: 'no-cors' }); } /** * Request URL * @property {number} URL * @return {number} */ reqURL (args){ const ajaxPromise = new Promise(resolve => { nets({ url: Cast.toString(args.URL) }, function(err, res, body){ resolve(body); return body; }); }); return ajaxPromise; } reqGistPython (args){ const ajaxPromise = new Promise(resolve => { nets({ url: "http://localhost:8000/?URL=" + Cast.toString(args.URL)//localhostを環境に応じて書き換えが必要 }, function(err, res, body){ resolve(body); return body; }); }); return ajaxPromise; } paramValue (args){ compURL = args.onlyURL + "/?" + args.parNAME + "=" + args.parVAL + "&" + args.parPLUS console.log(compURL) const ajaxPromise = new Promise(resolve => { nets({ url: "http://localhost:8000/?URL=" + Cast.toString(compURL)//localhostを環境に応じて書き換えが必要 }, function(err, res, body){ resolve(body); return body; }); }); return ajaxPromise; } paramValuePlus (args){ return Cast.toString(args.parNAME + "=" + args.parVAL + "&" + args.parPLUS) } encode (args){ return encodeURIComponent(args.text) } } module.exports = Scratch3HaLakeBlocks;
「追加した部分を書き加えてください」となると、各自の環境でミスが多発しそうなのですべて書き換えてください。
追加した内容を以下に示します。
{ opcode: 'reqGistPython', blockType: BlockType.REPORTER, text: ' [URL]', arguments: { URL: { type: ArgumentType.STRING, defaultValue: "https://gist.github.com/M-Shinoda/73d1b4fb557d5efa76a1405b347809f1/raw/?param=asdfghjk" } } }, { opcode: 'paramValue', blockType: BlockType.REPORTER, text: ' [onlyURL] /? [parNAME] = [parVAL] & [parPLUS]', arguments: { onlyURL: { type: ArgumentType.STRING, defaultValue: "https://gist.github.com/M-Shinoda/73d1b4fb557d5efa76a1405b347809f1/raw" }, parNAME: { type: ArgumentType.STRING, defaultValue: "param" }, parVAL: { type: ArgumentType.STRING, defaultValue: "hogehoge" }, parPLUS: { type: ArgumentType.STRING, defaultValue: " " } } }, { opcode: 'paramValuePlus', blockType: BlockType.REPORTER, text: '[parNAME] = [parVAL] & [parPLUS]', arguments: { parNAME: { type: ArgumentType.STRING, defaultValue: "param" }, parVAL: { type: ArgumentType.STRING, defaultValue: "hogehoge" }, parPLUS: { type: ArgumentType.STRING, defaultValue: " " } } }, { opcode: 'encode', blockType: BlockType.REPORTER, text: '[text]をエンコード', arguments: { text: { type: ArgumentType.STRING, defaultValue: "文字" } } }
reqGistPython (args){ const ajaxPromise = new Promise(resolve => { nets({ url: "http://localhost:8000/?URL=" + Cast.toString(args.URL)//localhostを環境に応じて書き換えが必要 }, function(err, res, body){ resolve(body); return body; }); }); return ajaxPromise; } paramValue (args){ compURL = args.onlyURL + "/?" + args.parNAME + "=" + args.parVAL + "&" + args.parPLUS console.log(compURL) const ajaxPromise = new Promise(resolve => { nets({ url: "http://localhost:8000/?URL=" + Cast.toString(compURL)//localhostを環境に応じて書き換えが必要 }, function(err, res, body){ resolve(body); return body; }); }); return ajaxPromise; } paramValuePlus (args){ return Cast.toString(args.parNAME + "=" + args.parVAL + "&" + args.parPLUS) } encode (args){ return encodeURIComponent(args.text) }
以上の二か所になり追加したブロック分プログラムが増えています。
追加したブロックの説明と実行例
今回追加したブロックは以下の3つになります。
画像と対応して上から順に
ブロックの表示幅を変えられなくて一部見切れていますが、今回の追加分です。
- 注意:拡張機能として追加されているブロックは全部で6種類ほどになっていますが上記のものはそこの下から3つ分にあたります。そのほかの3つは以前の記事で説明されているので説明は省きます。
入力欄の説明を表で示します。
上記図内のGistのURL
に入力する例を示すと、私のGistURLの1つが
https://gist.github.com/M-Shinoda/73d1b4fb557d5efa76a1405b347809f1
なのでこれに/rawを付与するとそこに保存してあるソースコードだけを送り返してくれるので/rawまでを付与したものがブロックに入力するGistのURLになります。
https://gist.githubusercontent.com/M-Shinoda/73d1b4fb557d5efa76a1405b347809f1/raw
これです。
試しに、これら2つのURLを開いてみると違いが分かると思います。
- 注意:上記の方法だと書き換えたプログラムがすぐに更新されない(3~4分程度)ので、すぐに更新したものを使いたい場合はその都度
raw
ボタンを押して開かれるURLをコピペして使ってください。その都度URLが変わることと、URLが長くなってしまうので使い分けることをお勧めします。
今回追加分ブロックの一番目の物で、最初から入力されていると思いますが赤枠で囲った部分にGistのURLを入力します。
次にこれの右側の入力欄に任意のパラメータ(クエリストリング)を入力して使います。
パラメータはPythonサーバでGistのURLと分割され、Gistに記述されたPythonのプログラムで使う変数のために用意されています。
先ほど指定したGistのURLに載せているプログラムを見ながら説明します。
パスワード判定
基本書き換えないPythonサーバ側にアクセスされたら実行する関数として指定されているfunc
関数をGistに置くプログラムに必ず記述します。(言い回しが難しいですが理解せず何度か実行して体で覚えるといいかもしれません)
そのfunc
関数は第一引数だけ指定できるようにしておきます。これはPythonサーバ側で実行する際に決まっているのでfunc
関数を定義するときはdef func(params):
がほぼ定型文となります。(仮引数名は変えても問題ありませんが。)
この第一引数にはPythonサーバプログラムでparams
変数が指定され実行されます。(paramsという名前が2回出てきますがGist側では仮引数でサーバプログラムでは実引数として動作しています。当たり前のことですが...)
これはdict
型になっており、1や2のブロックで入力したパラメータ名とその値が対としてすべて格納されているためfunc
関数内で簡単に使えるようにしてあります。
上記のパスワード判定を行うGistのプログラム
2,3行目を見るとパスワードの設定とブロックで入力された値との比較を行っているので、ブロックに以下のような(ほげ ほげ/&\|=?
)入力をした後、ブロックを起動すると
True
と帰ってきます。これはGist側でもブロック側でもパスワード(PASSWORD)
にほげ ほげ/&\|=?
という値が設定されているので同じ文字列であると判定されて帰ってきます。
これを最後の入力欄をふげ ふげ/&\|=?
とパラメータの値を変えるとFalse
が返ってきます。
しっかりとGistのプログラムが動いていることがわかります。
今回追加分3つ目のURLエンコードブロックは日本語や記号を使ったときに誤作動しないようにするためのブロックになります。
URLエンコードブロックを使わずに直接入力することもできますが、誤作動の原因になるので注意しましょう。
追加分の1つ目のブロックにその機能も追加しておけばいいじゃん!と思おう人もいるかもしれませんが、こういったことが原因で誤動作に繋がるというのも学んでもらいたいと思っています。
1~nの総和
赤枠のURLと青枠を好きな数字に書き換えてください。
書き換えるURLは以下に貼っておきます。
https://gist.github.com/M-Shinoda/10ee62409f1500ffec887ec9cbdec1fd
パスワード判定の時はデフォルトでそのURLが入っていましたが、今回はGistに置いてある違うプログラムを使いたかったのでURLをかきかえました。自分で用意したプログラムを使いたい方はURLとそのパラメータを自由に書き換えてください。
今回のプログラムは1~好きな数字までの総和を出力してくれるものになっていますので、青枠の書き換えた数字まで一つづつ足した数がかえってきます。
画像では10を指定しているので10までの緑枠に総和=(1+2+3+4+5+6+7+8+9+10)=55と返ってきているのがわかります。
謎のブロック
真面目にすべて読んでいる方なら気づいていいるかもしれませんが、追加したブロックで使ってないのあるじゃん!と思っているかもしれません。
今回追加したブロックの2つ目について説明します。
追加分1つ目のブロックの一番右側に穴が空いていて使っていなかったと思います。そのところに追加して入れることを想定して作りました。
今まで使っていた方法だとGistに置いてあるプログラムに1つしか値を渡してあげることしかしていなかったのですが、これを使うことによってある意味で無限に値を渡すことができます。つまりGist内でScratchから受け取った値を複数使えることになります。
- 注意:図中青字で説明されているように、パラメータ名は必ず同じ名前にならないようにする必要があります。通常の変数と同じで、同じ名前にしてしまうと後に入力した値に代わってしまうので思ったような動作をしなくなってしまいます。
こんな感じに無限に増やして実行すことが出来ます。見えにくいですがそれほど追加できます。
以下に実行したプログラムとGistのURLを載せます。
Scratch貼り付け用: https://gist.github.com/M-Shinoda/e7e3d52dc48b59673a982e3e59798e4d/raw
Scratch側の出力で改行して出力したかったのですが、実用性がないのと試しのプログラムなので今回は無視しています。ですがしっかりと変数が渡されていことがわかります。
動作は同じですがパラメータ名ごとにその値を取り出していることが分かり易く確認できるプログラムです。単純ですがどうぞ。
Scratchのブロックで指定したパラメータ名と対になっていることがわかるはずです。
Scratch貼り付け用: https://gist.github.com/M-Shinoda/dc70ed264b02520e6da4e42f2f940fee
まとめ
- 複雑で説明が難しくなってしまった。
- flaskを使った方が簡単にできたと後から気づいた
コメント
コメントを投稿