雑記帳(@watagasi_)

【Unity】ゲーム制作中

「Unity2日目」とか書いた記事から何も続きがないのでまた三日坊主になったかと自分で(?)思っていましたが、ちゃんとゲーム作ってます。

 

毎日作業してるとブログとか書く暇ないですね。

 

今はこの動画を参考にしながらC#の勉強をしつつUnityでゲーム作って遊んでます。

www.youtube.com

 

この動画の人、全部Javaでコード書いてるので、それをC#に書き直してるんですけど、それが結構いい勉強になっています。

 

今は衝突判定を上手く記述できなくて詰まっています。タイルマップを使った形式のゲームを作ってると、タイル同士が斜めに配置されていても、それぞれの角が接触してるんでそれらが衝突していることになっちゃうんですよね。上手く解決できるんでしょうか。

 

いくらかゲームとして遊べるようになったら、テキトーな素材を貼っつけて公開したいと思います。

 

 

pythonで遊んで2週間ぐらいの人間がword2vecで遊べるようになるまで【python】

pythonで遊んで2週間くらい経ったので、自然言語処理?とかそういうの?やってみようかなと思ってword2vecで遊んでみることにしました。

 

今回は、そこに至るまでの環境構築でどんだけ躓いたか記しておきます。

 

全体的に、雑にザックリ書いているのでロクなものだと思わないでください。

 

 

 

とりあえずツイッター上のツイートを集めて遊ぼ~と思ったので、ツイートを集めてみました。

 

コードはここから全部コピペです。

ailaby.com

ツイートをテキストファイルで保存する必要があるので、最後のmain文はちょっと弄って以下のようにしています。

 

if __name__ == '__main__':

# キーワードで取得
getter = TweetsGetter.bySearch(u'けもフレ')

# ユーザーを指定して取得 (screen_name
# getter = TweetsGetter.byUser('AbeShinzo')

f1 = open("kemofre_tweet.txt", "w", encoding="'utf_8-sig")

cnt = 0
for tweet in getter.collect(total=300000):
cnt += 1
print('------ %d' % cnt)
print('{} {} {}'.format(tweet['id'], tweet['created_at'], '@' + tweet['user']['screen_name']))
print(tweet['text'])
if "http" in tweet['text']:
print("This tweet incldes http")
elif "@" in tweet['text']:
print("This tweet incldes @")
elif "RT" in tweet['text']:
print("This tweet incldes RT")
else:
f1.write(tweet['text']+"\n")

f1.close()

 

流行りの言葉で遊ぼうと思ったので「けもフレ」を含んだツイートを3万件ほど取得しました。

 

あとでデータ整形するのが面倒なんで、「http」「@」「RT」を含んだツイートは予め除いておきました。除いたツイート数は2000件くらいだったので、まあ誤差でしょう(?)

 

 

 

次に、word2vecにデータを突っ込むにはMeCabとかいうやつで品詞分解しなきゃならんらしいので、MeCabを導入しました。

 

これがもうね、ホントめんどくさかったです。1つのサイトだけ見ても問題解決できなくて、最終的にWindows死ねってなりました。

 

まずここを参考にしました。

y-mattu.hatenablog.com

で、上手くいかなかったのでここを参考にしました。

qiita.com

それでも「error: Unable to find vcvarsall.bat」ってエラーが出るので、最初のブログに書いてあったここを参考にしました。

isiz.hateblo.jp

「なんかVS2015 Community入れろって書いてあるけどもう入ってるしなあ…」とか思いながら再インストールするも、エラーが治らない。

 

ここでウンウン唸りながら調べるとこのブログが出てきました。

thinkami.hatenablog.com

Visual Studio Community 2015でVisual C++ 2015用の共通ツールをインストールすれば、ビルド・インストールできます。

 

それならそうとちゃんと書いといてくれや!と思いながら、最初から手順をやり直し、ようやくMeCabが使えるようになりました。ヤッター。

 

 

 

で、MeCabを使って形態素分析してみたのですが、まず肝心な「けもフレ」をちゃんと品詞として認識してくれない。

 

これはMeCabの標準の辞書に「けもフレ」という単語が入ってないからです。まあ入ってたらびっくりですよね。

 

というわけで「MeCabで最新の単語に対応したければ、はてなキーワードcsvwikipediaのタイトルのcsvを変換して、ユーザー辞書に登録すればいいよ!」という知見を得て、このブログを参考にしました。

yukihir0.hatenablog.jp

例によってコードは全コピペです。インターネットの皆さんありがとう。

 

これではてなキーワードとかのcsvファイルを、MeCabの辞書に適したcsvに変換できる~~~!と思ったらまたダメでした。問題は文字コードのようです。

 

原因は、csvファイルをちょっと弄ったときにLibreOfficeで保存したせいでした。

 

だって「けものフレンズ」は、はてなキーワードに入ってるのに「けもフレ」は入ってないんですよ。弄って追加するしか無いじゃないですか。

 

めんどくせえ…と思いつつ、「SmoothCSV」なるもので編集することにしました。

smoothcsv.com

 

 

csvファイルが出来たので、MeCabで使えるようにdicファイルに変換します。

 

この辺を参考にして変換しました。「mecab-dict-index」って命令使えば良いんだなってことがわかり解決です。

Window PCでMeCabの辞書を追加する方法 - 楽楽研究室

MeCab: 単語の追加方法

 

dicファイルを適切な場所において、よ~しもう一回MeCabで分解だ~!と思ったら「けもフレ」を認識してくれない。

 

原因はユーザー辞書を指定するmecabrcにあるのはなんとなくわかったんですが、どうしたらいいかわからない。

 

なんとなく「;userdic = ”ユーザー辞書のディレクトリ” 」ってなっていたのを、最初の「;(セミコロン)」を外して「userdic = ”ユーザー辞書のディレクトリ” 」とすると、ちゃんと認識してくれた!

f:id:watagassy:20170305184031j:plain

コメントアウトになってたわけですね。わかんねーよ。

 

その後は。MeCabで出力された文章から句読点を取り除くだけの雑な整形をし、以下のブログを参考にモデル作成とword2vecの試験をやってみました。

m0t0k1ch1st0ry.com

今回は「けもフレ」というワードで収集したツイートがデータの元なので、「サーバル」という単語に類似度が近いものを調べてみました。

 

それが以下です。

f:id:watagassy:20170305184556j:plain

うん、「かばん」って単語が一番上に来てる時点でまあまあいい感じじゃないでしょうか。

 

もう少しツイート集めたら制度上がるかな?と思って6万件くらい集めて同じことやってみたのが以下です。

f:id:watagassy:20170305184858j:plain

そこまで変わりませんね。データの整形やword2vecに突っ込むときのデータの形式、そもそものコーパスの作り方なんかを良くしていくと、もっと関連したワードが出てくるかもしれません。

 

 

 

以上がword2vecで遊べるようになるまでの軌跡でした。

 

インターネッツの叡智を集めればほぼ全コピペでもpythonで結構遊べるぞ、という参考になれば幸いです。

【言語処理100本ノック】04. 元素記号【python】

03でだらだらプログラム書いていたんですけど↓

watagassy.hatenablog.com

なんと3行で済むみたいですね。はい。

 

s = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."

count = [len(i.strip(",.")) for i in s.split()]

print(count) 

参考:Python初心者が少しずつ言語処理100本ノックを頑張るエントリー - KAZUMA IEIRI

 

プログラム書きなれていないとこうなるわけです。

 

というかfor文ってこんな書き方できたんですね~。

 

これを「count = [len(i) for i in re.split("\W+",s).pop()]」とすれば自分の書いたプログラムだな~…と思ったら違いますね。

 

pop()は配列の最後の値を削除した後、削除した値を返すのであって、元の配列を返してくれるわけではありません。

 

じゃあ「re.split("\W+",s).remove("")」か?と思いましたが、これも違います。remove()は削除をしてくれるだけで、やっぱり元の配列を返してくれるわけではありません。

 

配列の要素を削除した後の配列を返してくれる関数は、自分の探した範囲だとないみたいで、多分あったとしてもメジャーじゃない、ってことかな?

 

ということは、re.split()よりもsplit()とstrip(",.")を重ねる方が、単語分解においては賢いのでしょうか。勉強が必要ですね。

 

 

ではお題を見ていきましょう。

"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字,それ以外の単語は先頭に2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

 

 今回はいくつかコードを書いてみたので、それぞれ見ていこうと思います。

 

まず最初に書いたのがこれ。

 

import re
test_str = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."

result = re.split("\W+",test_str)
result.pop()
char_list = []

for
i in range(len(result)):
char_list.append(list(result[i]))

dic1 = {}
char_listz = []

for
i in range(len(char_list)):
if i == 0 or i ==4 or i ==5 or i ==6 or i ==7 or i ==8 or i ==14 or i ==15:
dic1[char_list[i][0]] = i+1
else:
char_listz.append(char_list[i][0])
char_listz.append(char_list[i][1])
dic1["".join(char_listz)] = i+1
char_listz = []
print(dic1)

 

う~ん、汚すぎる。

 

上記の反省を生かす前なのでこんな感じです。pop()は前回に引き続き余計な感じで、変数もいちいち宣言しすぎですね。

 

これ、いったん文を単語に分解して、さらに単語を文字に分解したリストを作って、そしてそのリストの番号が指定されたものだったら、単語を2文字append、そうでなかったら1文字appendとかやってるんですけど。

 

さっきの方のブログ見るとまあひどいですねこれ。pythonの文字の扱いやすさを全くわかってない。あとfor文あたりの考え方もC言語のまんまっぽい。

 

というわけで反省して書き直したのがこちら。

s = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."

dic = {}
for i,word in enumerate(s.split(), 1):
if i in (1, 5, 6, 7, 8, 9, 15, 16, 19):
dic[word.strip(".")[:1]] = i
else:
dic[word.strip(".")[:2]] = i

print(dic)

まあきれいになりましたね。いい感じではないでしょうか。

 

 

 

ここで上記のブログの方がどう書いているか見てみました。

s = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."
dic = {word[:2-(i in (1,5,6,7,8,9,15,16,19))]:i for i, word in enumerate(s.replace(".", "").split(), 1)}
print(dic)

 

????????

 

一瞬意味が分かりませんでしたがよく見ていきます。

 

一応for以下は自分とだいたい同じなのでわかります。それ以外ですね。

 

まず第一の問題は[:2-(i in (1,5,6,7,8,9,15,16,19))]の部分です。最初見たとき「なんでこれで2文字と1文字のスライスが区別できるんだ????」って思いました。

 

 

そしていくつか試してみて合点がいきました。

 

突然ですが、pythonで「print(5-True)」と入力するとどうなるでしょうか?

 

答えは「4」が返ってきます。[:2-(i in (1,5,6,7,8,9,15,16,19))]の部分はこれを利用しているんですね。

 

「i in (1,5,6,7,8,9,15,16,19)」は、iが該当の数字であったときTrueを返します。

 

で、条件に合ったときに「2-True」が計算されて「1」になり、文字列の先頭1文字だけ取り出せるんですね。

 

こういうのってプログラミング慣れてる人は普通なんでしょうか?「python初心者とか言っときながら自分とスタート地点全然ちげーじゃねえか」ってキレそうになりました。

 

 

そう、そして第二の問題はディクショナリへの要素の追加が「dic ={a:b}」という形で行われていたことです。

 

ディクショナリに要素を追加するときは「dic[a]=b」みたいに書けってどこにでも書いてあるんですが、この人はどこから「for文を回せばdic ={a:b}の形式で書ける」と知ったのでしょう。絶対初心者じゃないですよね。

 

 

とりあえずpythonは短くスマートに書こうと思えばいくらでもそのようにできるという学びは得たので、次からはもっとペース挙げてやっていきましょう。

【言語処理100本ノック】03. 円周率【python】

言語処理100本ノックです。

www.cl.ecei.tohoku.ac.jp

 

なんで03からかというと、02までテキトーにやりすぎててpython的な書き方ちゃんと出来てないのでは?って具合で記事にするのが恥ずかしかったからです。

 

まあ100本ノックしながらpythonの勉強しているので、結局はまだ恥ずかしい感じだとは思いますが、とりあえず書いていきましょう。

 

 

お題は以下です。

 

"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

 

与えられた文章をまず単語に分解してリストにつっこみ、その単語それぞれの長さを取得したリストを作ってしまえば良さそうですね。

 

ではいきましょう。

 

import re

test_str = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
result = re.split("\W+", test_str)

re.split("\W+",文字列)って書いとけば、単語に分解してくれるんだって。便利ですね。

 

\Wが何なのかは「正規表現 W」とかで調べれば出てくると思います。

 

resultの中身は今こんな感じ。

>>>['Now', 'I', 'need', 'a', 'drink', 'alcoholic', 'of', 'course', 'after', 'the', 'heavy', 'lectures', 'involving', 'quantum', 'mechanics', '']

 いい感じですね。ただ最後に空の文字列が来るのは邪魔なのでresult.popで排除しておきましょう。

 

import re

test_str = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
result = re.split("\W+", test_str)
result.pop()

list1 = []
cr = len(result)
for i in range(cr):
list1.append(len(result[i]))

 次は単語それぞれの文字数を格納するリスト、list1を作ってそこに文字数をぶち込みます。

 

len(result[i])で各単語の文字数を取得できるので、それをappendでぶち込んでおけばいいですね。

 

何回ぶち込んだら良いかはresultの要素数と一致するんで、先にlen(result)で要素数を取得してcrってのに入れて、forで回していきましょう。

 

この時list1の中身はこんな感じ。

>>>[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

 はい、いい感じですね。

 

もっと簡単にやる方法があるかもしれませんが、今はこんなところで。

 

あとキレイにコード書きたいですね。いろいろ勉強していきましょう。

 

Unity1日目

Unity始めます。やるからには目標があるのが良いので何かあれば良いんですが、今は特にないです。

 

というわけでチュートリアルやりました。

github.com

f:id:watagassy:20170226171016j:plain

玉転がしができるそうです。ヤッター!

 

webGLで出力してunityroom(ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう)にて公開しようかと思ったのですが、なぜかunityroomで遊べない…。

 

Uncaught incorrect header check!とか出てくるんで、firefoxで起動してみたりとかいろいろしましたがムリ。

 

当面の間はおとなしく粛々とゲーム作ることにします。

【ピカ・チャン】さようなら、バトルおにいさん~彼の奇行を振り返ろう~

みなさん、ピカ・チャンという番組をご存知でしょうか?

f:id:watagassy:20160825181929j:plain

 

「ピカ・チャン」は、ポケモンバトルの楽しさを伝えるためにYoutubeで配信されている、公式のポケモン番組です。

 

毎月2回、隔週水曜日で配信されていました。(以下は1話のリンクです)

続きを読む