2019年9月29日日曜日

Ansible で Inventory ファイルに記載されている IP 情報を取得する方法

概要

Inventory ファイルに記載されている IP アドレスを playbook 内で使いたい場合はあると思います
そんな場合には Magic Variables を使いましょう

環境

  • CentOS 7.7.1908
  • ansible-playbook 2.8.5

サンプルコード

debug_hosts グループ内で定義されているホストの IP アドレスを取得してみたいと思います

  • vim main.yml
- hosts: target
  tasks:
    - name: debug inventry
      vars:
        msg: |
          {% for item in groups['debug_hosts'] %}
          {{ hostvars[item].ansible_host }}
          {% endfor %}
      debug:
        msg: "{{ msg.split('\n') }}"
#      debug:
#        msg: "{{ groups }}"

インベントリファイルは以下の通りです

  • vim inv
target:
  hosts:
    localhost:
      ansible_host: 127.0.0.1
debug_hosts:
  hosts:
    host1:
      ansible_host: 192.168.200.10
    host2:
      ansible_host: 192.168.200.11

ansible 自体は localhost に実行します

実行

  • ansible-playbook -i inv main.yml

結果

ok: [localhost] => { "msg": [ "192.168.200.10", "192.168.200.11", "" ] }

解説

まず groups 変数にインベントリファイルに定義したグループの情報が含まれています
ただ groups にはホスト名までの情報しかなく IP アドレスの情報は含まれていません
そこで登場するのが hostvars です
これもマップで管理されておりホスト名をキーにするとそのホストの情報が取得できます
その中に ansible_host というフィールドがありここで IP アドレスを管理しています

サンプルでは debug + template を使っていますが playbook ないで使う場合は好きなリソースを使ってください
また見やすくするように一旦 vars を使っていますがこれも playbook 内では不要かなと思います

参考サイト

2019年9月28日土曜日

Terraform vSphere 最速入門

概要

とりあえず動かしてみたい人向けです
クローン元の VM は事前に作成してあることが前提です

環境

  • vSphere 6.7.0.30000
  • terraform v0.12.1
  • CentOS 7.7.1908

事前準備

今回はクローンすることで VM を作成します
またストレージやネットワークなども事前に準備済みとします

tf ファイル

おそらくクローンで VM を作成する際の最低限の設定になります

  • vim resources.tf
variable "vsphere_user" {}
variable "vsphere_password" {}
variable "vsphere_server" {}

provider "vsphere" {
  user           = "${var.vsphere_user}"
  password       = "${var.vsphere_password}"
  vsphere_server = "${var.vsphere_server}"

  allow_unverified_ssl = true
}

data "vsphere_datacenter" "dc" {
  name = "dc1"
}

data "vsphere_datastore" "datastore" {
  name          = "datastore1"
  datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_compute_cluster" "cluster" {
  name          = "cluster1"
  datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_network" "network" {
  name          = "network1"
  datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_virtual_machine" "template" {
  name          = "seed_vm1"
  datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

resource "vsphere_virtual_machine" "vm" {
  name             = "terraform-test"
  resource_pool_id = "${data.vsphere_compute_cluster.cluster.resource_pool_id}"
  datastore_id     = "${data.vsphere_datastore.datastore.id}"

  num_cpus = 2
  memory   = 1024
  guest_id = "${data.vsphere_virtual_machine.template.guest_id}"

  scsi_type = "${data.vsphere_virtual_machine.template.scsi_type}"

  network_interface {
    network_id   = "${data.vsphere_network.network.id}"
    adapter_type = "vmxnet3"
  }

  disk {
    label            = "disk0"
    size             = "${data.vsphere_virtual_machine.template.disks.0.size}"
    eagerly_scrub    = "${data.vsphere_virtual_machine.template.disks.0.eagerly_scrub}"
    thin_provisioned = "${data.vsphere_virtual_machine.template.disks.0.thin_provisioned}"
  }

  clone {
    template_uuid = "${data.vsphere_virtual_machine.template.id}"

    customize {
      linux_options {
        host_name = "terraform-test"
        domain    = "test.internal"
      }

      network_interface {
        ipv4_address = "192.168.100.11"
        ipv4_netmask = 24
      }

      ipv4_gateway = "192.168.100.1"
    }
  }
}

動作確認

  • terraform init
  • terraform plan -var 'vsphere_user=administrator@vsphere.local' -var 'vsphere_password=xxxxxxxxxx' -var 'vsphere_server=192.168.100.10'
  • terraform apply -var 'vsphere_user=administrator@vsphere.local' -var 'vsphere_password=xxxxxxxxxx' -var 'vsphere_server=192.168.100.10'

削除

  • terraform destroy -var 'vsphere_user=administrator@vsphere.local' -var 'vsphere_password=xxxxxxxxxx' -var 'vsphere_server=192.168.100.10'

軽く解説

使っている terraform の機能 (リソース) は variable, provider, data そして resource になります
実際に VM を作成しているのは resource になります

variable はその名の通り変数を定義しています
今回は vCenter の「ログインユーザ名」「パスワード」「アドレス」を変数にしています
.tf ファイル内に書いても問題ないですが今回は実行時に引数で実行するようにしました

providervSphere Provider を使う定義をしています
変数で設定した認証情報はここに設定します

data は vSphere 内の各リソース (データセンターやクラスタ、データストア、ネットワーク、テンプレートなど) を定義します
各リソース内で datacenter_id を指定しています
これは Moref で取得できる ID で名前ではありません
terraform では ${data.vsphere_datacenter.dc.id} という感じで事前に定義したデータセンターの data を使うことで自動的に Moref からデータセンターの ID を引っ張ってきて設定してくれます
ID を引っ張ってくるのは terraform plan 時に取得して確認します
Provider が提供する参照可能なデータはリファレンスを見ると良いです

resourece で VM の作成を行います
今回はクローンして VM を作成するので vsphere_virtual_machine.clone リソースを使います
ここでクローン元の VM を指定します
template_uuid には事前に data で定義した data "vsphere_virtual_machine" "template" から id を参照すれば OK です
あとはディスクの情報とネットワークの情報を指定すれば OK です
今回は作成する VM の IP アドレスは固定 IP を指定するので IP の情報も記載しました
DHCP 環境のネットワークであれば IP アドレスやゲートウェイの指定は不要です
それ以外の情報はクローン元の VM と同じにするので ${data.vsphere_virtual_machine.template.disks.0.size} みたいな感じでクローン元の VM の情報を参照しています

最後に

Terraform vSphere をとりあえず動かしてみました
今回は紹介しませんでしたが実はポイントはクローン元の VM でこっちがちゃんと設定できていないと apply に失敗します

例えば vmware-tools のインストール漏れやネットワークインタフェースの設定が漏れていると IP アドレスが取得できなくてエラーになることがあります
vSphere Provider で VM がうまく作成できない場合は大抵ネットワーク周りかなと思います

あとは今回はすべてのリソースを resources.tf 配下に作成しましたが terraform は *.tf ファイルを自動で読み込んでくれるので各リソースごとに設定などをまとめたりできます

参考サイト

2019年9月27日金曜日

vSphere REST API を curl でサクっと実行する方法

概要

タイトルの通りです
SOAP ではなく JSON ベースの REST API になります

環境

  • CentOS 7.7.1908
  • vSpehre vCenter 6.7.0.30000

認証

まずは SessionID を取得します
vSphere Client でログインしているユーザとパスワードが必要になります
以下は user001/pass001 として SessionID を取得する例です

  • curl -k -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'vmware-use-header-authn: test' --header 'vmware-api-session-id: null' -u 'user001' 'https://192.168.100.10/rest/com/vmware/cis/session'

実行するとパスワードの入力が求められるので user001 のパスワードを入力します
vmware-use-header-authn は「test」のままで OK です

成功すると {"value":"1aa17f25fbe29ca15de233dd82d1fda8"} のような SessionID が返ってきます

API をコールする

例えばタグの一覧を取得する場合は以下のようにコールします

  • curl -k -X GET --header 'Accept: application/json' --header 'vmware-api-session-id: 1aa17f25fbe29ca15de233dd82d1fda8' 'https://192.168.100.10/rest/com/vmware/cis/tagging/tag'

これで JSON 情報が返ってきます
取得した SessionID は vmware-api-session-id に設定しましょう

最後に

コール可能な API の一覧は https://192.168.100.10/apiexplorer/ にアクセスすると確認できます

2019年9月25日水曜日

CentOS7 に Python3.7 をインストールする方法

概要

執筆時点だと yum 経由では 3.6 が最新だったので 3.7 系をインストールする方法を紹介します
方法はいろいろありますが pyenv を使うのが簡単かなと思います

環境

  • CentOS 7.7.1908
  • pyenv 1.2.13

pyenv インストール

  • git clone https://github.com/pyenv/pyenv.git ~/.pyenv
  • echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
  • echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
  • echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.bash_profile

シェルを再ログインします

依存ライブラリインストール

  • yum install -y libffi-devel openssl-devel

エラーが出て他にもライブラリが必要な場合は適宜インストールしてください

python3.7 インストール

pyenv install --list

ずらーっとインストール可能なバージョンが出てくるので最新のバージョンを見つけてインストールしましょう

  • pyenv install 3.7.4

PATH に通して使う

  • pyenv global 3.7.4

PYENV_VERSION やら .python-version を使って局所的にバージョンコントロールもできるようです
yum でインストールした /usr/bin/python などがある場合は PATH の export の順番を変更してください

  • pip -V
pip 19.0.3 from /root/.pyenv/versions/3.7.4/lib/python3.7/site-packages/pip (python 3.7)

ちゃんと pip が最新のインストールした最新の Python を参照しているのが確認できれば OK です

最後に

pyenv 自体はソースコードを持ってきてビルドしてインストールしているので pyenv を使わないで手動でソースコードからビルドしても OK です

参考サイト

2019年9月24日火曜日

docker for Mac を launchctl から起動する方法

概要

コマンドから Docker.app を起動する方法を紹介します
応用すれば launchctl からも起動できます

コマンド

open コマンドを使います

  • /usr/bin/open /Applications/Docker.app

launchctl

朝 09:05 に起動する場合は以下の通り

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>local.mac.testscript0</string>
    <key>WorkingDirectory</key>
    <string>/Applications</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/bin/open</string>
      <string>Docker.app</string>
    </array>
    <key>StartCalendarInterval</key>
    <array>
      <dict>
        <key>Weekday</key>
        <integer>1</integer>
    <key>Hour</key>
        <integer>9</integer>
        <key>Minute</key>
        <integer>5</integer>
      </dict>
    </array>
  </dict>
</plist>

参考サイト

2019年9月23日月曜日

マインクラフト 1.14 攻略メモ

概要

マイクラが 1.14 になったので久しぶりにやってみました
攻略メモを備忘録として残しておきます

環境

  • Minecraft 1.14

マイクラをやる上でのポイントだと思うこと

基本は「効率化」になります

  • 食料集めの効率化
  • 素材集めの効率化
  • 強化の効率化
  • それによる攻略の効率化

あとはこれらを自動化までする感じかなと思います
クリアまで最短ならこの流れでなくても全然できますが安定かつ高効率でクリアするための流れです
自動化に関しては出尽くしている感があるので調べればたくさん出てきます
自分で検証したい場合はクリエイティブモードを有効活用しましょう

攻略の王道の流れ

個人的にこの流れが簡単かつやりやすいかなと思っています
ゲーム自体にやり方はないので参考程度に御覧ください
また建築などは考慮せずストーリーを高効率かつスピーディに攻略するための流れになります

序盤

まずは基礎を固めます
とりあえずエンチャントできるようになるところを目指します

木を切る -> 作業台、チェスト

まずはこれで手刀で木を切り作業台とチェストを作成します

木のつるはし -> 丸石 -> かまど -> 木炭 -> たいまつ

木のつるはし作成して丸石からかまどを作成します
そしてかまどを使って原木から木炭を作成したいまつを作成します
たいまつは洞窟探検に使います

石装備 -> 洞窟探検開始 -> 鉄鉱石

丸石から石装備を作成します
そして洞窟に行き「鉄鉱石」を優先して採掘します

鉄インゴット -> バケツ -> 水 -> 小麦、さとうきび栽培 (小麦は多め、村人増殖用)

かまどで鉄鉱石から鉄インゴットを作成します
そしてバケツを作成し水を汲み食物を確保します
まずは育てやすくかつ回復力も良い「パン」を確保します
パンは小麦が必要なので小麦を栽培しましょう
また「紙」も今後必要になるので同時にさとうきびの栽培も始めます
余裕があればこの段階でさとうきび畑だけでも自動化しておくのもありです
小麦の自動化はかなり大変なので栽培する範囲をできる限り広げておけば OK です

また栽培に余裕があれば「にんじん」や「じゃがいも」も同時に栽培しても OK です
「農家」就職した村人とエメラルドの取引きに使えます

とり、羊、牛放牧 (羊、牛優先)

とりは繁殖させやすいので食料として確保します
羊はベットを大量に作成するためにある程度繁殖させておきます
ベットは「ゴーレムトラップ」用なのでゴーレムトラップを作らないのであれば優先度は低いです
牛は革の確保です
革は「本」を作るのに必要で本から「本棚」を作成します

鉄装備 -> 洞窟探検 -> ダイヤ、レッドストーンなど採掘

鉄装備とある程度の食料が確保できたらダイヤを探しに行きます
ダイヤは「ダイヤのつるはし」を優先します
とりあえず 1 本あれば OK です
またこの辺りでは効率的に採掘ができないのでとりあえず最低限が見つかれば OK です

さとうきび畑 -> 紙 -> 本

さとうきび畑から紙を回収し繁殖させた牛から革を回収します
そして「本」を作成しましょう
最低でも 45 冊 (本棚 15 台分) はクラフトしましょう
また村人を「司書」に就職させるため「書見台」がある程度必要になるので 45 冊以上作れる余裕があるとなお OK です

ダイヤのつるはし -> 黒曜石 -> エンチャント台

ダイヤのつるはしを使って「黒曜石」を採掘します
そしてエンチャント台を作成します
高レベルのエンチャントをいかに装備に付与させるかによってクリアまでの効率性とスピードは大きく変わってきます

本棚15台 -> エンチャント台強化

エンチャント台が作成できたタイミングですぐにエンチャントレベルを MAX にできるようにしておきましょう
あまったレベルがある場合は本にエンチャントしておきましょう
本にエンチャントできるのはこちらを御覧ください

中盤

更に効率を上げるための準備をします
この辺りから難しい要素も含まれてきます
司書で「修繕」のエンチャント本を獲得するまでが目標です

村 -> 書見台 -> 司書作成

村を探しましょう
村までは何度も通うことになるのである程度整地して行きやすいようにしておきましょう、トロッコを敷いても良いと思います
村を第 2 拠点にするのもありですが同じ種類の栽培や放牧をするのは面倒なので近ければ毎回通いましょう

そして村の各家に「書見台」を配置しましょう
村人が就職するタイミングがよく分かりませんが自分がやった限りではデフォルトで生成されている家でかつベットが置かれている家に書見台を置いて数日経過すれば司書に就職してくれます (参考)

余裕があれば司祭 (聖職者) も作成して「エンダーパール」を取引きできるレベルまで上げておきましょう (司祭は終盤後回しでも OK)

司書ガチャ

修繕が出るまで行います
司書ガチャのやり方はいろいろありますがこのあたりが参考になります
幸運など他にも優先したいですがまずは修繕で修繕が出たら好きな司書を作りましょう

※場合によっては不要です、本と経験値がほぼ無限にあるのであれば本のエンチャントで補填できるのでわざわざ同じ武器や道具を「修繕」せず別の武器を作ってエンチャントしなおせるからです

自分は村人を一箇所に集中させて柵で囲い、その中に「書見台」と「ベッド」を複数おきます
そして司書が「修繕」のエンチャント本が出ない場合はすべての書見台を壊し職を解除してから再度書見台を配置という感じで繰り返して司書が出るまでがんばりました

また途中でもしほしいエンチャント本が出た場合は一度だけ取引きすれば職が固定されるので取引きして確定させましょう
転職できなくなった村人が多くなったらパンなどで増殖すれば OK です

ネザー -> ネザークォーツ -> さとうきび自動化

この辺りでさとうきびは自動化しておきましょう
司書が作成できれば紙で「エメラルド」が交換できるようになるので紙はあるだけ役に立ちます
面倒なのはオブザーバーにネザークォーツが必要になる点くらいです

洞窟 -> スポーンブロック -> 経験値稼ぎ

これは結構大変かもしれません
エンチャントレベルを常に MAX で行うためにあると楽です
必須でないので余裕があればやりましょう
個人的には山脈の洞窟に見かけることが多い気がします
炭鉱付近にもよく見かけます

スポーンブロックはシルクタッチでもプロック化できないので注意しましょう
見つけたら周囲の洞窟の湧き潰しもしましょう
またスポーンブロックの最大湧き効率も考えると更に効率が上がります (参考)
水流で上げて落とすのは面倒なので「9x9」の範囲で高さは「3」の空間を作成しスポナーから下は最低「5」ブロック開けます
下に 5 ブロック開けているのは最大湧き効率を考慮しているためです
スポナーの湧き範囲内にまだ Mob がいると湧きが効率が悪くなります
そして 5 ブロック分落下させたあとに水流で溝に流して溝に落ちた Mob を倒す感じです
落下ダメージはないので剣で一発で倒せませんがエンチャントした剣であればすぐに倒せるので上げて落とすトラップを作るよりかは簡単です

目的は経験値なので経験値が稼げる方法が他にあればそれでも OK です (トラップタワーなど)

ネザー -> ウィザースケルトン -> 頭 -> ウィザー -> ウィザースター

中盤の最難関になるかなと思います
かなり運と実力に左右されます

まずはネザー要塞を見るける所からスタートします
ゲートの作成箇所によっては一発で見つかる場合もあるので黒曜石に余裕がある場合は複数のゲートをいろいろな地点に作成してネザー要塞に当たるまでやっても良いかもしれません

ウィザースケルトンを倒す場合は「ドロップ増加」のエンチャントが付与された武器で倒しましょう
※ただ自分が「ドロップ増加 IV」でウィザースケルトンを狩っていた際は一度も複数個の頭をドロップすることはありませんでした
※またドロップ確率が上がった感じもなかったのでもしかしたらドロップ増加のエンチャント自体意味がないかもしれません

3 つ手に入れたらウィザーを召喚しましょう
ウィザーは岩盤を使ってハメると楽に倒せます (参考)

ビーコン + スライムトラップタワー (任意)

攻略に必須というわけではないです
また作り方の詳細はこちらを参考にしてください
Finder をスライムチャンクを探します
チャンクを探す際には F3 + g ボタンを押してチャンク境界を表示しながらやると間違えにくくなります
またシード値を表示するには「/seed」とコマンドを打ち込めば表示されるのでスクリーンショットなどを取ってテキストにしましょう

彫りする進めるのは Y=42 からで OK です、なぜならスライムは Y=39 以下でしか湧かないためです
作成したビーコンを使って掘り進めましょう
「採掘速度II」まで出すには鉱石ブロックが 164 個必要になるのでそこまで鉱石がない場合は 9 個の鉱石ブロックで済む「採掘速度I」+「効率強化 IV」でも十分です

湧き層も MAX まで作ります
周辺の湧き潰しもしておきます
スライムボールが大量に手に入ったらスライムブロックを作ります
スライムブロックは冒険の際に持っていくようにしましょう
簡単に壊せるので足場や目印として役に立ちます

最悪「層」だけ作るだけでも OK です
自動のトラップにする場合は水流とマグマブロックなどを使って自動で取得できるようにしますが層を作るだけでかなり湧くようになるので「ドロップ増加 IV」を使って倒せばかなりの量のスライムボールが手に入るのでそれでも OK です

ゴーレムトラップ (任意)

ビーコンで 4 段できない場合には作ったほうが早いです
村人が必要になります

司書ガチャで集めた村人を使っても OK です
むしろそっちのほうが簡単かもしれません

終盤

ここまで準備できれば、かなり装備がかなり充実するので楽にダンジョンをクリアできると思います

ネザー -> ブレイズ狩り -> ポーション

ネザーウォートを栽培して奇妙なポーションを作れるようにしておきましょう
あとは燃料となる「ブレイズロッド」->「ブレイズパウダー」が必要になるのでブレイズを狩りましょう
おそらくウィザースケルトンを狩っているのでネザー要塞は見つかっているはずなので要塞内にあるブレイズスポナーを使って狩れば OK です

余裕があればトラップ化しても OK ですが面倒な場合は「ドロップ増加IV」を使って倒しても OK です
心配な場合は耐火のポーションを使って狩ってもいいかなと思います

エンダーマン狩り -> エンドポータル探し

まだエンドに行けていないので通常のワールドで狩りましょう
目的はエンダーアイなので司祭 (聖職者) から「エンダーパール」を交換しても OK です
エンダーアイが 30 個ほど作成できたらエンドポータルを探してポータルにアイをはめ込みジ・エンドに行けるようになります
エンダーアイは最低 12 個必要になります

洞窟探検 -> ゾンビスポナー (任意)

司祭との取引きでゾンビ肉が使えます
司祭のの職業レベルを上げるのにも使えます
面倒ですが必要であれば洞窟探検して探しましょう

武器、防具準備 -> ジ・エンド -> エンダードラゴン

武器と防具はできればダイヤ装備にしましょう
エンチャントで「ダメージ増加」や「ダメージ軽減」を入れられれば更に良しです
余裕があれば「力のポーション」も持っていきましょう
準備ができたら倒しましょう
攻略方法はいろいろありますが正攻法で装備、道具を揃えてから倒すのが楽しめるのでおすすめです (参考)

弓 or クロスボウはエンドクリスタルの破壊に必須かなと思います
壊しやすい適当な足場も合わせて持っていきましょう

倒したら「ドラゴンの卵」を取り忘れないようにしましょう

ジ・エンド探索 -> エンドシティ -> エリトラ、シュルカーボックス

再度ジ・エンドに行きましょう
そこからワープしてエンドシティに行きます
ワープ用のエンダーパールを忘れずに持っていきましょう

あとはひたすらエンドシティ探しです
なかなか見つからない場合は表示するチャンクサイズを最大の 32 にして探しましょう
またポータルとエンドシティの座標メモしておくのを忘れないようにしておきましょう

エンドシップも見つかれば晴れて「エリトラ」ゲットです
あと取り忘れないほうがいいのが「シュルカーの殻」です
シュルカーを倒すとドロップするのでちゃんと「ドロップ増加 IV」で倒すのを忘れないようにしましょう (ドロップ増加 IV で倒し続けたのですが複数ドロップすることはなかったので意味ないかもしれません)
あとはエンドシップで「ドラゴン頭」も取っておきます

帰ったらエリトラに「修繕」のエンチャントをするのを忘れないようにしましょう

天空トラップタワー -> 火薬集め

エリトラの「ロケット花火」用です
おそらく天空トラップタワーが一番簡単で効率が良いので作りましょう
作り方はこちらが一番簡単かなと思います
効率はそこまでよくないので効率を求める場合は水流式にしましょう

作るのは地上からではなく広い海上を見つけてその真中に建築すると湧き潰ししなくて済みます
そして待機場所も考えましょう
自分は

  • (上の湧き層の Y 座標- 32) から (下の湧き層の Y 座標 - 24 ) の範囲

に待機場所を作成します
なげなら 32 ブロック以上離れると mob が移動しなくなってしまいかつ 24 ブロック以内にいると mob が湧かなくなってしまうためその範囲にいる必要があるためです
例えば上の湧き層の Y 座標が 231、下の湧き層の Y 座標が 228 の場合、231 - 32 = 199、228 - 24 = 206 なので Y 座標が 199 から 206 の範囲に待機場所を作成しましょう
X, Z 座標は処理層のブロックに密接する感じにすれば OK です (参考)

エンダーマントラップ -> 経験値稼ぎ (任意)

スポーンブロックのトラップよりも経験値効率がかなりよいので余裕があれば作りましょう
エメラルドがほしい場合はゾンビトラップを使うなど使い分けできるようになっていると更に良いです
おすすめはこの作り方が簡単かつ高効率です
超効率を求める場合はこちらですがここまでは正直必要ないです

落下式トラップになるのでもし高さを間違えてエンダーマンが即死してしまう場合にはハーフブロックなどを使って待機場所から高さ調整してください

その他各種攻略

あとは好きなところから探索すれば OK です
移動手段や装備などはここまでくれば簡単かつ効率的に準備できるようになっていると思います

  • 海底神殿
  • 沈没船
  • 森の洋館
  • ジャングル
  • 各種トラップの作成、自動化 (釣りなど)
  • 強い装備の作成 (アンデット特攻V + ダイヤの斧など)

その他 Tips 系

  • 壊れた武器同士は作業台でクラフトすることで耐久力を回復することができる (ただしエンチャントはなくなる、エンチャントを継承したい場合は金床を使う)
  • 洞窟探索時は分岐点などで帰り道がわかるように松明などを使って目印をつける
  • また探索が終了した箇所はいけないように石などを積んでブロックする
  • スポーン場所、洞窟の入り口、村など新たな場所を発見した場合は場所を忘れないように F3 でデバッグ表示して F2 でスクリーンショットを取得する
  • 牛から革を手に入れる場合できれば「ドロップ増加 IV」のエンチャントを付与した装備を使って倒す
  • 小麦やにんじん、じゃがいもなどの作物は「幸運 III」を使って収穫しましょう
  • ブランチマイニングする場合は Y=11 の高さがおすすめ

最後に

自分なりにマイクラを攻略する際の流れをまとめてみました
実際に上記の流れで自分がプレイしてみるとだいたい 1 ヶ月くらいで最後までいけるかなと思います

「強い装備と道具」が簡単かつ効率的に確保できる状態を目指す感じが良いのかなと思います
また効率性を更に上げるために「ビーコン」と「修繕」は重要かなと思います
ベストな組み合わせとしては

  • 経験値稼ぎ・・・エンダーマントラップ
  • 採掘、整地・・・効率強化 V + ビーコン
  • 装備、道具・・・修繕あり + 耐久力 III + 好きなエンチャント
  • 移動・・・エリトラ
  • 食料・・・鶏肉

それらがあれば時間をかけずに効率的にゲームを進行、展開できるかなと思います
ただマインクラフトの場合奈落や溶岩といった即死要素で全ロストする可能性はどうしても防ぎようがないかなと思います

2019年9月19日木曜日

Ruby でジャロ・ウィンクラー距離を求めてみる

概要

ジャロ・ウィンクラー距離は異なる 2 つの単語の類似度を計算することができる手法です
Ruby に簡単にライブラリがあるので使ってみました

環境

  • macOS 10.14.6
  • Ruby 2.6.2p47
    • jaro_winkler 1.5.3

サンプルコード

  • bundle init
  • vim Gemfile
gem "jaro_winkler"
  • bundle install --path vendor
  • vim app.rb
# coding: utf-8
require 'jaro_winkler'

p "ignore_case"
p JaroWinkler.distance "hakwsnowlog", "HAWKSNOWLOG"
p JaroWinkler.distance "hakwsnowlog", "HAWKSNOWLOG", :ignore_case => true
p "weight"
p JaroWinkler.distance "hakwsnowlog", "hawk-snowlog"
p JaroWinkler.distance "hakwsnowlog", "hawk-snowlog", :weight => 0.15
p JaroWinkler.distance "hakwsnowlog", "hawk-snowlog", :weight => 0.25
p "adj_table"
p JaroWinkler.distance "HAWKSNOWLOG", "HAWKSN0WL0G", :adj_table => false
p JaroWinkler.distance "HAWKSNOWLOG", "HAWKSN0WL0G", :adj_table => true
p "multi-bytes"
p JaroWinkler.distance "今日はいい天気です", "今日は晴れています"
  • bundle exec ruby app.rb
"ignore_case" 0.0 0.9757575757575758 "weight" 0.9535353535353536 0.9593434343434344 0.970959595959596 "adj_table" 0.9272727272727274 0.949090909090909 "multi-bytes" 0.7925925925925926

少し解説

数字は 0 から 1 の間で計算されます
1 に近ければ近いほど類似度は高いということになります

普通に計算する場合は JaroWinkler.distance を使えば OK です
オプションがいくつかあるので紹介します

まず ignore_case ですがこれは比較するの大文字小文字を無視して比較します
サンプルにある大文字 (HAWKSNOWLOG) と小文字 (hawksnowlog) を比較したときに :ignore_case => true を指定しないと結果が 0 になっているのがわかると思います

次に weight ですがこれを付与すると結果が上方修正されます
デフォルトが 0.1 で最大 0.25 まで設定できます
weight と同時に使えるオプションで threshold があります
これは指定した threshold を超えた場合にだけ weight の値を適用することができるというオプションになります

最後に adj_table ですがこれは表記ゆれを解消するための機能です
例えば数字の「0」と英文字の「O」を同じ文字としてみなす場合には :adj_table => true にします
デフォルトでは false になっています
サンプルの結果を見ると表記ゆれがある場合には true に設定したほうが類似度が高くなるのがわかると思います
また adj_table は現状だとカスタムできないようです

マルチバイト文字にも対応しているので日本語の比較も可能です

最後に

ジャロ・ウィンクラー距離を Ruby で計算してみました
基本はデフォルトで使うのが良いかなと思います
基本は単語同士の比較に使うのが良いかなと思います
短いのであれば文章にも適用できると思います

コサイン類似度などを使っても算出できますが複雑な計算が必要なのでそういった意味ではジャロ・ウィンクラー距離は簡単に計算できるので良いのかなと思います

2019年9月18日水曜日

MacOS で Ruby を Homebrew でインストールしたときのパスやら gem のインストール先やら

概要

Homebrew を使って Ruby をインストールした場合のインストール先をメモしておきます
また gem install した場合のパスも紹介します

環境

  • macOS 10.14.6
  • Homebrew 2.1.11
  • Ruby 2.6.2p47

Ruby のインストール先

/usr/local/opt/ruby/bin/ruby

調べ方

インストールコマンドは以下の通りです

  • brew install ruby

実は info コマンドで見ると上記のインストール先と違う情報が表示されます

  • brew info ruby
By default, binaries installed by gem will be placed into: /usr/local/lib/ruby/gems//bin

インストールされたファイルの一覧を ls コマンドで確認してみます

  • brew ls ruby
r/local/Cellar/ruby/2.6.2/bin/bundle /usr/local/Cellar/ruby/2.6.2/bin/bundler /usr/local/Cellar/ruby/2.6.2/bin/erb /usr/local/Cellar/ruby/2.6.2/bin/gem /usr/local/Cellar/ruby/2.6.2/bin/irb /usr/local/Cellar/ruby/2.6.2/bin/rake /usr/local/Cellar/ruby/2.6.2/bin/rdoc /usr/local/Cellar/ruby/2.6.2/bin/ri /usr/local/Cellar/ruby/2.6.2/bin/ruby /usr/local/Cellar/ruby/2.6.2/include/ruby-2.6.0/ (28 files) /usr/local/Cellar/ruby/2.6.2/lib/libruby.2.6.dylib /usr/local/Cellar/ruby/2.6.2/lib/pkgconfig/ruby-2.6.pc /usr/local/Cellar/ruby/2.6.2/lib/ruby/ (3569 files) /usr/local/Cellar/ruby/2.6.2/lib/libruby.dylib /usr/local/Cellar/ruby/2.6.2/libexec/gembin/ (2 files) /usr/local/Cellar/ruby/2.6.2/share/emacs/site-lisp/ruby/ruby-style.el /usr/local/Cellar/ruby/2.6.2/share/man/ (29 files) /usr/local/Cellar/ruby/2.6.2/share/ri/ (15695 files)y default, binaries installed by gem will be placed into:

そして /usr/local/Celler/ruby/2.6.2/usr/local/opt 配下に自動でリンクされています

  • ls -ltr /usr/local/opt/ | grep ruby
lrwxr-xr-x 1 hawksnowlog admin 20 4 12 10:24 ruby -> ../Cellar/ruby/2.6.2 lrwxr-xr-x 1 hawksnowlog admin 20 4 12 10:24 ruby@2.6 -> ../Cellar/ruby/2.6.2 lrwxr-xr-x 1 hawksnowlog admin 29 9 15 00:04 ruby-build -> ../Cellar/ruby-build/20190828

なので /usr/local/opt/ruby/bin/ruby でアクセスできます

gem のインストール先

/usr/local/lib/ruby/gems/2.6.0

調べ方

  • gem environment

INSTALLATION DIRECTORY を見ましょう
ここに設定されているパスに gem はインストールされます
例えば

  • gem install rubocop

すると

  • /usr/local/lib/ruby/gems/2.6.0/gems/rubocop-0.74.0/exe/rubocop

というパスにインストールされます
gem でインストールした場合は /usr/local/opt/ みたいなパスにリンクが貼られるわけではないのでコマンドごとに PATH を変更したりする必要があります
またバージョンが変わるとインストールされるパスも変わると思います

2019年9月17日火曜日

Ruby Gosu でゲームを開発入門

概要

gosu は Ruby or C++ で 2D ゲーム開発ができるライブラリです
今回は Ruby ライブラリを使って簡単なチュートリアルゲームを作成してみました

環境

  • macOS 10.14.6
  • Ruby 2.6.2p47
    • gosu 0.14.5

準備

  • brew install sdl2
  • bundle init
  • vim Gemfile
gem "gosu"
  • bundle install --path vendor

とりあえずウィンドウを表示する

  • vim app.rb
require 'gosu'

class Tutorial < Gosu::Window
  def initialize
    super 640, 480
    self.caption = "Tutorial Game"
  end

  def update
  end

  def draw
  end
end

Tutorial.new.show
  • bundle exec ruby app.rb

実行すると真っ暗なウィンドウだけが表示されます

背景画像の設定

次にゲームの背景画像を設定します
何でも良いので画像をダウンロードしておきましょう
公式のチュートリアルで使用している画像はここにあります 

require 'gosu'

class Tutorial < Gosu::Window
  def initialize
    super 640, 480
    self.caption = "Tutorial Game"
    @bg = Gosu::Image.new("bg.png", :tileable => true)
  end

  def update
  end

  def draw
    @bg.draw(0, 0, 0)
  end
end

Tutorial.new.show

Gosu::Image.new で背景に指定する画像のパスを指定します
また draw で実際に画像をどの座標に描画するのか指定します
座標は左上が起点になります数字が増えるほど右下に移動します

実行すると以下のようにダウンロードした画像が背景として設定されています

プレイヤーの作成と配置

ゲームに必須の要素になります
キーボードで移動可能なプレイヤーを設置してみます

player.rb

プレイヤーを管理するクラスを別途作成します
少し長いですがあとで解説します

  • vim player.rb
require 'gosu'

class Player
  def initialize
    @image = Gosu::Image.new("starfighter.bmp")
    @x = @y = @vel_x = @vel_y = @angle = 0.0
    @score = 0
  end

  def warp(x, y)
    @x = x
    @y = y
  end

  def turn_left
    @angle -= 4.5
  end

  def turn_right
    @angle += 4.5
  end

  def accelerate
    @vel_x += Gosu.offset_x(@angle, 0.5)
    @vel_y += Gosu.offset_y(@angle, 0.5)
  end

  def move
    @x += @vel_x
    @y += @vel_y
    @x %= 640
    @y %= 480
    @vel_x *= 0.95
    @vel_y *= 0.95
  end

  def draw
    @image.draw_rot(@x, @y, 1, @angle)
  end
end

キーボードの右を押した時に右に回転し左を押した時に左に回転するようにします
キーボードの上を押した際にプレイヤーが前に動くようにします
それぞれ turn_right, turn_left, accelerate メソッドが対応しています

move メソッドは実際に設定された座標にプレイヤーを移動するメソッドです
@x %= 640@y %= 480 はプレイヤーが画面からはみ出さないようにするための設定です
@vel_x *= 0.95, @vel_y *= 0.95 は摩擦係数のようなものでこれを設定しないと一度 accelerate したプレイヤーが永遠に動き続けてしまいます

少し難しいのは Gosu.offset_xGosu.offset_y になります
これは現在の位置からどの方向にどれだけ動かすかを指定することができるメソッドです
@angle で調整した角度に対して 0.5 だけ動かします
つまり上ボタンが押されている間徐々に動くような挙動になります

プレイヤー自体を動かす場合は draw_rot で動かします
draw メソッドはプレイヤーが固定されて伸縮するような表現に使います

warp は初期配置用のメソッドです

メインにプレイヤーを配置する

キーボードの入力のハンドリングはメインとなる app.rb 側の update で処理します

  • vim app.rb
require 'gosu'
require './player.rb'

class Tutorial < Gosu::Window
  def initialize
    super 640, 480
    self.caption = "Tutorial Game"
    @bg = Gosu::Image.new("bg.png", :tileable => true)
    @player = Player.new
    @player.warp(320, 240)
  end

  def update
    if Gosu::button_down?(Gosu::KB_LEFT) || Gosu::button_down?(Gosu::GP_LEFT)
      @player.turn_left
    end
    if Gosu::button_down?(Gosu::KB_RIGHT) || Gosu::button_down?(Gosu::GP_RIGHT)
      @player.turn_right
    end
    if Gosu::button_down?(Gosu::KB_UP) || Gosu::button_down?(Gosu::GP_BUTTON_0)
      @player.accelerate
    end
    @player.move
  end

  def draw
    @bg.draw(0, 0, 0)
    @player.draw
  end

  def button_down(id)
    if id == Gosu::KB_ESCAPE
      close
    else
      super
    end
  end
end

Tutorial.new.show

キーボードの入力は Gosu::button_down? でハンドリングできます
ハンドリング可能なキーボードは定数で定義されています

updatedraw メソッドは 60fps でコールされ続けるので内部的にはキーボードに移動と再描画を繰り返すことであたかもプレイヤーが動いているような表現を実現しています

button_down は他のキーボードの入力をハンドリングするためのメソッドです
close を呼び出すことでわざわざ左上のバツボタン押さなくてもゲームが終了するようにしています

これで実行してみましょう
マシンのキーボードを使って以下のようにプレイヤーが操縦できるようになります

星を追加する

star.rb

少しゲーム要素を追加します
星を取得するとスコアがカウントアップするようにします
また星は連続したタイル画像を使います (これ)
なので星が回転するような動きになるようなアニメーションを実装します

  • vim star.rb
require 'gosu'

class Star
  attr_reader :x, :y

  def initialize(animation)
    @animation = animation
    @color = Gosu::Color::BLACK.dup
    @color.red = rand(256 - 40) + 40
    @color.green = rand(256 - 40) + 40
    @color.blue = rand(256 - 40) + 40
    @x = rand * 640
    @y = rand * 480
  end

  def draw
    img = @animation[Gosu.milliseconds / 100 % @animation.size]
    img.draw(@x - img.width / 2.0, @y - img.height / 2.0, 1, 1, 1, @color, :add)
  end
end

@animation はタイルに上に切り分けられた連続した画像になります
色や場所をランダムで決定します
そして draw が呼ばれる際に適切なタイルの情報を取得することであたかも星が回転しているようなアニメーションを実現してます
draw はいろいろと引数を指定していますがそれぞれ「X 座標」「Y 座標」「Z 座標」「X 方向の画像のスケール」「Y 方向の画像のスケール」「色」「追加モード」になります

プレイヤーが星を集められるようにする

だいぶ長くなってきました
player.rb を修正します
追加しているのは下部にある scorecollect_star メソッドになります

  • vim player.rb
require 'gosu'

class Player
  def initialize
    @image = Gosu::Image.new("starfighter.bmp")
    @x = @y = @vel_x = @vel_y = @angle = 0.0
    @score = 0
  end

  def warp(x, y)
    @x = x
    @y = y
  end

  def turn_left
    @angle -= 4.5
  end

  def turn_right
    @angle += 4.5
  end

  def accelerate
    @vel_x += Gosu.offset_x(@angle, 0.5)
    @vel_y += Gosu.offset_y(@angle, 0.5)
  end

  def move
    @x += @vel_x
    @y += @vel_y
    @x %= 640
    @y %= 480
    @vel_x *= 0.95
    @vel_y *= 0.95
  end

  def draw
    @image.draw_rot(@x, @y, 1, @angle)
  end

  def score
    @score
  end

  def collect_stars(stars)
    stars.reject! { |star| Gosu.distance(@x, @y, star.x, star.y) < 35 }
  end
end

ポイントは プレイヤーと星の距離に応じて stars 配列から reject! している Gosu.distance になります
これで 2 つのオブジェクトの距離を計算することができます
今回は 35 以下であれば集めたと判定して星を管理する配列から星を削除します

メインで星を描画する

あとはメインで星を描画する処理を実装します
星は連続するタイル画像になります
そういった画像を使う場合は Gosu::Image.load_tiles を使います
これに各タイルのサイズをしていすることで配列として扱うことができます

  • vim app.rb
require 'gosu'
require './player.rb'
require './star.rb'

class Tutorial < Gosu::Window
  def initialize
    super 640, 480
    self.caption = "Tutorial Game"
    @bg = Gosu::Image.new("bg.png", :tileable => true)
    @player = Player.new
    @player.warp(320, 240)
    @star_anim = Gosu::Image.load_tiles("star.png", 25, 25)
    @stars = Array.new
  end

  def update
    if Gosu::button_down?(Gosu::KB_LEFT) || Gosu::button_down?(Gosu::GP_LEFT)
      @player.turn_left
    end
    if Gosu::button_down?(Gosu::KB_RIGHT) || Gosu::button_down?(Gosu::GP_RIGHT)
      @player.turn_right
    end
    if Gosu::button_down?(Gosu::KB_UP) || Gosu::button_down?(Gosu::GP_BUTTON_0)
      @player.accelerate
    end
    @player.move
    @player.collect_stars(@stars)
    if rand(100) < 4 && @stars.size < 25
      @stars.push(Star.new(@star_anim))
    end
  end

  def draw
    @bg.draw(0, 0, 0)
    @player.draw
    @stars.each do |star|
      star.draw
    end
  end

  def button_down(id)
    if id == Gosu::KB_ESCAPE
      close
    else
      super
    end
  end
end

Tutorial.new.show

また先程紹介しましたが星の数は配列で管理しています
集めると reject! されるので追加していく必要があります
update されるたびに stars の状態を確認して減ってきたり 4% の確率で追加するようにします
また星を集めているかどうかも update@player.collect_stars(@stars) を呼び出すことで実現します
各星との距離を毎回計算するので少し重い処理になりそうですが今回はチュートリアル通りに進めます

これで実行すると以下のように星を集められるようになります
だいぶゲームっぽくなってきました

スコアの表示を行う

最後にスコアの表示を行う処理を実装します
@fontinitialize で初期化して draw で描画しています

  • vim app.rb
require 'gosu'
require './player.rb'
require './star.rb'

class Tutorial < Gosu::Window
  def initialize
    super 640, 480
    self.caption = "Tutorial Game"
    @bg = Gosu::Image.new("bg.png", :tileable => true)
    @player = Player.new
    @player.warp(320, 240)
    @star_anim = Gosu::Image.load_tiles("star.png", 25, 25)
    @stars = Array.new
    @font = Gosu::Font.new(20)
  end

  def update
    if Gosu::button_down?(Gosu::KB_LEFT) || Gosu::button_down?(Gosu::GP_LEFT)
      @player.turn_left
    end
    if Gosu::button_down?(Gosu::KB_RIGHT) || Gosu::button_down?(Gosu::GP_RIGHT)
      @player.turn_right
    end
    if Gosu::button_down?(Gosu::KB_UP) || Gosu::button_down?(Gosu::GP_BUTTON_0)
      @player.accelerate
    end
    @player.move
    @player.collect_stars(@stars)
    if rand(100) < 4 && @stars.size < 25
      @stars.push(Star.new(@star_anim))
    end
  end

  def draw
    @bg.draw(0, 0, 0)
    @player.draw
    @stars.each do |star|
      star.draw
    end
    @font.draw("Score: #{@player.score}", 10, 10, 3, 1.0, 1.0, Gosu::Color::YELLOW)
  end

  def button_down(id)
    if id == Gosu::KB_ESCAPE
      close
    else
      super
    end
  end
end

Tutorial.new.show

あとは星を収集した際にスコアのカウントを行うだけです
collect_stars を少し改修しています

  • vim player.rb
require 'gosu'

class Player
  def initialize
    @image = Gosu::Image.new("starfighter.bmp")
    @x = @y = @vel_x = @vel_y = @angle = 0.0
    @score = 0
  end

  def warp(x, y)
    @x = x
    @y = y
  end

  def turn_left
    @angle -= 4.5
  end

  def turn_right
    @angle += 4.5
  end

  def accelerate
    @vel_x += Gosu.offset_x(@angle, 0.5)
    @vel_y += Gosu.offset_y(@angle, 0.5)
  end

  def move
    @x += @vel_x
    @y += @vel_y
    @x %= 640
    @y %= 480
    @vel_x *= 0.95
    @vel_y *= 0.95
  end

  def draw
    @image.draw_rot(@x, @y, 1, @angle)
  end

  def score
    @score
  end

  def collect_stars(stars)
    stars.reject! do |star|
      if Gosu.distance(@x, @y, star.x, star.y) < 35
        @score += 10
      else
        false
      end
    end
  end
end

これで実行すれば完成です
ちゃんと星を取得するとスコアがカウントアップするのが確認できます

Tips

Gosu は背景が #ff00ff の色を自動的に透過にしてくれます

最後に

Gosu で Ruby を使って 2D ゲーム開発に入門してみました
キーボードを使ったゲームですが簡単にできました

物理エンジンなどおそらくないので重力加速などが必要な場合は自分で実装する必要がありそうです
当たり判定なども今回自分で実装したので距離などの情報を使って自分で実装するのかなと思います
基本はキーボードが入力になるのでマウスは考慮しなくても良さそうですがマウスの入力もできるっぽいです
詳しくは参考サイトにある Github の Wiki や Rdoc を見てください

Windows と Mac 用にエクスポートできるようなので次回紹介したいと思います

参考サイト

2019年9月15日日曜日

macOS 10.14.6 に Ruby 2.0.0 をインストールする方法

概要

Homebrew でインストールした場合は最新のバージョンが入ります
古いバージョンの Ruby を使いたい場合は rbenv を使うと楽です

環境

  • macOS 10.14.6

rbenv インストール

  • brew install rbenv

rbenv を使って Ruby 2.0.0 をインストール

  • export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
  • export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include
  • rbenv install -l
  • rbenv install 2.0.0-p645

ruby-buildopenssl が必要になるのでない場合は

  • brew install ruby-build openssl

しましょう

使う

  • /Users/hawksnowlog/.rbenv/versions/2.0.0-p645/bin/ruby -v

メインの Ruby にする

Homebrew ではなく完全に rbenv に移行する場合は以下のようにします

  • rbenv init - >> ~/.bash_profile
  • source ~/.bash_profile

一番後ろに追記しているので PATH に最優先で探索されます
Homebrew の Ruby の PATH は削除しないでも大丈夫です
元に戻す場合は ~/.bash_profile の内容を元に戻しましょう

2019年9月12日木曜日

numberOfRowsInSection unrecognized selector sent to instance

概要

Xcode でビルドした際にタイトルのようなエラーが出ました
StoryBoard で Outlets などを使っている場合に出るようです

環境

  • macOS 10.14.6
  • Xcode 10.3

エラー文

2019-09-11 16:35:13.649217+0900 ios-fndic[16100:1943401] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ios_fndic.FirstViewController tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0x7f9d4d83a800'

対応方法

StoryBoard の Outlets をちゃんと設定するという記事をよく見たのですが自分の場合は違いました
ViewController クラスでちゃんと UITableViewDelegateUITableViewDataSource を継承して上げる必要がありました

class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, ...

参考サイト