Gaming Life

一日24時間、ゲームは10時間

最近読んだ本・漫画を振り返る 2019年10月編

読書メモとして、最近読んだ技術書、一般書、漫画で面白かった本をブログに残していこうと思う。一応2~3ヶ月に一度は書くつもりでいる。

技術書

通信・ネットワーク周り

マスタリングTCP/IP 入門編 第5版

マスタリングTCP/IP 入門編 第5版

マスタリングTCP/IP 入門編 第5版

最早私が説明するまでもない、コンピュータ通信技術入門の大名著。ある論文の紹介をする際、何度も読み返し、その度にわかりやすい説明に感銘を受けた。

アプリケーション層しか触らないような人でも読むべき。というかコンピュータに関わる技術者はみんな読むべき。

改訂三版 802.11高速無線LAN教科書

改訂三版 802.11高速無線LAN教科書 (インプレス標準教科書シリーズ)

改訂三版 802.11高速無線LAN教科書 (インプレス標準教科書シリーズ)

研究の参考に教授に勧められた本。発売が2008年ということで802.11nまでの情報しか乗ってないが、802.11x系の無線通信フレームのフォーマットについて、くどいほど詳しく書いてある。TCP/IPを一定程度理解した人間が、Wifi周りの勉強をする時はまず最初に読んで、間違いないと思う。早く.11ac対応版出て。

Linuxネットワークプログラミング

Linuxネットワークプログラミング

Linuxネットワークプログラミング

Linuxネットワークプログラミングバイブル

Linuxネットワークプログラミングバイブル

Linuxネットワークプログラミングバイブル

IPv6に対応した貴重なネットワークプログラミングの入門本。これがなかったら研究室でコードなにも書けないニートになるところだった。

ゲームプログラミング・3DCG関連

コンピュータグラフィックス [改訂新版]

コンピュータグラフィックス [改訂新版]

コンピュータグラフィックス [改訂新版]

CG-ARTS検定の参考書.たかが一民間試験の参考書と侮るなかれ.CGの基本を,カラーの画像や数式を交えながら事細かく説明している.これ一冊で,最新のCG技術を実装できるようになるわけでは無いが,足がかりにはなる.CG特有の専門用語をざっくりと学ぶのにおすすめ.

Effective Modern C++

Effective Modern C++ ―C++11/14プログラムを進化させる42項目

Effective Modern C++ ―C++11/14プログラムを進化させる42項目

モダンなC++を書くのには必携の本.C++を学ぶならこの本から,という入門本の立ち位置ではないのに注意.

C++ポケットリファレンス

[改訂第3版]C++ポケットリファレンス (POCKET REFERENCE)

[改訂第3版]C++ポケットリファレンス (POCKET REFERENCE)

正直これは買わなくてもよい,cpprefjpやらcppreferenceなど,Web上には無料で閲覧できる日本語のC++ライブラリの解説ページが存在するからだ.私は電車の中など,スマホで調べてもいいが,スマホを使うとゲームで遊んでしまいそうな時などによく読んでいる.

一般書

岩田さん 岩田聡はこんなことを話していた。

岩田さん 岩田聡はこんなことを話していた。

岩田さん 岩田聡はこんなことを話していた。

任天堂岩田聡社長の,生前のインタビュー記事をまとめた一冊.課題解決によって人を幸せにすることを最上の幸せとして生きた氏の生き方が詰まっている.

(Linux) UDPを使って一定時間おきに文字列を送信するプログラム

研究室でUDPを使った無線通信の受信側が受信待ち状態にない時のパケットキャプチャをする必要があったので書いた.

劣化iperfにすぎないとか言ってはいけない

#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

enum { DEST_PORT = 12345 };

void rand_text(int length, char* result) {
    int i, rnd_int;
    const char char_set[] = "01234567890abcdefghijklmnopqrstuvwkyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    for (i = 0; i < length; i++) {
        result[i] = char_set[rand() % strlen(char_set)];
    }
    result[length] = 0;
}

// ./main 192.168.20.2 7360(1パケットあたりのUDPデータ長[Byte]) 1(何秒間隔で送るか) count(合計何回送るか)
int main(int argc, char* argv[]) {
    if (argc < 5) {
        printf("command line arguments is invalid!\n");
        return 1;
    }
    const char* dest_addr = argv[1];
    const int udp_data_len = atoi(argv[2]);
    const int interval_sec = atoi(argv[3]);
    const int count_max = atoi(argv[4]);

    printf("Send random data(%dByte) %dtimes to %s through UDP to every %d sec\n", udp_data_len, count_max, dest_addr, interval_sec);
    char* str;
    str = (char*)malloc(sizeof(char) * udp_data_len);
    srand(time(NULL));
    rand_text(udp_data_len, str);
    printf("create string strlen(%ld)\n", strlen(str));

    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(DEST_PORT);
    addr.sin_addr.s_addr = inet_addr(dest_addr);

    int count = 0;
    while (count < count_max) {
        printf("send %ldByte\n", strlen(str));
        sendto(sock, str, strlen(str), 0, (struct sockaddr*)&addr, sizeof(addr));
        printf("----------\n");
        sleep(interval_sec);
        count++;
    }
    free(str);
    return 0;
}

30分程度で書いた使い捨てのプログラム故,エラー処理が一切書いてないのに注意.

std::bindではデフォルト引数を省略できない

std::bindを使っていたらある問題に遭遇した。

void func(int a){
    std::cout << a * 10 << std::endl;
}
int main(){
    using namespace std::placeholders;
    auto fuction = std::bind(func, _1);
    function(2);
}

std::bindを使ってライブラリで用意されている関数を束縛し別のところで呼び出す、といったことをしたかったのだが、これが何故かコンパイルが通らなかった。(実際は、クラスのメンバ関数をbindした。簡単のためそのコードはここに示す

なぜだろうか……といろいろ調べて回ったところ、とても単純な話だった。

void func(int a, int b = 10){
    std::cout << a * b << std::endl;
}
int main(){
    using namespace std::placeholders;
    auto fuction = std::bind(func, _1);
    function(2);
}

引数1つで呼び出すものと思っていたfunc()関数が、実際は第2引数にintを取る関数で、それにデフォルト引数が設定されていた。じゃあどうやってこの関数を束縛すればいいかというと、bind時、デフォルト引数も明示的に渡せばよい。

// Error!
// auto function = std::bind(func, _1);

// OK!
auto function = std::bind(func, _1, 10);

// call
function(2);

wandbox.org

bindは使うべきではないという話

ここまでbindを使って関数を束縛してきたが、調べてみると、bindはパフォーマンス上に問題があるらしい。

じゃあ代わりに何を使うのかっていうと、みんな大好きラムダ式である。

// Error!
// auto function = std::bind(func, _1);

// OK! (low performance)
auto function = std::bind(func, _1, 10)

// OK! (high performance)
auto function = [=](int _1){ func(_1); };

// call
function(2);

Compiler Explorerbindラムダ式を比較してみると一目瞭然でパフォーマンスにかなり影響することがわかる。

まとめ

bindなんか使わずラムダを使おう。

VSCodeでAsciidocを書く時相対パス入力補完を働かせる

当ブログで何度か紹介しているAsciidocだが,仕様書を書いたり,レポートを書いたりするのに非常に重宝している.

ただ,画像挿入時などで,相対パスの記述をする時に,Path InteliSenceによる入力補完が効かないことがとにかく不便だった.

import {} from './include/hogehoge'  // 引用符で囲む時は補完が効く
image::./img/sample.png     // 引用符で囲んでいないので補完が効かない

この度この問題を解決出来たのでメモ.

Path Autocompleteによるパス入力補完

まず,Path Intelisenceを入れている場合はアンインストールし,代わりに,Path Autocompleteを導入する.

marketplace.visualstudio.com

ただ,Path Autocompleteのデフォルト設定のままでは,目的の入力補完が効かない.

  • Path Autocompleteのデフォルト設定
import {} from './include/hogehoge'  // 引用符で囲む時は補完が効く
image::./img/sample.png     // 引用符で囲んでいないので補完が効かない

Path Autocompleteの設定の内, path-autocomplete.triggerOutsideStringstrueにすると,引用符で囲まなくても入力補完が効くようになる.

しかしながら,これでも,目的の入力補完が効かない.

  • Trigger Outside Strings On
import {} from './include/hogehoge'  // 引用符で囲む時は補完が効く
./img/sample.png            // 引用符で囲まなくても補完が効く
image::./img/sample.png     // ':' と './'の区切りを認識出来ないので補完が効かない.

path-autocomplete.pathSeparators は,文と ./ の区切りを定義している.ここに,: を加えることで, image::./img/sample.png と入力する時も,相対パスの補完が効くようになる.

まとめ

  1. Path Autocompleteを導入
  2. path-autocomplete.triggerOutisideStringsをtrueに設定
  3. path-autocomplete.pathSeparatorsに : を追加
  4. おわり!

プログラミングに関する調べ物や最新技術のキャッチアップ方法

※注 ポエム要素が高い記事です

最近は研究室で忙しく、ブログに公開できるようなネタになるようなことをやれないでいる。 しかし、月イチ更新は守りたい → じゃあプログラミングを始めた頃の自分が知りたかった情報を書こう → プログラマーってどうやって最新技術を追いかけて、わからなかったことを調べているんだ、と当時考えていたことを思い出す

というわけで、今の自分が実践している、プログラミングに関する調べ方、最新技術のキャッチアップ方法をつらづらと書いていく。

Google検索

まずはここから。どんなときも、わからないことがあったらGoogleに聞けば大体解決する。しかしながら、ここ最近のプログラミング関連のワードの、Google日本語検索の上位に出てくる記事は くだらないゴミ記事 正しい情報が書かれていないモノが増えてしまい、求めている、正確な情報には簡単にたどり着けなくなっている(特にPythonとか酷い)。あまりにも酷いサイトは、ブラウザの拡張機能で検索結果に表示されなくするのが吉。(FireFoxユーザの私はPersonal BlockList を使っている)

初学者の内は日本語情報でも十分だが、そのうち、日本語情報では不足するようになる。そういったときは、公式リファレンスや、Stack Overflow、Google英語検索を利用している。英語が読めなくても近年の機械翻訳は相当な精度なので、十分読めている。

書籍

信頼と安心の情報源。古い本だと、最新の環境で使えないことがままあるが、それでも、基礎を抑えるには最良の手。なにか新しい言語、ライブラリに挑戦するときは、まず、書籍を当たるようにしている。

また、特に買う予定の本もないのに本屋に行く事も続けている。何か行き詰まっていたり、求めている機能を提供してくれるソフトが見当たらなかったりした時、本屋に行くと答えがあったりする。そして買う予定のなかった本を買って財布が薄くなる。

はてなブックマーク

Qiitaやら、ITMediaやら、engadgetやら、各サイトそれぞれ見にいくってのも一つの手ではあるが、毎日全部見るというのは、現実的には難しい。私は、代わりにはてブテクノロジーカテゴリのトレンド を一通り見ている。 トレンドに上がっている中で、気になる情報があればそのサイトに飛んでみるし、タイトルだけ見ておくだけでも、最新トレンドを知(った気にな)ることができる。

Twitter

その分野の第一人者とも言えるような人をフォローし、 TweetDeck でその人の全ツイートを追っかける、みたいなストーカー的ムーブができる。真似しないほうがいい。

最近、ハマっているのは、エラーに悩まされていたり、ソフトの使い方がわからなかったときに、Google検索の前に、Twitter検索で調べるということ。「Python リスト」みたいなざっくりした検索ワードだと、なんの役にも立たないが、エラー番号等、詳細なキーワードで検索すると、Google検索するより早く解決することがある。

興味のある技術分野に関わる人々を沢山フォローすると、TLを眺めているだけで有益な情報が集まってくる。

デメリットはTwitterにハマりすぎて、作業が疎かになりがちなこと。(そしてこれが最近の悩みでもある)

まとめ

こういって調べ事をしていると、最初の内は何のことかわからないワードだらけだが、継続は力なり。いずれ理解できる日が来る。そして1理解すると10理解できない事が生まれ、またそれを調べる。プログラマーとはそうやって永遠に終わりのない調べ物をし続ける生き物なのだなぁとつくづく思う近頃。これからも続けていきたい。

Dungeon Template LibraryをUE4で利用してLandscapeを自在に操る

@wanotaitei さんが開発しているDungeon Template Library(以後DTL) がUE4で使えそうだったので使ってみた。

f:id:ai_gaminglife:20190518201300g:plain

github.com

画像

UE4でDTLを使えるようにする

上記リンクからDTLをcloneしておく。

C++プロジェクトとしてUE4プロジェクトの Source/ 以下に library/DTL ディレクトリを作成。そこに、DTLライブラリの include 以下をコピーする。

UE4プロジェクトを開き直し、 (プロジェクト名)Build.cs に以下を記述。

        PublicIncludePaths.Add(ModuleDirectory + "/library/DTL/");

        PrivateDependencyModuleNames.AddRange(new string[] { "Landscape", "LandscapeEditor" });

これで、DTLと、後に使うLandscape関連の関数が利用できるようになる。

Landscapeを操作する関数を実装する

BlueprintFunctionLibraryを継承したクラスを作成し、以下をコピペ。

  • DTLLandscapeControlInEditor.h
#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "DTLLandscapeControlInEditor.generated.h"

UCLASS()
class DTLSAMPLEUE4_TPS_API UDTLLandscapeControlInEditor : public UBlueprintFunctionLibrary
{
    GENERATED_BODY()

    UFUNCTION(BlueprintCallable, Category = DTL, meta = (HidePin = "worldContextObject_", DefaultToSelf = "worldContextObject_"))
    static bool perlinNoise(const UObject* worldContextObject_, float scale);
};
  • DTLLandscapeControlInEditor.cpp
#include "DTLLandscapeControlInEditor.h"

#include "EngineUtils.h"
#include "Landscape.h"
#include "LandscapeInfo.h"
#include "LandscapeEditor/Public/LandscapeEditorUtils.h"

#include <DTL.hpp>

bool UDTLLandscapeControlInEditor::perlinNoise(const UObject* worldContextObject_, float scale)
{
    UWorld* world = worldContextObject_->GetWorld();
    for (TActorIterator<ALandscape> actorItr(world); actorItr; ++actorItr)
    {
        ALandscape* landscape = *actorItr;
        if (landscape != nullptr)
        {
            // 2: ULandscapeInfoの初期化
            ULandscapeInfo::RecreateLandscapeInfo(world, false);

            FIntRect rect = landscape->GetBoundingRect();
            int32 w = rect.Width() + 1;
            int32 h = rect.Height() + 1;

            using shape_t = uint16;
            std::vector<std::vector<shape_t>> matrix(h, std::vector<shape_t>(w, 0));
            constexpr double frequency = 6.0;
            constexpr uint8_t octaves{ 16 };
            const uint32_t seed{ static_cast<uint32_t>( rand() ) };

            const dtl::utility::PerlinNoise perlin(seed);
            double frequency_x{ w / frequency };
            double frequency_y{ h / frequency };

            for (std::size_t row{}; row < h; ++row)
                for (std::size_t col{}; col < w; ++col)
                    matrix[row][col] = static_cast<shape_t>(50.0 * perlin.octaveNoise(octaves, col / frequency_x, row / frequency_y));

            TArray<uint16> Data;
            Data.Init(0, w * h);
            for (auto x = 0; x < w; x++)
            {
                for (auto y = 0; y < h; y++)
                {
                    Data[x * h + y] = static_cast<uint16>(FMath::FloorToInt(scale * matrix[y][x]));
                }
            }

            LandscapeEditorUtils::SetHeightmapData(landscape, Data);
            return true;
        }
    }
    return false;
}

エディタ側からコンパイルし、通れば成功。

実装した関数を呼び出すActorを作成

Actorを継承したブループリントクラスを作成。画像のようなBPを組む。この際、EventPerlinNoiseCall in Editor フラグにチェックを、Scale float変数は、Instance EditableExpose on Spawn にチェックを入れる、

f:id:ai_gaminglife:20190518201112p:plain

作成したActorを 適当にレベルに配置、続いて、Landscapeを作成し、機能別サンプルから取ってきたLandscape Material を適当に割り当てて上げれば完成。

まとめ

現在エディタ側からしかLandscapeを操作出来ないが、ランタイムでLandscapeを操作できると嬉しい。また、まだ試してないが、他のダンジョン生成関数との連携は簡単にできそう。

参考サイト

unwitherer.blogspot.com

WSLのUbuntu18.04でmatplotlibを使えるようにするまで

WSLのUBuntu18.04はGUI表示が存在しないので、matplotlibを使ったグラフ描画ができない。だが、調べてみると、何とか描画できるようにできたので、メモしておく。

前準備

> sudo apt update && sudo apt upgrade
> sudo apt install python3-pip

matplotlibの導入

pip3を使ってmatplotlibと、セットで使われがちなnumpyを導入しておく

> pip3 install numpy
> pip3 install matplotlib

matplotlibを使った参考プログラム

vim等のエディタを使って、以下のコードを入力

> vim sampleGraph.py
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.random.randn(100)
plt.plot(x, y)
plt.show()

これを実行してみる。

> python3 sampleGraph.py

この時点で Tkinterがないだのというエラーが出たら、以下のコマンドを実行

> sudo apt install python3-tk
> sudo apt install tk-dev

ウィンドウに描画できるようにする

sourceForgeで、VcXsrvをDLする。

インストーラーでは特に追加設定の必要なし。指示通り勧めていけばよい。

インストールが終わったら、Windowキーを押し、XLaunchを実行する。

デフォルト設定のまま進め、完了を押す前にSave configurationを押し、設定ファイルをわかりやすいところ、例えばデスクトップに保存しておく。

完了を押せば、XLaunchが起動する。

WSLに戻って、以下のコマンドを実行。

> sudo vim ~/.bashrc

最後の行に以下を追加して保存する。

export DISPLAY=:0.0

WSLを再起動(ウィンドウを閉じるか、exitすれば良い)すればこの設定が読み込まれて、設定が反映される。

この後pythonを実行すると

> python3 sampleGraph.py

f:id:ai_gaminglife:20190429204952p:plain

こんな感じでウィンドウが表示されるようになる。