- 投稿日:2020-03-15T23:55:13+09:00
学習記録(4日目)#相対パスから絶対パスを取得する方法
学習内容
- 相対パスから絶対パスを取得する方法
- Python基本文法
相対パスから絶対パスを取得する方法
HTMLでリンク先が相対パスで記述されていた際には、
urllib.parse.urljon()
を利用して絶対パスを取得する。記述例
from urllib.parse import urljoin base = "http://exsample.com/html/a.html" compurl = lambda q: print(urljoin(base,q)) compurl("b.html") compurl("sub/c.html") compurl("../index.html") compurl("../img/hoge.png")実行結果
http://example.com/html/b.html
http://example.com/html/sub/c.html
http://example.com/index.html
http://example.com/img/hoge.pngPython基本文法
pass
文Pythonではインデントによって処理ブロックを定義するので、処理を行う必要のない時には処理ブロック自体がなくなってしまう。そこで、何も処理を行うことを明示的に記述するために
pass
文を用いる。with open('exsample.txt', 'w'): pass条件分岐
if
、elif
、else
を用いて記述する。また、一つの条件式によって2通りの処理ブロックに分岐する場合は三項演算子を用いて記述することもできる。if 条件式1: <処理ブロック1> # 条件式1がTrueのときに実行される処理 elif 条件式2: <処理ブロック2> # 条件式1がFalse、かつ条件式2がTrueのときに実行される処理 else: <処理ブロック3> # 条件式1がFalse、かつ条件式2がFalse、かつ条件式3がTrueのときに実行される処理 # 三項演算子による条件分岐 # 条件式がTrueのとき値1、Falseのとき値2 値1 if 条件式 else 値2イテレータ
データを表す値そのものではなく、一連のデータを生成することができるルールとしてデータを保持する。大量のデータが必要なときには、イテレータを用いた方がメモリ効率が良い。以下に
range
型のイテレータの記述例を示す。# 以下3つのrange()は,0から9まで、1ずつ増えるイテレータを返す range(0, 10, 1) range(0, 10) a = range(10) print(a) print(a[0])実行結果
range(0, 10)
0
range()
は、Pythonでは使うことができないインクリメント演算子(++
)の機能を備えている。デクリメント(--
)はreversed()
というイテレータを用いて行う。
break
文とcontinue
文ループ文の処理ブロック内に記述することで、実行中のループ文を制御することができる。
break
文現在実行中のループを中断してループの外に抜ける。
b = 0 while True: b += 1 if b > 5 break # b = 6 となった時点でループから抜けて処理が終了する。 print(b)実行結果
1
2
3
4
5
continue
文実行中の処理ブロックを中断して、ループの条件式評価まで処理を移動する。
c = 0 while True: c += 1 if c < 5 continue # b = 6 となるまでこの先の処理は実行されない。 print(c) break実行結果
6
まとめ
利用しているスクレイピングに関する参考書のコードの理解に苦労し始めたので、再びPythonの基礎文法についての学習を始めることにした。
C
やJava
では非常に便利だったインクリメント・デクリメントが使えないことには驚いたが、累算代入(+=
,-=
)やイテレータを用いてうまく対応していけるようにしたい。参考書
参考にした書籍から公開されているGitHubを添付しておきます。
増補改訂Pythonによるスクレイピング&機械学習 開発テクニック
- 投稿日:2020-03-15T22:25:35+09:00
「感染を封じこめる」をJavaScriptとHTML(SVG, canvas)を使って可視化してみた
プログラマとして、なにかできることはないのか、、、。
リアルなウイルスに関して、無力感を感じていたところに、以下のエントリに出会った。https://www.washingtonpost.com/graphics/2020/world/corona-simulator/
なるほど、こうやって可視化することで、パニックにならず冷静な対応をすることができるわけか、、、
このようなコードなら、プログラマには朝飯前? (これは、普段からあまり表には出てこない、プログラマという職業が、みなさまのお役にたてるチャンスかもしれないじゃないですか。)
「感染を封じ込める」を可視化する
「START」ボタンを押すと、入力した条件で、どのくらい感染を封じ込められるのか(広がるのか)がシュミレートされます。
そして、いろいろ数値を変えて実行してみることで、どのパラメータが感染に効果があるのかもわかってきます。See the Pen I tried to visualize the infection by yamazaki.3104 (@yamazaki3104) on CodePen.
初期条件では、おそらく収束するまでに 80% 近い感染者数になると思います。
トータルの感染者数を減らすには、・移動速度を減らす → movespeed
・素早く治療する(もしくは閉じこもる) → cure_days
・接触しない(手を洗う、マスクをする?) → rangeどれも効きますが、どれが効果があると思いますか?
ここに結論を書くよりも、みなさまで実際に試してみて、なにが効果的なのか各自で感じるとよいと思います。(わたしなりの結論は、このエントリの最後に書きます。)また、コードもすべて載せておきますので、CodePenからでも、このページからでもご自由にご利用ください。ただし、
このコードが正しく動作しているかどうかは、まったく保証できないし、計算された数値をどう解釈するかは各自の責任の範囲で使ってください
。「こうしたほうがいいよ」とか「こういう条件も追加してシミュレートしてみたいのだけど、、、」といったコメントも歓迎しています。(ぶっちゃけ、プログラマは「すげー!」とか「ありがとう!」という言葉に飢えていると思います。)
全コード 174行
<html> <body> <script> // このコードが正しく動作しているかどうかは、まったく保証できないし、計算された数値をどう解釈するかは各自の責任の範囲で使ってください // Dashboard var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(b){var c=0;return function(){return c<b.length?{done:!1,value:b[c++]}:{done:!0}}};$jscomp.arrayIterator=function(b){return{next:$jscomp.arrayIteratorImpl(b)}};$jscomp.makeIterator=function(b){var c="undefined"!=typeof Symbol&&Symbol.iterator&&b[Symbol.iterator];return c?c.call(b):$jscomp.arrayIterator(b)}; var DbNode=function(b,c){this.con_text=this.elm_tag_name=null;this.elm_attribute={};this.elm_contents=[];this.self_node=null;this.parent_node=c;this.update(b)};DbNode.prototype.delete_node=function(){this.elm_contents=[];this.elm_attribute={};this.con_text=this.elm_tag_name=null;this.parent_node.removeChild(this.self_node)}; DbNode.prototype.update=function(b){if("[object Object]"==toString.call(b)){if(this.elm_tag_name!=b.tag_name){for(var c=$jscomp.makeIterator(this.elm_contents),d=c.next();!d.done;d=c.next())d.value.delete_node();null!=this.self_node&&this.parent_node.removeChild(this.self_node);""==b.tag_name?this.self_node=this.parent_node:("svg-"!=b.tag_name.slice(0,4)?this.self_node=document.createElement(b.tag_name):this.self_node=document.createElementNS("http://www.w3.org/2000/svg",b.tag_name.slice(4)),this.parent_node.appendChild(this.self_node)); this.elm_tag_name=b.tag_name;this.con_text=null;this.elm_attribute={};this.elm_contents=[]}for(var e in this.elm_attribute)e in b.attribute||this.self_node.removeAttribute(e);c={};for(var f in b.attribute)c.$jscomp$loop$prop$atr_key$2$7=f,"[object Function]"==toString.call(b.attribute[c.$jscomp$loop$prop$atr_key$2$7])?(b.self_node=this.self_node,this.self_node[c.$jscomp$loop$prop$atr_key$2$7]=function(c){return function(d){b.attribute[c.$jscomp$loop$prop$atr_key$2$7](b.self_data,d,b.self_node)}}(c)): this.self_node.hasAttribute(c.$jscomp$loop$prop$atr_key$2$7)?this.self_node.setAttribute(c.$jscomp$loop$prop$atr_key$2$7,b.attribute[c.$jscomp$loop$prop$atr_key$2$7]):(d=document.createAttribute(c.$jscomp$loop$prop$atr_key$2$7),d.value=b.attribute[c.$jscomp$loop$prop$atr_key$2$7],this.self_node.setAttributeNode(d)),c={$jscomp$loop$prop$atr_key$2$7:c.$jscomp$loop$prop$atr_key$2$7};this.elm_attribute=b.attribute;if(this.elm_contents.length>b.contents.length)for(f=this.elm_contents.length-1;f>=b.contents.length;f--)this.elm_contents[f].delete_node(), this.elm_contents.pop();for(var g in b.contents)g<this.elm_contents.length?this.elm_contents[g].update(b.contents[g]):this.elm_contents.push(new DbNode(b.contents[g],this.self_node))}else this.con_text!=b&&(null!=this.self_node&&this.parent_node.removeChild(this.self_node),this.self_node=document.createTextNode(b),this.parent_node.appendChild(this.self_node),this.elm_tag_name=null,this.con_text=b)}; var Dashboard={table:[],child:{},_UI_Ary_to_HTML_obj:function(b,c){var d={tag_name:"",attribute:{},contents:[],self_data:c};if("[object Array]"!=toString.call(b)||1>b.length)return d;if("[object String]"!=toString.call(b[0])){for(var e in b)d.contents.push(Dashboard._UI_Ary_to_HTML_obj(b[e],c));return d}d.tag_name=b[0];for(var f in b)if(0!=f){e=b[f];var g=toString.call(e);if("[object Object]"==g)for(var h in e)d.attribute[h]=e[h];else"[object Array]"==g?d.contents.push(Dashboard._UI_Ary_to_HTML_obj(e, c)):d.contents.push(e)}return d},default_ui:function(b){var c=function(b){var d="",f=toString.call(b);if("[object Array]"==f)for(var g in b)d+='[ "div", { "style": "margin-left: 20px;" }, "'+g+': ", '+c(b[g])+" ], ";else if("[object Object]"==f)for(var h in b)d+='[ "div", { "style": "margin-left: 20px;" }, "'+h+': ", '+c(b[h])+" ], ";else d+='"'+b+'", ';return d.slice(0,-2)};return JSON.parse("[ "+c(b)+" ]")},bind:function(b){b.backup="";Dashboard.table.push(b);return b},_draw_animation_frame:function(){for(var b= $jscomp.makeIterator(Dashboard.table),c=b.next();!c.done;c=b.next()){c=c.value;var d=JSON.stringify(c.data);if(c.backup!=d){c.backup=d;for(var e in c.view)if("[object Function]"==toString.call(c.view[e])&&(d=document.querySelector(e),null!=d)){var f=Dashboard._UI_Ary_to_HTML_obj(c.view[e](c.data),c.data);e in Dashboard.child?Dashboard.child[e].update(f):Dashboard.child[e]=new DbNode(f,d,c.data)}}}window.requestAnimationFrame(Dashboard._draw_animation_frame)}};window.requestAnimationFrame(Dashboard._draw_animation_frame); </script> <div id='div_ui' class='Dashboard' ></div> <div id='div_svg' class='Dashboard' ></div> <div id='result' class='Dashboard' ></div> <canvas id='chart' width='555px' height='100px'></canvas> <script> class Point { constructor() { this.x = Math.random() * AREA_W this.y = Math.random() * AREA_H this.movespeed_x = (Math.random() - 0.5) this.movespeed_y = (Math.random() - 0.5) this.stat = 'nomal' this.elapsed_date = -1 // 経過日数 } move() { // 移動 this.x += this.movespeed_x * ui.data.movespeed this.y += this.movespeed_y * ui.data.movespeed if ( this.x < 0 ) { this.x *= -1 ; this.movespeed_x *= -1 } if ( this.y < 0 ) { this.y *= -1 ; this.movespeed_y *= -1 } if ( this.x >= AREA_W ) { this.x = AREA_W - (AREA_W - this.x); this.movespeed_x *= -1 } if ( this.y >= AREA_H ) { this.y = AREA_H - (AREA_H - this.y); this.movespeed_y *= -1 } } check( _a ) { // 確認 if ( this.stat != 'have' ) return this.elapsed_date++ // 経過日数 if ( this.elapsed_date > ui.data.complete_cure_days ) { this.stat = 'CompleteCure' return } const r = ui.data.range for ( const a of _a ) { const rx = this.x - a.x if ( rx > r ) continue if ( rx < -r ) continue const ry = this.y - a.y if ( ry > r ) continue if ( ry < -r ) continue if ( rx * rx + ry * ry > r * r ) continue if ( a.stat == 'nomal' ) { a.stat = 'have' a.elapsed_date = 0 } } } } const ui = Dashboard.bind( { data: { people: 1000, movespeed: 10, complete_cure_days: 14, range: 10 }, view: { 'div#div_ui.Dashboard': ( _d ) => [ [ 'div', 'people : ', [ 'input', { type:'number', value: _d.people, oninput: (_dt,_ev,_el)=>{ _dt.people = _el.value } } ] ], [ 'div', 'movespeed: ', [ 'input', { type:'number', value: _d.movespeed, oninput: (_dt,_ev,_el)=>{ _dt.movespeed = _el.value } } ] ], [ 'div', 'cure_days: ', [ 'input', { type:'number', value: _d.complete_cure_days, oninput: (_dt,_ev,_el)=>{ _dt.complete_cure_days = _el.value } } ] ], [ 'div', 'range : ', [ 'input', { type:'number', value: _d.range, oninput: (_dt,_ev,_el)=>{ _dt.range = _el.value } } ] ], [ 'button', 'START', { onclick: (_dt,_ev,_el)=>{ start_sim( _dt.people ) } } ], ], } } ) const percent = (_p) => { return parseInt( _p / ui.data.people * 1000 ) / 10 } const result = Dashboard.bind( { data: { nomal_cnt: 0, have_cnt: 0, cure_cnt: 0, day: 0 }, view: { 'div#result.Dashboard': ( _d ) => [ [ 'div', `nomal: ${ _d.nomal_cnt}, ${ percent(_d.nomal_cnt) }%` ], [ 'div', `have : ${ _d.have_cnt }, ${ percent(_d.have_cnt ) }%` ], [ 'div', `cure : ${ _d.cure_cnt }, ${ percent(_d.cure_cnt ) }%` ], [ 'div', `day : ${ _d.day }` ], ] } } ) const AREA_W = 555 const AREA_H = 333 const div_svg = Dashboard.bind( { data: { p: [] }, view: { 'div#div_svg.Dashboard': (_d) => [ [ 'svg-svg', { width: AREA_W+5*2, height: AREA_H+5*2, stroke: "#111", fill: "#ddd" }, [ 'svg-rect', { x: 0, y: 0, width: AREA_W+5*2, height: AREA_H+5*2, } ], _d.p.map( (_it)=> [ 'svg-circle', { cx: _it.x+5, cy: _it.y+5, r: '5px', fill: _it.stat=='nomal'?'hsl(95, 46%, 75%)':_it.stat=='have'?'red':'hsl(300, 41%, 59%)' } ] ) ] ] } } ) const animation = () => { for ( let p of div_svg.data.p ) p.move() for ( let p of div_svg.data.p ) p.check( div_svg.data.p ) let nomal_cnt = 0 let have_cnt = 0 let cure_cnt = 0 for ( let p of div_svg.data.p ) { if ( p.stat == 'nomal' ) nomal_cnt ++ else if ( p.stat == 'have' ) have_cnt ++ else cure_cnt ++ } result.data.nomal_cnt = nomal_cnt result.data.have_cnt = have_cnt result.data.cure_cnt = cure_cnt // チャートに線を引く const ctx = document.querySelector('canvas#chart').getContext('2d') const draw_line = ( _x1, _y1, _x2, _y2, _color ) => { ctx.beginPath() ctx.moveTo( _x1, _y1 ) ctx.lineTo( _x2, _y2 ) ctx.moveTo( _x1-1, _y1 ) ctx.lineTo( _x2-1, _y2 ) ctx.strokeStyle = _color ctx.stroke() } const n = percent( nomal_cnt ) const h = percent( have_cnt ) draw_line( result.data.day+1, 0, result.data.day+1, 100, '#fff' ) draw_line( result.data.day, 0, result.data.day, n, 'hsl(95, 46%, 75%)' ) draw_line( result.data.day, n, result.data.day, n+h, 'red' ) draw_line( result.data.day, n+h, result.data.day, 100, 'hsl(300, 41%, 59%)' ) result.data.day++ if ( result.data.day > 555 ) result.data.day = 0 if ( have_cnt > 0 ) window.setTimeout( animation, 1000/20 ) // 20fps } const start_sim = () => { div_svg.data.p = [] for ( let i=0 ; i<ui.data.people ; ++i ) div_svg.data.p.push( new Point() ) div_svg.data.p[0].stat = 'have' result.data.day = 0 window.setTimeout( animation, 1000/20 ) // 20fps } </script> </body> </html>細かい解説をしなくても、緑の丸がワシャワシャ動いているメインのところを SVG で描いていて、下のチャートの部分は canvas で描いています。どちらも一長一短がありますので、適材適所で使い分けています。
いまのところ、Chrome で動作の確認を行っています。
わたしの考察を書くと
「感染には移動が効く。とにかく一定時間じっとしているといい。ぶっちゃけ感染期間に何人と接触したのか?で決まる」
です。
このコードでは、movespeed が3以下になれば、ほどんと感染が広がらないことが確認できます。もしくは、以下の2点で感染者数が劇的に変化することがわかると思います。お試しあれ。
movespeed: 5 ← 出歩かない(移動を半分にする) cure_days: 14 range : 5 ← 感染距離を半分にする(手洗いをする)みなさま、ふんばりどころです。がんばりましょう。
このコードが少しでもみなさまのお役にたてば幸いです。
Dashboard.js
コードの先頭に minify されているコードは、Dashboard と名付けた UI ライブラリですが、まだ、テストも不十分なので、しばらく minify のままとさせてください。みなさまからの声が集まったら、しっかりテストしたのちに公開、、、するかもしれないです。ってか、UIのテストって、どうやって書くんでしょう??
Dashboard.js に関してもコメント募集中です。よろしくお願いいたします。
- 投稿日:2020-03-15T22:25:35+09:00
JavaScript と HTML を使って「感染を封じこめる」を可視化してみた
プログラマとして、なにかできることはないのか、、、。
リアルなウイルスに関して、無力感を感じていたところに、以下のエントリに出会った。https://www.washingtonpost.com/graphics/2020/world/corona-simulator/
なるほど、こうやって可視化することで、パニックにならず冷静な対応をすることができるわけか、、、
このようなコードなら、プログラマには朝飯前? (これは、普段からあまり表には出てこない、プログラマという職業が、みなさまのお役にたてるチャンスかもしれないじゃないですか。)
「感染を封じ込める」を可視化する
「START」ボタンを押すと、入力した条件で、どのくらい感染を封じ込められるのか(広がるのか)がシュミレートされます。
そして、いろいろ数値を変えて実行してみることで、どのパラメータが感染に効果があるのかもわかってきます。See the Pen I tried to visualize the infection by yamazaki.3104 (@yamazaki3104) on CodePen.
初期条件では、おそらく収束するまでに 80% 近い感染者数になると思います。
トータルの感染者数を減らすには、・移動速度を減らす → movespeed
・素早く治療する(もしくは閉じこもる) → cure_days
・接触しない(手を洗う、マスクをする?) → rangeどれも効きますが、どれが効果があると思いますか?
ここに結論を書くよりも、みなさまで実際に試してみて、なにが効果的なのか各自で感じるとよいと思います。(わたしなりの結論は、このエントリの最後に書きます。)また、コードもすべて載せておきますので、CodePenからでも、このページからでもご自由にご利用ください。ただし、
このコードが正しく動作しているかどうかは、まったく保証できないし、計算された数値をどう解釈するかは各自の責任の範囲で使ってください
。「こうしたほうがいいよ」といったコメントも募集しています。
全コード 174行
<html> <body> <script> // このコードが正しく動作しているかどうかは、まったく保証できないし、計算された数値をどう解釈するかは各自の責任の範囲で使ってください // Dashboard var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(b){var c=0;return function(){return c<b.length?{done:!1,value:b[c++]}:{done:!0}}};$jscomp.arrayIterator=function(b){return{next:$jscomp.arrayIteratorImpl(b)}};$jscomp.makeIterator=function(b){var c="undefined"!=typeof Symbol&&Symbol.iterator&&b[Symbol.iterator];return c?c.call(b):$jscomp.arrayIterator(b)}; var DbNode=function(b,c){this.con_text=this.elm_tag_name=null;this.elm_attribute={};this.elm_contents=[];this.self_node=null;this.parent_node=c;this.update(b)};DbNode.prototype.delete_node=function(){this.elm_contents=[];this.elm_attribute={};this.con_text=this.elm_tag_name=null;this.parent_node.removeChild(this.self_node)}; DbNode.prototype.update=function(b){if("[object Object]"==toString.call(b)){if(this.elm_tag_name!=b.tag_name){for(var c=$jscomp.makeIterator(this.elm_contents),d=c.next();!d.done;d=c.next())d.value.delete_node();null!=this.self_node&&this.parent_node.removeChild(this.self_node);""==b.tag_name?this.self_node=this.parent_node:("svg-"!=b.tag_name.slice(0,4)?this.self_node=document.createElement(b.tag_name):this.self_node=document.createElementNS("http://www.w3.org/2000/svg",b.tag_name.slice(4)),this.parent_node.appendChild(this.self_node)); this.elm_tag_name=b.tag_name;this.con_text=null;this.elm_attribute={};this.elm_contents=[]}for(var e in this.elm_attribute)e in b.attribute||this.self_node.removeAttribute(e);c={};for(var f in b.attribute)c.$jscomp$loop$prop$atr_key$2$7=f,"[object Function]"==toString.call(b.attribute[c.$jscomp$loop$prop$atr_key$2$7])?(b.self_node=this.self_node,this.self_node[c.$jscomp$loop$prop$atr_key$2$7]=function(c){return function(d){b.attribute[c.$jscomp$loop$prop$atr_key$2$7](b.self_data,d,b.self_node)}}(c)): this.self_node.hasAttribute(c.$jscomp$loop$prop$atr_key$2$7)?this.self_node.setAttribute(c.$jscomp$loop$prop$atr_key$2$7,b.attribute[c.$jscomp$loop$prop$atr_key$2$7]):(d=document.createAttribute(c.$jscomp$loop$prop$atr_key$2$7),d.value=b.attribute[c.$jscomp$loop$prop$atr_key$2$7],this.self_node.setAttributeNode(d)),c={$jscomp$loop$prop$atr_key$2$7:c.$jscomp$loop$prop$atr_key$2$7};this.elm_attribute=b.attribute;if(this.elm_contents.length>b.contents.length)for(f=this.elm_contents.length-1;f>=b.contents.length;f--)this.elm_contents[f].delete_node(), this.elm_contents.pop();for(var g in b.contents)g<this.elm_contents.length?this.elm_contents[g].update(b.contents[g]):this.elm_contents.push(new DbNode(b.contents[g],this.self_node))}else this.con_text!=b&&(null!=this.self_node&&this.parent_node.removeChild(this.self_node),this.self_node=document.createTextNode(b),this.parent_node.appendChild(this.self_node),this.elm_tag_name=null,this.con_text=b)}; var Dashboard={table:[],child:{},_UI_Ary_to_HTML_obj:function(b,c){var d={tag_name:"",attribute:{},contents:[],self_data:c};if("[object Array]"!=toString.call(b)||1>b.length)return d;if("[object String]"!=toString.call(b[0])){for(var e in b)d.contents.push(Dashboard._UI_Ary_to_HTML_obj(b[e],c));return d}d.tag_name=b[0];for(var f in b)if(0!=f){e=b[f];var g=toString.call(e);if("[object Object]"==g)for(var h in e)d.attribute[h]=e[h];else"[object Array]"==g?d.contents.push(Dashboard._UI_Ary_to_HTML_obj(e, c)):d.contents.push(e)}return d},default_ui:function(b){var c=function(b){var d="",f=toString.call(b);if("[object Array]"==f)for(var g in b)d+='[ "div", { "style": "margin-left: 20px;" }, "'+g+': ", '+c(b[g])+" ], ";else if("[object Object]"==f)for(var h in b)d+='[ "div", { "style": "margin-left: 20px;" }, "'+h+': ", '+c(b[h])+" ], ";else d+='"'+b+'", ';return d.slice(0,-2)};return JSON.parse("[ "+c(b)+" ]")},bind:function(b){b.backup="";Dashboard.table.push(b);return b},_draw_animation_frame:function(){for(var b= $jscomp.makeIterator(Dashboard.table),c=b.next();!c.done;c=b.next()){c=c.value;var d=JSON.stringify(c.data);if(c.backup!=d){c.backup=d;for(var e in c.view)if("[object Function]"==toString.call(c.view[e])&&(d=document.querySelector(e),null!=d)){var f=Dashboard._UI_Ary_to_HTML_obj(c.view[e](c.data),c.data);e in Dashboard.child?Dashboard.child[e].update(f):Dashboard.child[e]=new DbNode(f,d,c.data)}}}window.requestAnimationFrame(Dashboard._draw_animation_frame)}};window.requestAnimationFrame(Dashboard._draw_animation_frame); </script> <div id='div_ui' class='Dashboard' ></div> <div id='div_svg' class='Dashboard' ></div> <div id='result' class='Dashboard' ></div> <canvas id='chart' width='555px' height='100px'></canvas> <script> class Point { constructor() { this.x = Math.random() * AREA_W this.y = Math.random() * AREA_H this.movespeed_x = (Math.random() - 0.5) this.movespeed_y = (Math.random() - 0.5) this.stat = 'nomal' this.elapsed_date = -1 // 経過日数 } move() { // 移動 this.x += this.movespeed_x * ui.data.movespeed this.y += this.movespeed_y * ui.data.movespeed if ( this.x < 0 ) { this.x *= -1 ; this.movespeed_x *= -1 } if ( this.y < 0 ) { this.y *= -1 ; this.movespeed_y *= -1 } if ( this.x >= AREA_W ) { this.x = AREA_W - (AREA_W - this.x); this.movespeed_x *= -1 } if ( this.y >= AREA_H ) { this.y = AREA_H - (AREA_H - this.y); this.movespeed_y *= -1 } } check( _a ) { // 確認 if ( this.stat != 'have' ) return this.elapsed_date++ // 経過日数 if ( this.elapsed_date > ui.data.complete_cure_days ) { this.stat = 'CompleteCure' return } const r = ui.data.range for ( const a of _a ) { const rx = this.x - a.x if ( rx > r ) continue if ( rx < -r ) continue const ry = this.y - a.y if ( ry > r ) continue if ( ry < -r ) continue if ( rx * rx + ry * ry > r * r ) continue if ( a.stat == 'nomal' ) { a.stat = 'have' a.elapsed_date = 0 } } } } const ui = Dashboard.bind( { data: { people: 1000, movespeed: 10, complete_cure_days: 14, range: 10 }, view: { 'div#div_ui.Dashboard': ( _d ) => [ [ 'div', 'people : ', [ 'input', { type:'number', value: _d.people, oninput: (_dt,_ev,_el)=>{ _dt.people = _el.value } } ] ], [ 'div', 'movespeed: ', [ 'input', { type:'number', value: _d.movespeed, oninput: (_dt,_ev,_el)=>{ _dt.movespeed = _el.value } } ] ], [ 'div', 'cure_days: ', [ 'input', { type:'number', value: _d.complete_cure_days, oninput: (_dt,_ev,_el)=>{ _dt.complete_cure_days = _el.value } } ] ], [ 'div', 'range : ', [ 'input', { type:'number', value: _d.range, oninput: (_dt,_ev,_el)=>{ _dt.range = _el.value } } ] ], [ 'button', 'START', { onclick: (_dt,_ev,_el)=>{ start_sim( _dt.people ) } } ], ], } } ) const percent = (_p) => { return parseInt( _p / ui.data.people * 1000 ) / 10 } const result = Dashboard.bind( { data: { nomal_cnt: 0, have_cnt: 0, cure_cnt: 0, day: 0 }, view: { 'div#result.Dashboard': ( _d ) => [ [ 'div', `nomal: ${ _d.nomal_cnt}, ${ percent(_d.nomal_cnt) }%` ], [ 'div', `have : ${ _d.have_cnt }, ${ percent(_d.have_cnt ) }%` ], [ 'div', `cure : ${ _d.cure_cnt }, ${ percent(_d.cure_cnt ) }%` ], [ 'div', `day : ${ _d.day }` ], ] } } ) const AREA_W = 555 const AREA_H = 333 const div_svg = Dashboard.bind( { data: { p: [] }, view: { 'div#div_svg.Dashboard': (_d) => [ [ 'svg-svg', { width: AREA_W+5*2, height: AREA_H+5*2, stroke: "#111", fill: "#ddd" }, [ 'svg-rect', { x: 0, y: 0, width: AREA_W+5*2, height: AREA_H+5*2, } ], _d.p.map( (_it)=> [ 'svg-circle', { cx: _it.x+5, cy: _it.y+5, r: '5px', fill: _it.stat=='nomal'?'hsl(95, 46%, 75%)':_it.stat=='have'?'red':'hsl(300, 41%, 59%)' } ] ) ] ] } } ) const animation = () => { for ( let p of div_svg.data.p ) p.move() for ( let p of div_svg.data.p ) p.check( div_svg.data.p ) let nomal_cnt = 0 let have_cnt = 0 let cure_cnt = 0 for ( let p of div_svg.data.p ) { if ( p.stat == 'nomal' ) nomal_cnt ++ else if ( p.stat == 'have' ) have_cnt ++ else cure_cnt ++ } result.data.nomal_cnt = nomal_cnt result.data.have_cnt = have_cnt result.data.cure_cnt = cure_cnt // チャートに線を引く const ctx = document.querySelector('canvas#chart').getContext('2d') const draw_line = ( _x1, _y1, _x2, _y2, _color ) => { ctx.beginPath() ctx.moveTo( _x1, _y1 ) ctx.lineTo( _x2, _y2 ) ctx.moveTo( _x1-1, _y1 ) ctx.lineTo( _x2-1, _y2 ) ctx.strokeStyle = _color ctx.stroke() } const n = percent( nomal_cnt ) const h = percent( have_cnt ) draw_line( result.data.day+1, 0, result.data.day+1, 100, '#fff' ) draw_line( result.data.day, 0, result.data.day, n, 'hsl(95, 46%, 75%)' ) draw_line( result.data.day, n, result.data.day, n+h, 'red' ) draw_line( result.data.day, n+h, result.data.day, 100, 'hsl(300, 41%, 59%)' ) result.data.day++ if ( result.data.day > 555 ) result.data.day = 0 if ( have_cnt > 0 ) window.setTimeout( animation, 1000/20 ) // 20fps } const start_sim = () => { div_svg.data.p = [] for ( let i=0 ; i<ui.data.people ; ++i ) div_svg.data.p.push( new Point() ) div_svg.data.p[0].stat = 'have' result.data.day = 0 window.setTimeout( animation, 1000/20 ) // 20fps } </script> </body> </html>いまのところ、Chrome で動作の確認を行っています。
わたしの考察は、感染には、移動が効く。とにかく一定時間じっとしているといい。
このコードでは、movespeed が3以下になれば、ほどんと感染が広がらないことが確認できます。もしくは、以下の2点で感染者数が劇的に変化することがわかると思います。お試しあれ。
movespeed: 5 ← 出歩かない(移動を半分にする) cure_days: 14 range : 5 ← 感染距離を半分にする(手洗いをする)みなさま、ふんばりどころです。がんばりましょう。
このコードが少しでもみなさまのお役にたてば幸いです。
Dashboard.js
コードの先頭に minify されているコードは、Dashboard と名付けた UI ライブラリですが、まだ、テストも不十分なので、しばらく minify のままとさせてください。みなさまからの声が集まったら、しっかりテストしたのちに公開、、、するかもしれないです。ってか、UIのテストって、どうやって書くんでしょう??
Dashboard.js に関してもコメント募集中です。よろしくお願いいたします。
- 投稿日:2020-03-15T09:43:26+09:00
初心者によるプログラミング学習ログ 260~262日目
100日チャレンジの260~262日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
260~262日目は、おはようございます
— ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) March 11, 2020
260日目
・自作ポートフォリオ改造
・cssをsassで書く練習#早起きチャレンジ#駆け出しエンジニアと繋がりたい#100DaysOfCodeおはようございます
— ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) March 12, 2020
261日目
・自作ポートフォリオ改造
・cssをsassで書く練習#早起きチャレンジ#駆け出しエンジニアと繋がりたい#100DaysOfCodeおはようございます
— ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) March 13, 2020
262日目
・自作ポートフォリオ改造
・cssをsassに書く練習#早起きチャレンジ#駆け出しエンジニアと繋がりたい#100DaysOfCode