karasuex54’s blog

プログラミングよりイリヤの方が好き

docker-composeでdenoの環境を作る

はじめに

お久しぶりです、からすさんです。タイトル通りdocker-composeでdenoを試すための環境を作る記事です。本記事の環境は次の通りです。

Ubuntu 20.04.3 LTS (Focal Fossa)
Docker version 20.10.8
docker-compose version 1.26.0

docker-compose

次のようにdocker-compose.ymlを作成します。

version: '3'
services:
  app:
    image: denoland/deno:1.15.1
    ports:
      - "8000:8000"
    volumes:
      - .:/app
    command: /bin/bash
    tty: true

command: /bin/bashtty: trueはコンテナを起動させ続けるために記述しています。

コンテナ起動

次のコマンドで起動させます。

$ docker-compose up -d

コンテナが実行中であるかを次で確認します。

$ docker-compose ps
      Name                     Command               State                    Ports                  
-----------------------------------------------------------------------------------------------------
deno-docker_app_1   /tini -- docker-entrypoint ...   Up      0.0.0.0:8000->8000/tcp,:::8000->8000/tcp

コンテナ内でdenoを試す

先ほど起動させたコンテナ内でコマンド実行を行うために、次のコマンドを実行させます。

$ docker-compose exec app bash
root@xxx:/#

コンテナ内でdeno --versionと実行させて、次のような出力がされ、denoの環境作りが終えました。

root@xxx:/# deno --version
deno 1.15.1 (release, x86_64-unknown-linux-gnu)
v8 9.5.172.19
typescript 4.4.2

備考

tty

ttyは、UNIXで同名のコマンドがあり、「標準入出力となっている端末デバイスの名前を表示する」コマンドみたいです。

$ tty
/dev/pts/1

同じ計算機上で複数ターミナルを起動しているときに/dev/pts/1/dev/pts/2があった時に/dev/pts/1側のターミナル上で

$ echo "hello" > /dev/pts/2

とコマンドを実行させると/dev/pts/2側のターミナル上にhelloと出力させることができるみたいです。

Dockerにおけるtty

run — Docker-docs-ja 19.03 ドキュメント

によると

疑似ターミナル (pseudo-TTY) を割り当て

だそうです。

tty: turecommand: /bin/bash

docker-compose.yml内でtty: turecommand: /bin/bashの処理を行わなければ、コンテナを起動させた時に、コンテナがすぐに終了してしまいます。これは、コンテナを起動させ続けるためのプロセスが存在しないため、コンテナが正常終了してしまうからです。そのため、今回はコンテナを動かし続けるため、ターミナル上でbashを実行させプロセスが無くならないようにしています。

おわりに

間違った内容等があったら、こっそり教えてください!

BMS始めた

久しぶりの投稿です。BMS熱が出てきて始めました。

使っているBMSプレイヤーについて

使っているBMSプレイヤーは beatoraja を使っています。もともと Lunatic Rave 2 を(3年前ぐらいに)使っていたのですが HD 化するのにいろいろとめんどうごとがあるみたいで、すぐに HD で遊べるように選択しました。次のサイトで色々と調べれます。

w.atwiki.jp

スキンは LITONE5 を使っています。次のサイトで取得できます。

desout2.tk

見た目は次のような感じで

f:id:karasuex54:20201222134741p:plain

プレイ中だと

f:id:karasuex54:20201222134821p:plain

のようになっています。(フレームや背景とかは見やすいように黒に染めています。ここは調整可能です。)

曲の入手について

BMSは曲が豊富ですので、探すのが一苦労です。特に、自分の実力にあった曲をたくさん入手するのは難しいと思っています。そんな中で 第2通常難易度表 という beatmaniaIIDX の難易度に合わせた難易度表がありこれを参考に曲を集めようと思います。探した中で便利だったのが以下の Twitter のアカウントにあるリンクでBMS第2通常難易度表の曲をまとめてダウンロードできます。

twitter.com

全部が全部集めれるとは限らないようです...

その他

コントローラーはキーボードで、s/d/f/space/j/k/l で皿は a/; で設定しています。

段位は GENOCIDE2018六段 が取れるぐらいでまだまだ練習中です。

8月に読み進める本

久しぶりの投稿です。意思表示の意も込めて読んでいく本を書いていこうと思います。

「ネット上に勉強する題材とかは大量にあるとあるんやけど、実際手に持たんと意欲わかん」

目標としては

「確率の基礎から統計へ」
f:id:karasuex54:20200730121016j:plain

「サポートベクトルマシン」
f:id:karasuex54:20200730121013j:plain

「たのしいバイナリの歩き方」
f:id:karasuex54:20200730121010j:plain

生協食堂のメニューをコスパ良く選んでみた

こんにちわ、からすさんです。お題通りに生協のメニューをコスパ良く選んでみました。

じゃあまずどういうことかってことを以下にまとめてみました。

  • 1食分の食品群(赤、緑、黄)を1食でちゃんと満たす
  • 1食に2品同じものが選ばれない
  • 食品群の他にも脂質や塩分の条件をつけくわえれる

以上の3点を満たしかつ値段を最小にしてくれるコスパのいいメニューを選びましょう!

問題設定

以下のような問題を最適化問題で表していきます。

  • 1品1回まで選択可
  • 食品群(赤、緑、黄)はそれぞれ(2点、1点、5点)以上とする。(これは男版)
  • 任意の栄養も調整可

以上を踏まえて今回解いていく最適化問題は次の通りです。

f:id:karasuex54:20200313235629p:plain

f:id:karasuex54:20200314000228p:plain

これは、線形計画問題でその中でも0-1整数計画問題と呼ばれる問題です。

解き方

解き方を書こうと思ったけどPythonPuLPというフリーのソルバーがあり、これにぶっこむだけで答えが返ってきます!この手のブログは解き方がメインだけど今回は「答えが出ればいい」だからね

PuLPは次のサイトからサンプルコードやいろいろを学んできました。

qiita.com

ソースコード

今回使用したコードはgithubに置いときますね。

github.com

いくつか注意しなければならない点があります。今回使用したソルバーPuLPをインストールする際に

pip install PuLP==1.6.0

とバージョンを1.6.0で使用しています。最新のバージョンでは動きませんでしたX(

使用例

python solver.py

でsolver.pyを実行します。そこで、いくつか入力を求められるので以下の入力を参考に使ってみてください。(なお答えがでなければ「not solve」が出ます。)

次のような条件で候補を出してみます。

  • エネルギーは1kcal以上1000klca以下
  • タンパク質は2g以上2000g以下
  • 脂質は3g以上3000g以下
  • 炭水化物は4g以上4000g以下
  • 塩分は0.5g以上50g以下
  • 赤は2以上200以下
  • 緑は1以上100以下
  • 黄は5以上50以下
1 1000
2 2000
3 3000
4 4000
0.5 50
2 200
1 100
5 50

これを入力して出力されるのは

['あじフライ', '肉じゃが', '春雨サラダ(しそ風味)', '大根おろし']
352.0

となります。1行目は品のリストで2行目はその合計金額です。実際に合ってるのかを調べてみて次に示します。

f:id:karasuex54:20200314003414p:plain

上の画像より、3点群やほかの栄養素の条件、金額があってることが確認できました。

もうすぐしたら新学期です。楽しい大学ライフを送りましょう!


二郎的なサムシング

本記事は「UEC Advent Calendar 2019」15日目の記事です.
昨日はおひげPさんの記事でした.

blog.mbsoftware.tokyo

これでみなさんも深層学習の準備ができたので
f:id:karasuex54:20191214234957j:plain
なんとかできそうですね!

はじめに

はじめましての方は初めまして.僕は一類MIのB4のからすさんです.卒論が近くてボスに「君は文章書くのが苦手だから心配だよ」ってご心配かけてしまって泣きそうです;;.


みなさん二郎って知ってますか?(画像は前に府中二郎で撮ってきたもの)
f:id:karasuex54:20191213024155j:plain
具体的な二郎の内容は延べませんが,二郎のwebアプリってあるといいなーって思いました.どんな機能があるといい...?
・現在位置から最寄りの二郎店までの距離
・店舗ごとの掲示
...今の自分の実力で作れそうな範囲で考えてみました.

ちなみに,今回のwebアプリ作るのにGo言語,Go言語のWebフレームワークのginとDBはSQLite3を用いました.


この記事では制作の過程ではなく,初歩的な内容を書いてます.


初めてのGo言語とwebアプリ制作でしたので間違ってるところも多いと思いますが温かい目で見て頂ければ幸いです.
ソースコード活動記録?はこちらです.下の内容すっとばしたい方向けなのでどうぞ.

環境

Windows 10 Home
go version go1.13.4 windows/amd64
SQLite version 3.28.0

基本

基本的なことを書いていきたいと思います.

ひな形を作ろう!

Go / Gin で超簡単なWebアプリを作る - Qiita を参考にまずひな形を作って,それにいろいろと付け足していこうと思います.
main.goファイルとindex.htmlファイルを以下の作ります.(index.htmlmain.go内のrouter.LoadHTMLGlob("templates/*.html")で場所を指定するのでそこに作っておいてください.)

main.go

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    router.LoadHTMLGlob("templates/*.html")

    router.GET("/", func(ctx *gin.Context){
        ctx.HTML(200, "index.html", gin.H{})
    })

    router.Run()
}

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Sample App</title>
</head>
<body>
    <h1>Hello World!!!</h1>
</body>
</html>

go run main.goで起動し f:id:karasuex54:20191214223231p:plain
ブラウザでhttp://localhost:8080/を表示すると f:id:karasuex54:20191214223405p:plain
上のように表示されたかと思います.
これでひな形(と動作確認)ができました.

次からはGoとhtmlとの挙動を見ていきたいと思います.

aタグ

index.html

<a href="/test">ここをクリック</a>

を追加しこれをクリックするとどうなるかを見ていきます.
main.goを起動した後に「ここをクリック」を押したら

404 page not found

と表示されたかと思います.
index.htmlからmain.goに「/testだお~」って送ったけども無いものは無いんで✋( ͡° ͜ʖ ͡°)
無かったなら作ればいい!ってことなのでmain.go内のmain関数内に

router.GET("/test", func(ctx *gin.Context){
    fmt.Println("クリックされたお")
    ctx.HTML(200, "index.html", gin.H{})
})

import "fmt"も忘れずに書きます.そして先ほどのタグをクリックすると f:id:karasuex54:20191214234530p:plain (ターミナルの方で)「クリックされたお」が表示され,ブラウザではindex.htmlが表示されたのではないかと思います.
先ほどの追加した

ctx.HTML(200, "index.html", gin.H{})

index.htmlを別の(例えば)hoge.htmlにするとhoge.htmlを表示させることができます.
200に関しては勉強不足なのであまり触れれないです.

gin.H{}って?

上の

ctx.HTML(200, "index.html", gin.H{})

で「gin.H{}ってなんぞや?」ってなりますよね.(なりますよね.)
簡単に説明するとhtml側に送る変数の中身です.
main.go内で

router.GET("/test", func(ctx *gin.Context){
    ctx.HTML(200, "index.html", gin.H{
        "text" : "クリックされたお",
        "number" : 16,
    })
})

index.html

<a href="/test">ここをクリック</a>
<p>{{.text}}</p>
<p>{{.number}}</p>

と追加しときます.先ほどと同様にクリックすると
f:id:karasuex54:20191215000706p:plain
↓↓↓↓↓↓↓↓
f:id:karasuex54:20191215000758p:plain
と表示させることができました.
もう少し詳しい話は

Gin(Golang)におけるHTMLテンプレート記述方法 - Qiita

を参考にするといいと思います.

リクエストの話

GETリクエストとPOSTリクエストの話を同時にしたいと思います.
index.html

<p>GET</p>
<form method="GET" action="/">
    <input type="text" name="get_text">
    <p><input type="submit"></p>
</form>
ここに入力した文字が出力されるよ「{{.get_text}}」
<p>POST</p>
<form method="POST" action="/">
    <input type="text" name="post_text">
    <p><input type="submit"></p>
</form>
ここに入力された文字が出力されるよ「{{.post_text}}」

main.go

router.GET("/", func(ctx *gin.Context){
    text := ctx.Query("get_text")
    ctx.HTML(200, "index.html", gin.H{
        "get_text" : text,
    })
})
router.POST("/", func(ctx *gin.Context){
    text := ctx.PostForm("post_text")
    ctx.HTML(200, "index.html", gin.H{
        "post_text" : text,
    })
})

としてください.
起動すると
f:id:karasuex54:20191215051550p:plain
method="GET"formで入力すると
f:id:karasuex54:20191215051910p:plain
URLを見てみると
f:id:karasuex54:20191215051928p:plain
name="get_text"としてたので/?get_text=hogehogeとなってますね.
GETリクエストされた後のmain.goではtext := ctx.Query("get_text")で値を取得していきます.
POSTの方も同様にURLには表示されませんが,text := ctx.PostForm("post_text")で取得してることがわかりますね.

データベースの話

Go言語のORMであるGORMを使ってSQLiteを操作しています.
まずはテーブルを作りたいので,例として以下のようなのを目指そうと思います.
f:id:karasuex54:20191215054129p:plain
main.goで構造体を次のように定義します.

type Student struct {
     gorm.Model
     Name string
     Num int
     Units int
     Gpa float64
}

テーブル名は構造体名が複数形になるのでStudentsになり,gorm.Modelにはid,created_at,updated_at,deleted_atのカラムが備わってます.
続いてmain.go内でDBを作ります.

func dbInit() {
    db, err := gorm.Open("sqlite3", "test.db")
    db.AutoMigrate(&Student{})
    defer db.Close()
}

gorm.Openの第二引数で作成するDBの名前,db.AutoMigrate()で構造体からテーブルを作成します.
次に値を入れてみましょう.

func dbinsert(){
    db, err := gorm.Open("sqlite3", "test.db")
    db.Create(&Student{Name: "からすさん", Num: 16000000, Units: 108, Gpa: 1.6357})
    defer db.Close()
}

やばいっすね...db.Create()で構造体とその中身の入ってるもので挿入してくれるみたいです.

まとめ

「これさえあればできる!」の(たぶん)最低限な内容を書いてみました.

さいごに

ボスの口癖に「違うよ」ってのがあります.(たぶん違います.)
読んでいただいた方の多くに「違うよ」って思うところがあったかと思いますが,後でこっそりと教えてくれると嬉しかったりします.
明日は mu_uec さんです.布教活動をされるみたいですけど技術系ではないって言ってるのが逆に怖いですね...((((;゚Д゚))))

前回の切手の問題をまた解く

お久しぶりです。プロジェクトオイラーの問題をときながら前回の記事の解決案を見つけたのでまた記事にさせていただきます。
参考とさせていただいた記事は次のもので、

nantonaku-shiawase.hatenablog.com

前回の解き方の間違ってる点ですが、例えば手元に「1円」と「2円」の切手があるとします。そこで3円分を作るときに、0円分の作り方、1円分の作り方、・・・、と0円から考えていくやりかたでした。そこで3円分を作る際に2円分の組み合わせと1円分の組み合わせを足してたため「2円」と「1円」それぞれ一つずつの組み合わせの重複を余分に足してしまっていました。
そこで、1円を使って何通り、1円と2円を使って何通り・・・と使う切手の枚数を徐々に増やしていく考え方を学びました。コードで書くと次のとおりです。

K = [1,2]
N = 3
KN = [[0]*(N+1) for i in range(len(K))]
for n in range(N+1):
    KN[0][n] = 1
for k in range(len(K)):
    KN[k][0] = 1
for k in range(1,len(K)):
    for n in range(N+1):
        if n//K[k]==0: KN[k][n] = KN[k-1][n]
        else: KN[k][n] = KN[k-1][n]+KN[k][n-K[k]]
for k in KN:print(k)

まず0円分を作るのはどの値段の切手を使っても1通りです。次に、1円切手だけ使っても全部1とおりです。
では、2円切手を使うとどうなるのか、KN[1][1]から考えていきたいと思います。KN[1][1]は1円分にたいして1円切手と2円切手の組み合わせで2円切手は1枚も使わず1円切手だけを使うのでKN[0][1]の値と同値。次にKN[1][2]に対しては、2円切手を1枚使う方法(KN[1][0])と1円切手だけを使う方法(KN[0][2])があるのでその和と同値。これを繰り返していきます。
そこで本題について書いていきたい。
上の雛形を用いて

K = [1,2,3,5,10,20,30,50,62,82,92,100,120,140,205,280,310,500,1000]
N = 1000
KN = [[0]*(N+1) for i in range(len(K))]
for n in range(N+1):
    KN[0][n] = 1
for k in range(len(K)):
    KN[k][0] = 1
for k in range(1,len(K)):
    for n in range(N+1):
        if n//K[k]==0: KN[k][n] = KN[k-1][n]
        else: KN[k][n] = KN[k-1][n]+KN[k][n-K[k]]
for k in KN:print(k)

となり、答えは1141266126310(約1.14兆)通りあることがわかった。(すげえ)

1000円渡されたら何種類の切手を買えるのか?

ことのほったん(と思われるの)は以下のツイートから

そしてこういう考えを思いついた人もいた
以下ここに書かれることは筆者の自己満足と自分の考えが正しいかがよくわからないため他人による評価を(ちょびっとだけ)もらいたいために書かれた記事であることを先に言っておく。あとMarkdownの書き方の練習も含めて

タイトルにもある通り「1000円で何種類の切手を買えるか」とあるがここでは「N円で何種類買えるか」という問題にしておく。
日本郵便さんによると切手は
1円、2円、3円、5円、10円、・・・、500円、1000円とあるそうだ。 www.post.japanpost.jp
この問題をDP問題として、次にPythonで書いたものを示す。

kinds = [1,2,3,5,10,20,30,50,62,82,92,100,120,140,205,280,310,500,1000]
dp = [1]
N = 10
for i in range(1,N+1):
  s = [dp[i-j] for j in kinds if i-j>=0]
  print(s)
  dp.append(sum(s))
  print(i,"円の時",dp[i],"通り。")

まずは考え方から、この問題を0円からスタートし1円を買うには切手のうちどれを使い1円未満の値段での買い方から選ぶという方針でやっている。
上のコードを出力すると

[1]
1 円の時 1 通り。
[1, 1]
2 円の時 2 通り。
[2, 1, 1]
3 円の時 4 通り。
[4, 2, 1]
4 円の時 7 通り。
[7, 4, 2, 1]
5 円の時 14 通り。
[14, 7, 4, 1]
6 円の時 26 通り。
[26, 14, 7, 2]
7 円の時 49 通り。
[49, 26, 14, 4]
8 円の時 93 通り。
[93, 49, 26, 7]
9 円の時 175 通り。
[175, 93, 49, 14, 1]
10 円の時 332 通り。

となり、配列sを出力することで思い通りに計算されてるかを確認することができる。例えば10円渡されて買うとき 残り1円切手で10円ぶんになる切手の種類から残り10円切手で10円ぶんになる切手の種類までを足せばいい
つまり、最後に買う切手を[1円切手、2円切手、3円切手、5円切手、10円切手]と考えたとき、この配列は
切手の種類が[9円のとき、8円のとき、7円のとき、5円のとき、0円のとき]と考えることができる。これらの種類を足せば10円渡されて買える切手の種類が出せる、と私は考えた。
おまちかね、1000円のときだが、上のNを1000にしたときの出力が

1000 円の時 2018816696222847406903248298783095971003454597950956950486814286870151769566638334351695889582461204439244633372769436724665312005396075530178629791204098410261766867285766690432361030106623128263952566362440060615017667935586334548238897367080748492851021980966669336418640390 通り。

恐ろしい数が出てしまって正直自分の考えがあってるとは思えなくなってしまった。

追伸:僕なら1000円渡されたら50円切手を20枚買うね。

追記(2019/06/12)

上の計算の仕方には問題点があった。
たとえば、3円渡された時を考える。
上のコードでは「1円切手、2円切手」と「2円切手、1円切手」を別々に計算している点だ。これでは切手の買う種類が爆上がりするのも納得いく。 まだ思いつかないけどね