Vue.jsでHighLowゲームをつくったよ

Vue.jsとは

Vueの公式ページからのコピペ

Vue (発音は / v j u ː / 、 view と同様)はユーザーインターフェイスを構築するためのプログレッシブフレームワークです。他の一枚板(モノリシック: monolithic)なフレームワークとは異なり、Vue は少しずつ適用していけるように設計されています。中核となるライブラリは view 層だけに焦点を当てています。そのため、使い始めるのも、他のライブラリや既存のプロジェクトに統合するのも、とても簡単です。また、モダンなツールやサポートライブラリと併用することで、洗練されたシングルページアプリケーションの開発も可能です。

リアクティブなことを使って何かをしたい

たまたまハイローゲームの話が友達との間で出たのでそれを実装してみました。

コード

Flaskをサーバに使っているためデリミターを変更しています。npmしろってはなしなんですけどCDNの書き方しかわからんのだわこれが・・・・

作ったゲームのページですHighLow

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>HighLow</title>
    <!-- 開発バージョン、便利なコンソールの警告が含まれています -->
    <script src="../static/js/Vue/vue.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/siimple@3.1.1/dist/siimple.min.css">
</head>

<body>
    <h1>ハイローゲーム</h1>
    <div id="app">
        <h2>残りのカード</h2>
        <div class="siimple-grid-row">
            <div class="siimple-grid-col siimple-grid-col--0" v-for="card in cards" v-bind:key="card">
                [[card]]
            </div>
        </div>
        <h2>現在のカード</h2>
        <div>[[nowcard]]</div>
        <div class="siimple-tag siimple-tag--success" v-show="judge">Success!!</div><br>
        <div class="siimple-btn siimple-btn--red" v-show="!start" v-on:click="Start">Game Start</div>
        <div class="siimple-btn siimple-btn--red" v-show="start" v-on:click="High">High</div>
        <div class="siimple-btn siimple-btn--blue" v-show="start" v-on:click="Low">Low</div>
    </div>
</body>

</html>

<script>
    var vm = new Vue({
        el: "#app",
        delimiters: ['[[', ']]'], // Flaskのdelimiterとの重複を回避
        data: {
            cards: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
            nowcard: null,
            start: false,
            judge: false,
            message: null
        },
        methods: {
            draw: function() {
                var random = Math.floor(Math.random() * this.cards.length);
                this.nowcard = this.cards[random]
                this.cards.splice(random, 1)
            },
            High: function() {
                var before_card = this.nowcard
                this.draw()
                if (this.nowcard >= before_card) {
                    this.judge = true
                } else {
                    this.loseprocess()
                }
                this.winCheck()
            },
            Low: function() {
                var before_card = this.nowcard
                this.draw()
                if (this.nowcard <= before_card) {
                    this.judge = true
                } else {
                    this.loseprocess()
                }
                this.winCheck()
            },
            winCheck: function() {
                if (this.cards.length == 0) {
                    alert("よううぃn!")
                    this.judge = false
                    this.start = false
                    this.cards = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
                    this.nowcard = null
                }
            },
            loseprocess: function() {
                this.judge = false
                this.start = false
                this.cards = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
                alert("ゲームオーバー" + this.nowcard)
                this.nowcard = null
            },
            Start: function() {
                this.draw()
                this.start = true
            }
        }
    })
</script>

まとめ

さくっとできた

SQLiteを個人的にいじりやすくしてみました

SQLite3を簡単に使いたい

SQLite3を使ってうーんとなった

めちゃめちゃいいライブラリだと思います。簡単にデータベースっぽいことできるのがよい・・・よい

でもなんかSQLiteのコマンドは忘れるわ、接続いちいちしないといけないわで調べるのに時間かかるし(メモとっとけって話だけど)、なにより接続の部分ががががって感じだった

デコレータ使うとどうやらその辺が改善されるとのことでやってみることにした〜ん。プログラムとかオブジェクト指向とか5ヶ月前に知ったばっかりで赤ちゃんだからなんでこんなことしてるの?とか変数の名前わかりにくすぎwwwwってのがあれば切実に教えて欲しいです。

肝心のプログラム

こんな感じです

import sqlite3
import time
from datetime import datetime, timedelta, timezone
from typing import Dict, List, Tuple

import pandas as pd


class Handle:
    def __init__(self, db: str):
        self.dbpath = db

    # 1つのレコードを挿入する命令を作るメソッド
    def __MakeOneInsertOrder(self, table: str, data: List):
        """
        1つのレコードを挿入する
        data: 時間は自動でセットされる
        return: 1レコードのinsert文
        """
        print("MakeOneInsertOrder start")
        insert = "INSERT INTO {} VALUES ".format(table)
        s = self.__TupleMake(data)
        insert += s
        print(insert)
        print("MakeOneInsertOrder finish")
        return insert

    # 複数のレコードを挿入する命令を作るメソッド
    def __MakeSomeInsertOrder(self, table: str, datas: List[List]):
        """
        複数レコードを挿入する
        data: 挿入したいデータを入れ子にすること
              時間は自動でセットされる
        return: 複数レコードのinsert文 
        """
        print("MakeSomeInsertOrder start")
        insert = "INSERT INTO {} VALUES ".format(table)
        s = [self.__TupleMake(data) for data in datas]
        s = ", ".join(s)
        insert += s
        print(insert)
        print("MakeSomeInsertOrder finsish")
        return insert

    # テーブルを作成する命令を作るメソッド
    def __MakeTableOrder(self, table: str, columns: List):
        """
        テーブルを新しく作る命令文を作るメソッド
        columns: 設定したいカラム, dateは自動でつけられる
        return: create文
        """
        print("MaleTableOrder start")
        create = "CREATE TABLE IF NOT EXISTS {} ".format(table)
        record = "(date DATE PRIMARY KEY"
        for col in columns:
            record += ", "+col+" TEXT"
        record += ")"
        create += record
        print(create)
        print("MaleTableOrder finish")
        return create

    def __MakeSelectOrder(self, table: str, hour: int):
        """
        select文を作るメソッド
        return select文
        """
        print("MakeSelectOrder start")
        if hour > 0:
            hour = self.__CreateTimeStamp() - 3600*hour
            select = "SELECT * from {} WHERE date > {}".format(table, hour)
        else:
            select = "SELECT * from {}".format(table)
        return select

    # レコードに挿入するデータ形式に変換するメソッド
    def __TupleMake(self, data: List):
        """
        リスト形式のデータを()の入れ子に変換する
        """
        print("TupleMake start")
        time = self.__CreateTimeStamp()
        s = "({}".format(time)
        for item in data:
            s += ", '{}'".format(item)
        s += ")"
        print("Tuple finish")
        return s

    # タイムスタンプを返す
    def __CreateTimeStamp(self):
        """
        タイムスタンプを作る
        """
        print("CreateTimeStamp start")
        now = time.time()
        JST = timezone(timedelta(hours=+9), 'JST')
        loc = datetime.fromtimestamp(now, JST).timestamp()
        print("CreateTimeStamp finish")
        return loc

    # sqlite3のコネクションを司るデコレータ
    # わかっていない部分もあるので今後バシバシ使っていくこと
    def connectdb(func):
        from functools import wraps

        @wraps(func)
        def _connectdb(self, *args, **kwargs):
            print("connection start")
            con = sqlite3.connect(self.dbpath)
            cur = con.cursor()
            try:
                result = func(self, *args, **kwargs, con=con, cur=cur)
            except sqlite3.Error as e:
                print('sqlite3.Error occurred:', e.args[0])
                result = None
            finally:
                con.commit()
                con.close()
                print("connection finish")
            return result
        return _connectdb

    @connectdb
    def MakeTable(self, table: str, columns: List, con=None, cur=None):
        """
        テーブルを実際に作るメソッド
        """
        print("MakeTable start")
        order = self.__MakeTableOrder(table, columns)
        cur.execute(order)
        print("MakeTable finish")

    @connectdb
    def InsertRecord(self, table: str, data: List, con=None, cur=None):
        print("InsertRecord start")
        if isinstance(data[0], list):
            order = self.__MakeSomeInsertOrder(table, data)
        else:
            order = self.__MakeOneInsertOrder(table, data)
        cur.execute(order)
        print("InsertRecord finish")

    @connectdb
    def GetData(self, table: str, hour=1, con=None, cur=None):
        """
        データを指定した時間分取得するメソッド
        hour=0の時は全てのデータを取ってくる
        return: pandasデータフレーム
        """
        print("GetData start")
        if table not in self.GetTableList():
            print("!!!Error!!! {} is not exist!!!".format(table))
            print("GetData finish")
            return pd.DataFrame()
        else:
            order = self.__MakeSelectOrder(table, hour)
            df = pd.read_sql(order, con)
            print("GetData finish")
            return df

    @connectdb
    def GetTableList(self, con=None, cur=None):
        """
        作られているテーブル一覧を返すメソッド
        """
        print("GetTableList start")
        select = "SELECT * FROM sqlite_master WHERE TYPE = 'table'"
        cur.execute(select)
        print("GetTableList finish")
        return [x[1] for x in cur.fetchall()]

    @connectdb
    def UpdateRecord(self, table: str, record: dict, update_data: dict, con=None, cur=None):
        """
        table: テーブル名
        record: {"カラム名": "指定するレコードを示すデータ"}
        update_data: {"カラム名": 変更する内容} 
        """
        print("UpdateRecord start")
        rec_key, rec_val = list(record.items())[0]
        update_key, update_val = list(update_data.items())[0]
        order = "update {} set {} = '{}' where {} = {}".format(
            table, update_key, update_val, rec_key, rec_val)
        cur.execute(order)
        print("UpdateRecord finish")

    @connectdb
    def DeleteTable(self, table: str, con=None, cur=None):
        """
        table: 削除したいテーブル名
        """
        print("DeleteTable start")
        # テーブルの削除
        cur.execute("DROP TABLE {}".format(table))
        # 空き容量の解放
        cur.execute("VACUUM")
        print("DeleteTable finish")

    @connectdb
    def DeleteRecord(self, table: str):
        pass

デコレータを使ったところ

# sqlite3のコネクションを司るデコレータ
    # わかっていない部分もあるので今後バシバシ使っていくこと
    def connectdb(func):
        from functools import wraps

        @wraps(func)
        def _connectdb(self, *args, **kwargs):
            print("connection start")
            con = sqlite3.connect(self.dbpath)
            cur = con.cursor()
            try:
                result = func(self, *args, **kwargs, con=con, cur=cur)
            except sqlite3.Error as e:
                print('sqlite3.Error occurred:', e.args[0])
                result = None
            finally:
                con.commit()
                con.close()
                print("connection finish")
            return result
        return _connectdb

wrapsを使うとどうなるのかよくわかってない・・・データを保持できるとかなんとか書いてあったけどいまいち現象が掴めないって感じです

_connectidb(self, *args, **kwargs)にself入れ込んだことでself使えるようになってはっぴーって感じ!

デコレータ自体を書ける気がしない・・・・この書き方なんかこんがらがりませんか????

これ以外のメソッドは大したことしていないので見たらすぐわかると思います。

まとめ

いい感じで動いているので嬉しい

自動でHTMLを生成してくれるサイトがでました

なんかMicrosoftがすごいものを出しました

 

Sketch2Code(https://sketch2code.azurewebsites.net/)です

 

こんなページを作りたい!っていうページの構成を紙に書いて写真をこのサイトにアップロードするだけでソースが出来上がるとのこと…

jsと一体型になってるvue.jsとかだと使えないとは思うけど雛形つくって修正って形を取ればだいぶぽいものを作れる気がします。HTMLでうんうん悩んでる時間を削減できることはいいこと?だと思います?いいのかな?自分はHTML全然わからないのでいいと思います

使って何か作れたらいいな〜とか思ってます

簡単な作ったもののまとめサイトとか…?

 

最近fusion360入れて遊んでるので3Dモデル置くところにしてもいいかも…?

そろそろ3Dプリンターで遊んでいる様子の記事を書きたいですね…って事で今日はおわりです

Vtuber Land開演プレミアムパーティに行ってきました

9/17によみうりランドであったVtuberのイベントに行ってきました〜

 

アトラクションにVtuberの実況がつけられててめちゃめちゃ面白そうでした(9/24がにじさんじdaysでそれが一番な目的なのでまだアトラクションにはのってません)

 

プレミアムグッズはタオルでした!

f:id:Naporitan:20180919012801j:image

めちゃめちゃ手触りいいですこれ…何しろ委員長が可愛すぎる…

 

トークイベントはしずりん先輩と猫宮ひなたちゃんが永遠に可愛かった…あとでろーんと委員長の身長の対比が刺さりました…くぅ〜オタクでよかった…JK組の2人が3Dモデル実装されたことによって今までこんな動きだったのか〜ってのが伝わってきてよかった〜個人的にはしずりん先輩が3Dになったことでマイパースさが可視化?っていうか目でも声でも感じられたのでよかったなーって思いました〜

ミライアカリちゃんが上から下ネタを言わないように!と念押しされたんだよ〜って言っててそんなに言われたの???って感じで面白かったです〜

最近ほんとにおじさんじとかにじさんじとか名取とかしか見てなかったのでまた見る幅を戻していければな〜と思っています(webアプリ作ったりPython触ったりの方がお熱でした)

 

9/23,24はにじさんじオンリーの#にじそうさくとにじさんじdaysがあるので楽しみー

 

それではこの辺でキモオタは失礼します

 

もう少しIRKitで遊びます

最近1日1食生活を1週間ほど続けていたのですがふらふらします...できる人とできない人がいるようです.自分はやるとそのうち倒れると思います.

 

倒れないように!とご飯を満足するまで食べたらやる気が出てきたので新しいwebアプリでも作ってみようかと思います!!!

 

前回IRKitのwebアプリを作ったんですけど部屋のエアコンがたまについてなかったり,電気が消えなかったりしたのでIoT?的なことと絡めてもうちょっといい感じのwebアプリを作って行きます

 

使いたいものとしては

vue.js

python (webサーバをcgiで動かすため.)

cgiを使う理由としてはDjangoとかFlaskとかも使ってもいいけどこんなしょぼいアプリケーションにフレームワークを使うほうが労力かかるかなとおもったからです.テンプレート使うほど何枚もhtml書かなきゃいけないことはないと思うんだ~~~~

かなと思っています.

 

vue.jsはまだよく調べていないのですがどうやらページのリレンダリングを自動的にやってくれるらしいとのこと.ボタンの追加とかwebサーバからのレスポンスによる動作が多くなりそうなのでIRKitのアプリを作るにはいいのではないかなと思っています.(実は友達がこれ面白そうだよっていって来たからなんとなく使ってみたいだけ)

 

pyhtonではCRUD(生成,読み取り,更新,削除)の実装ができたらいいなぁとwebAPIとしては機能が少なすぎるし意味がないかもしれないけどはじめはモノを作ってみてから考えたいと思います.これが意味のない努力だとしても使えるものができていればそれでいいと考えています.

 

完成図みたいなものをiPadProで書きました.結構雑ですが方針にはなりそうです

f:id:Naporitan:20180915034724p:plain

 

今更IRKitの即興Webアプリを作った

IRKitの即興Webアプリ

できたwebアプリ

気に入ってるのでアホみたいにでかくはろ f:id:Naporitan:20180912050510j:plain

IRKitって何?

IRKit: オープンソースクラウドリモコンです.中身は確かESP8266で赤外線の送受信ができます.
curlでぽちぽち書くだけですぐ赤外線を送受信できるのでやってる感でていい・・・・・

curlを変換してくれるサイトがありました!!!

昔IRKit買いたての頃post,getが全くわからないけど動かしてみたいってことでここで変換してwebサイトを駆け巡りコピペしてたのを思い出しました
Convert curl syntax to Python, Node.js, PHP, Rここです.まじで神サイトだと思ってます
pythonをよく使うのですがrequestsのget,postメソッドがどうもうまくいかないなぁ・・・・って時に変換して確かめたりしました(それに何の意味があるんだって話ですが)
まぁ動けばきぶんがいいんでいいんです!

作ったコード

HTMLの方

<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>IRKit</title>
  <style>
    select {
      font-size:16px;
    }
    #set{
      width: 50px; 
      height: 30px;
    }
    #send{
      width: 50px; 
      height: 30px;
    }
    #savebtn{
      width: 50px; 
      height: 30px;
    }
  </style>
</head>

<body>
    <label for="mode">Request method</label><br>
    <select id="mode" name="mode">
      <option value="get">GET</option>
      <option value="post">POST</option>
    </select><br>

    <select id="ir" name="ir">
        <option>-</option>
    </select>
    <input type="submit" value="SET" id="set"><br>

    <label id="message">Message</label><br>
    <textarea id="msg" ></textarea><br>

    <label for="response">Response</label><br>
    <textarea id="res" cols="40" rows="5"></textarea><br>
    <input type="submit" name="btn" id="send"><br><br>
    
    <div>
      <label for="save">save</label>
      <input type="text"  id ="save">
      <input type="submit"  id="savebtn">
    </div>
</body>

</html>

<script src="modules/jquery-3.3.1.min.js"></script>
<script src="modules/irkit.js"></script>

これと

<select id="ir" name="ir">
    <option>-</option>
</select>

これ

<div>
      <label for="save">save</label>
      <input type="text"  id ="save">
      <input type="submit"  id="savebtn">
    </div>

こいつらは自前でpythonで作ったWebAPI(あれはAPIって呼んでいい代物なのだろうか・・・・自分はAPIだと思いたいのでAPIって言い張ります)
から今までの赤外線データを取ってきたり,新規の赤外線データを保存できます

削除はweb側でできないんですけどね!!!!!そのうち削除もします

JavaScriptの方

val_list = [];

$(function () {
    get_keys();
 });

$('#send').click(function () {
    var url = "https://api.getirkit.com/1/messages";
    var clientKey = "クライアントキー"
    var deviceId = "デバイスキー";

    if ($('#mode').val() == "get") {
        $('#msg').val("Wait...");
        $.ajax({
            type: "get",
            url: url,
            data: {
                clientkey: clientKey,
                deviceid: deviceId
            },
            timeout: 5000
        }).done(function (json) {
            $('#msg').val("OK");
            $('#res').val(JSON.stringify(json["message"]));
        }).fail(function (XMLHttpRequest, textStatus, errorThrown) {
            $('#msg').val(textStatus);
        });
    } else {
        $.ajax({
            type: "post",
            url: url,
            data: {
                clientkey: clientKey,
                deviceid: deviceId,
                message: $('#res').val()
            },
            timeout: 5000
        }).done(function (json) {
            $('#msg').val("OK");
        }).fail(function (XMLHttpRequest, textStatus, errorThrown) {
            $('#msg').val(textStatus);
        });
    }
});

$('#savebtn').click(function () {
    var ir_name = $('#save').val();
    var ir_val = $('#res').val();
    if (ir_name.length <= 0 || ir_val.length <= 0) {
        $('#msg').val("error");
        return;
    }

    $.ajax({
        type: "post",
        url: "自作APIのアドレス",
        data: {
            ir_name: ir_name,
            ir_val: ir_val
        },
        timeout: 1000
    }).done(function (json) {
        $('#ir').empty();
        get_keys();
    }).fail(function (XMLHttpRequest, textStatus, errorThrown) {
        $('#msg').val(textStatus);
    });
});

$('#set').click(function(){
    var res = val_list[$('#ir').val()]
    $('#res').val(res);
    $('#mode').val("post");
});

$(function () {
   get_keys();
});

function get_keys(){
    $.ajax({
        type: "get",
        url: "自作APIのアドレス",
        timeout: 1000
    }).done(function (json) {
        $('#ir').empty();
        $('#ir').append("<option>-</option>");
        var key_list = json["keys"];
        val_list = json["vals"];
        for(var i=0;i<key_list.length;i++) {
            $('#ir').append("<option value="+i+">"+key_list[i]+"</option>");
        }
    }).fail(function (XMLHttpRequest, textStatus, errorThrown) {
        alert("今までの赤外線ファイルが読み込めませんでした");
    });
}

なんかJavaScriptのほうが色がつかない・・・・・
でも普通に動いてるのでいいです

最後に

なんだかんだ言って結構気に入ってます
pythonの方も削除できるようになったら載せるかもしれません

Scrapyつかってスライドをごそっととってくる

SlideShareスクレイピングするやつ〜

今日はもう眠いのでスパイダーのソースだけ
scrapyでやってます.

# -*- coding: utf-8 -*-
import io
import os
import time
import urllib
from datetime import datetime as dt

import requests
import scrapy
from PIL import Image
from pytz import timezone
from reportlab.pdfgen import canvas
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_splash import SplashRequest

from slide_scrapy.items import SlideScrapyItem


class SlideshareSpider(CrawlSpider):
    name = 'slideshare'
    allowed_domains = ['www.slideshare.net']
    start_urls = ['http://www.slideshare.net/']

    custom_settings = {
        "DOWNLOAD_DELAY": 1,
        "FEED_EXPORT_FIELDS": [
            "title",
            "author",
            "page",
            "path",
            "url"
        ]
    }

    # csv export
    now = dt.now(timezone('Asia/Tokyo'))
    date = now.strftime('%Y-%m-%d')
    jst_time = now.strftime('%Y-%m-%dT%H-%M-%S')

    # rules = (
    #     Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
    # )

    def parse(self, response):
        search_url = urllib.parse.urljoin(response.url, "search/slideshow")
        query = {
            "searchfrom": "header",
            "q": "iot python",
            "lang": "ja"
        }
        query = urllib.parse.urlencode(query)
        url = search_url+"?"+query
        print(url)

        yield SplashRequest(url,
                            method="get",
                            callback=self.after_search,
                            args={"wait": 2,
                                  "timeout": 90},
                            dont_filter=True)

    def after_search(self, response):
        # とりあえず1ページ目だけ
        contents = response.xpath(
            "//div[@class='thumbnail-content ']/a/@href").extract()
        for content in contents:
            url = urllib.parse.urljoin(response.url, content)
            yield SplashRequest(url,
                                method="get",
                                callback=self.content_search,
                                args={"wait": 2,
                                      "timeout": 90},
                                dont_filter=True)

    def content_search(self, response):
        item = SlideScrapyItem()


        max_page = int(response.xpath(
            "//span[@id='total-slides']/text()").extract_first())
        images_url = response.xpath(
            "//img[@class='slide_image']/@data-full").extract()

        title = response.xpath(
            "//span[@class='j-title-breadcrumb']/text()").extract_first().strip()
        author = response.xpath(
            "//span[@itemprop='name']/text()").extract_first().strip()

        pdf_name = title+".pdf"
        output_dir = "適当なディレクトリ"

        item["title"] = title
        item["author"] = author
        item["page"] = max_page
        item["path"] = output_dir+pdf_name
        item["url"] = response.url

        pdf_cnvs = canvas.Canvas(output_dir+pdf_name)
        for idx, img_url in enumerate(images_url):
            self.logger.info("title: {0} {1}/{2}".format(title,idx+1,max_page))
            image = Image.open(io.BytesIO(requests.get(img_url).content))
            image.save(".temp.png")
            image =Image.open(".temp.png")
            pdf_cnvs.setPageSize((image.size[0]+10,image.size[1]+10))
            pdf_cnvs.drawInlineImage(image,0,0)
            pdf_cnvs.showPage()
            time.sleep(1)
        os.remove(".temp.png")
        pdf_cnvs.save()      
        yield item


urlから画像をPILのImageオブジェクトのままpdfにしたかったけどなんか赤色が加算?されちゃうので一回隠しファイルでファイルを生成してます〜

超カッコ悪くて草