シェルスクリプトマガジン

test

機械学習のココロ(Vol.62掲載)

投稿日:2019.09.25 | カテゴリー: コード

著者:石井 一夫

最終回は、次世代データサイエンス言語として注目されている「Julia」を紹介します。高速な実行速度、並列分散処理の容易さ、数式記述の自然さなどを特徴とするJuliaは、今後急速に普及すると考えられます。

シェルスクリプトマガジン Vol.62は以下のリンク先でご購入できます。

図4 必要パッケージを読み込むコード

using Pkg
Pkg.add("Flux")
using Flux
using Statistics
using Flux: onehotbatch, onecold, crossentropy, throttle
using Base.Iterators: repeated

図5 MNIST データを読み込むコード

imgs = Flux.Data.MNIST.images()
labels = Flux.Data.MNIST.labels()

図7 訓練用データの前処理用コード

X = hcat(float.(reshape.(imgs, :))...)
Y = onehotbatch(labels, 0:9)

図8 モデルの構築用コード

m = Chain(
  Dense(28^2, 32, relu),
  Dense(32, 10),
  softmax)

図9 損失関数などの設定用コード

loss(x, y) = crossentropy(m(x), y)
opt = ADAM()
accuracy(x, y) = mean(onecold(m(x)) .== onecold(y))
dataset = repeated((X,Y),200)
evalcb = () -> @show(loss(X, Y))

図10 訓練データを用いた学習をするコード

Flux.train!(loss, params(m), dataset, opt, cb = throttle(evalcb, 10))

図13 テストデータの前処理用コード

test_X = hcat(float.(reshape.(Flux.Data.MNIST.images(:test), :))...)
test_Y = onehotbatch(Flux.Data.MNIST.labels(:test), 0:9)

図14 テスト画像の数字を推測するコード

onecold(m(test_X[:,5287])) - 1

特集1 PostgreSQL入門(Vol.62記載)

投稿日:2019.09.25 | カテゴリー: コード

著者:千田貴大

PostgreSQLは、今もなお成長を続けるオープンソースのリレーショナルデータベース管理システム(RDBMS)です。オーストリアのsolid IT社が運営するDBMSに関する情報サイト「DB-Engines」(https://db-engines.com/en/)では、2017年から2年連続で「the DBMS of the year」に選ばれており、勢いがあるRDBMSといえます。本特集では、PostgreSQLの導入方法や基本的な使い方、いくつかの機能について紹介します。

シェルスクリプトマガジン Vol.62は以下のリンク先でご購入できます。

図7 環境変数設定ファイル「/var/lib/pgsql/.bash_profile」の内容

[ -f /etc/profile ] && source /etc/profile
PGDATA=/var/lib/pgsql/11/data
export PGDATA
# If you want to customize your settings,
# Use the file below. This is not overridden
# by the RPMS.
[ -f /var/lib/pgsql/.pgsql_profile ] && source /var/lib/pgsql/.pgsql_profile

図13 「pg_hba.conf」ファイルの内容

# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust

図16 アーカイブログ取得のための「postgresql.conf」ファイルの変更箇所

archive_mode = on
archive_command = 'cp "%p" "/var/lib/pgsql/11/archive/%f"'

図17 「recovery.conf」ファイルに記述する必要がある設定

restore_command = 'cp "/var/lib/pgsql/11/archive/%f" "%p"'

ユニケージ新コードレビュー(Vol.62掲載)

投稿日:2019.09.25 | カテゴリー: コード

著者:坂東 勝也

ユニケージでは、小さな道具の「コマンド」をシェルスクリプトで組み合わせて、さまざまな業務システムを構築しています。本連載では、毎回あるテーマに従ってユニケージによるシェルスクリプトの記述例を分かりやすく紹介します。第9回は、前回の続きとしてデータの扱い方について解説します。

シェルスクリプトマガジン Vol.62は以下のリンク先でご購入できます。

図2 LV3データ作成処理のコード(一部抜粋)

#######################################
# LV3 の作成

echo $lv2d/$today/PROFILE*   |  # /home/hoge/DATA/LV2/20190919/PROFILE*
tarr                         |
ugrep -v "\*"                > $tmp-list
ERROR_CHECK

# LV2 ファイルが存在した場合だけ処理
if [ -s "$tmp-list" ] ; then

        # LV2 ファイル
        # 1:管理番号        2:名前     3:ふりがな  4:アドレス    5:性別
        # 6:年齢            7:生年月日 8:婚姻      9:血液型      10:都道府県
        # 11:都道府県コード 12:携帯    13:キャリア 14:削除フラグ 15:オペレータ
        # 16:更新日付
        cat $tmp-list        |
        xargs cat            |
        msort key=1@NF       > $tmp-kousin
        ERROR_CHECK
)
        # 新規マスタの作成
        # 1:管理番号        2:名前     3:ふりがな  4:アドレス    5:性別
        # 6:年齢            7:生年月日 8:婚姻      9:血液型      10:都道府県
        # 11:都道府県コード 12:携帯    13:キャリア 14:削除フラグ 15:オペレータ
        # 16:更新日付
        up3 key=1@NF $lv3d/$yday/PROFILE $tmp-kousin | #前日マスタに本日LV2の情報をマージ
        # 最新の情報だけを残す
        getlast key=1                                | #管理番号ごとに最も新しいものだけを出力
        # 削除フラグ=1は除外
        delr 14 1                                    > $lv3d/$today/PROFILE
        ERROR_CHECK

        # マスタの置換
        cp $lv3d/$today/PROFILE $lv3d/PROFILE.new
        ERROR_CHECK
        mv $lv3d/PROFILE.new $lv3d/PROFILE
        ERROR_CHECK

fi

シェルスクリプトマガジンvol.62 Web掲載記事まとめ

投稿日:2019.09.25 | カテゴリー: コード

004 レポート exFATのLinuxカーネル実装
005 NEWS FLASH
008 特集1 PostgreSQL入門/千田貴大 コード掲載
024 特集2 Jetson Nanoを使ってみよう/橘幸彦
034 姐のNOGYO
035 特別企画 はじめてのLinux/長原宏治
050 ラズパイセンサーボードで学ぶ 電子回路の制御/米田聡 コード掲載
054 漢のUNIX/後藤大地
062 バーティカルバーの極意/飯尾淳 コード掲載
066 法林浩之のFIGHTING TALKS/法林浩之
068 機械学習のココロ/石井一夫 コード掲載
073 MySQL Shellを使おう/梶山隆輔
078 円滑コミュニケーションが世界を救う!/濱口誠一
080 香川大学SLPからお届け!/宇野光純 コード掲載
088 めし/桑原滝弥・イケヤシロウ
090 中小企業手作りIT化奮戦記/菅雄一
096 ユニケージ新コードレビュー/坂東勝也 コード掲載
102 Techパズル/gori.sh
104 コラム「平凡で地味な人生を幸せに送る」/シェル魔人

Vol.62 補足情報

投稿日:2019.09.25 | カテゴリー: コード

訂正・補足情報はありません
情報は随時更新致します。

Vol.62

投稿日:2019.09.25 | カテゴリー: バックナンバー

 オープンソースでは人気が高いデータベース管理システム「PostgreSQL」。特集1では、このPostgreSQLの概要、WindowsやCentOSへのインストール方法、初期設定と基本操作、知っておきたい機能を解説しました。PsotgreSQLを初めて利用する人にも分かりやすい内容になっています。
 特集2では、本格的なAI(人工知能)を安価に試せるGPU「Jetson Nano」を扱いました。米NVIDIA社の無料オンライントレーニングを基にして、開発者キットの立ち上げ方からAIによる画像分類までを日本語で分かりやすく紹介しています。
 特別企画では、無料の基本ソフト(OS)であるLinuxについて、やさしく解説しました。この企画で「Linuxとは何か」「どう使うのか」を基本からしっかり理解してください。
 このほか、ラズパイセンサーボードに接続した4桁の7セグLEDの制御、Pythonの制御構文、次世代データサイエンス言語「Julia」、MySQL Shellの運用管理ユーティリティなどを連載で紹介しています。
 今回も読み応え十分のシェルスクリプトマガジン Vol.62。お見逃しなく!

※記事掲載のコードはこちら。記事の補足情報はこちら

※読者アンケートはこちら

センサーボードで学ぶ電子回路の制御(Vol.62掲載)

投稿日:2019.09.25 | カテゴリー: コード

著者:米田 聡

シェルスクリプトマガジンでは、小型コンピュータボード「Raspberry Pi」(ラズパイ)向けのセンサー搭載拡張ボード「ラズパイセンサーボード」を制作しました。第9 回では、I/Oエキスパンダに7セグメントLEDを四つ接続してセンターからの値を表示します。

シェルスクリプトマガジン Vol.62は以下のリンク先でご購入できます。

図5 LEDを表示するライブラリ(led4digits.py)

from mcpgpio import MCPGPIO
import threading
import time

class LED4DIGITS(threading.Thread):

  # 点灯させる桁のコード
  __dig = [
    [0b00000000, 0b00100000], #13
    [0b00010000, 0b00000000], #4
    [0b00001000, 0b00000000], #3
    [0b00000100, 0b00000000]  #2
  ]

  # ドットのコード
  __dot = [0b00000000, 0b00000100] # 10

  # 数値のコード
  __leds = [ [0b11100000, 0b00001011 ],  # [7, 5, 11, 9, 8, 6] 
           [0b00100000, 0b00001000 ],  # [5, 11] 
           [0b10100000, 0b00010011 ],  # [7, 5, 12, 8, 9]
           [0b10100000, 0b00011010 ],  # [7, 5, 12, 11, 9]
           [0b01100000, 0b00011000 ],  # [6, 12, 5, 11]
           [0b11000000, 0b00011010 ],  # [7, 6, 12, 11, 9]
           [0b11000000, 0b00011011 ],  # [7, 6, 12, 11, 9, 8]
           [0b10100000, 0b00001000 ],  # [7, 5, 11]
           [0b11100000, 0b00011011 ],  # [7, 5, 11, 9, 8, 6, 12]
           [0b11100000, 0b00011010 ]   # [7, 5, 11, 9, 6, 12]
    ]

  __d = 0                 # 現在の桁
  value = 0               # 表示する値
  __term = False          # 停止フラグ
  __p = -1                # ドットの位置

  def __init__(self):
    threading.Thread.__init__(self)

    self.gpio = MCPGPIO()

    for i in range(16):
      self.gpio.setup(i, self.gpio.OUTPUT)
      self.gpio.output(i, self.gpio.LOW)

  def print(self, v):
    if (v > 9999) or (v < 0):
      return

    self.__p = -1
    self.value = 0
    if isinstance(v, int):
      self.value = v

    elif isinstance(v, float):
      s = '{:.4g}'.format(v)
      if float(s) < 10:
        self.value = int(float(s) * 1000)
        self.__p = 3
      elif float(s) < 100:
        self.value = int(float(s) * 100)
        self.__p = 2
      elif float(s) < 1000:
        self.value = int(float(s) * 10)
        self.__p = 1
      else:
        self.value = int(s)

    else:
      return
    
  def stop(self):
    self.__term = True

  def run(self):
    while not self.__term:
      d = self.__d & 0b11
      co = 10 ** d
      n = int(self.value / co)
      p = int(n / 10)
      n %= 10
      # clear
      self.gpio.gpioa = 0
      self.gpio.gpiob = 0
      if (n != 0) or (d == 0) or (p > 0) or (self.__p == 3):
        # put
        a = self.__leds[n][0] | self.__dig[d][0]
        b = self.__leds[n][1] | self.__dig[d][1]
        if self.__p == d:
          a |= self.__dot[0]
          b |= self.__dot[1]
        self.gpio.gpioa = a
        self.gpio.gpiob = b

      self.__d += 1
      time.sleep(0.002)

図6 BME280からの温度を取得・表示するプログラム(sample.py)

import time
import smbus2
import bme280
from led4digits import LED4DIGITS

BME280_ADDR = 0x76
BUS_NO = 1

# BME280
i2c = smbus2.SMBus(BUS_NO)
bme280.load_calibration_params(i2c, BME280_ADDR)

# LED Start
led = LED4DIGITS()
led.start() # 点灯開始

try:
    while True:
      data = bme280.sample(i2c, BME280_ADDR)
      led.print(data.temperature)
      time.sleep(1)
except KeyboardInterrupt:
    led.stop()

香川大学SLPからお届け!(Vol.62掲載)

投稿日:2019.09.25 | カテゴリー: コード

筆者:宇野 光純

 前回に引き続き、Windowsアプリケーションとして動く簡単な2Dゲームの開発を紹介します。汎用プログラミング言語の「C++」と、オープンソースのパソコンゲーム開発用ライブラリの「DXライブラリ」を組み合わせることで、時間と労力は必要ですが、Unityなどのゲームエンジンよりも自由度の高いゲーム開発ができます。

シェルスクリプトマガジン Vol.62は以下のリンク先でご購入できます。

図2 「Shot.h」ファイルに記述するコード

#pragma once
#include "Object.h"

class Shot : public Object {
private:
  bool flag;
  bool image;
  // true なら敵機の弾、false なら自機の弾
  static int image1; // 画像ハンドル1
  static int image2; // 画像ハンドル2
  void SetImage(); // 画像関連設定用の関数

public:
  double xv, yv; // X、Y 方向の移動量
  Shot();
  void Update(); // 更新
  void Draw(); // 描画
  // 座標、速度、画像を指定し発射する
  void Shoot(double nx, double ny,
             double nxv, double nvy, bool fimg);
};

図3 「Shot.cpp」ファイルに記述するコード

#include "DxLib.h"
#include "Shot.h"
#include "Info.h"
int Shot::image1 = -1;
int Shot::image2 = -1;

Shot::Shot() {
  x = y = 0.0; xv = yv = 0.0; flag = true; image = false;
  SetImage();
}
void Shot::Update() {
  if (flag) {
    x += xv; y += yv;
    // 画面外に出た場合、無効にする
    if (x < 0 || GetWidth() < x || y < 0 || GetHeight() < y) flag = false;
  }
}
void Shot::Draw() {
  if (flag) {
    if (image) DrawGraph((int)(x - size / 2), (int)(y - size / 2), image1, TRUE);
    else DrawGraph((int)(x - size / 2), (int)(y - size / 2), image2, TRUE);
  }
}
void Shot::SetImage() {
  size = 16;
  if (image1 == -1) image1 = LoadGraph("./images/shot1.png");
  if (image2 == -1) image2 = LoadGraph("./images/shot2.png");
}
// 座標、速度、画像を指定し発射する
void Shot::Shoot(double nx, double ny, double nxv, double nyv, bool fimg) {
  x = nx; y = ny; xv = nxv; yv = nyv;
  image = fimg; flag = true;
}

図4 「Object.h」ファイルに追加するコード

class Object {
public:
  bool flag; // 有効無効を示すフラグ
};

図5 「Player.h」ファイルに追加するコード

#include "Shot.h"
class Player : public Object {
private:
  int shot_num; // 現在の弾配列の添字
  int shot_span; // 弾の発射間隔
  void SetShot(); // 弾関連の設定用関数
  void ShotFire(); // 弾発射用の関数
public:
  static const int shot_max = 20; // 弾配列の要素数
  Shot shot[shot_max]; // 弾配列
};

図6 「Player.cpp」ファイルに追加するコード

Player::Player() {
  flag = true; // 有効フラグを設定立てる
  this->SetShot(); // 自機の弾関連の設定
}
void Player::Update() {
  this->ShotFire(); // 自機の弾の発射
  for (int i = 0; i < shot_max; i++) shot[i].Update();
}
void Player::Draw() {
  for (int i = 0; i < shot_max; i++) shot[i].Draw();
}
void Player::SetShot() {
  shot_num = 0; shot_span = 0;
  for (int i = 0; i < shot_max; i++) shot[i] = Shot();
}
void Player::ShotFire() {
  if (GetKey(KEY_INPUT_Z)) {
    // 発射間隔shot_span が4 以上になったとき
    if (shot_span++ >= 4) {
      // 自機位置から弾を発射する
      shot[shot_num++].Shoot(x, y, 0, -8, false);
      // 配列の添字が要素数以上になったときは0 にする
      if (shot_num >= shot_max) { shot_num = 0; }
      // 発射間隔のリセット
      shot_span = 0;
    }
  }
}

図7 「MainScene.h」ファイルに記述するコード

#include "Shot.h"
#include <vector>

class MainScene {
private:
  int enemy_span; // 弾の発射間隔
  double enemy_shot_base; // 発射角度
  std::vector<Shot> enemy_shot; // 敵機の弾配列

public:
  void StageInitialize(); // パラメータ初期化用関数
  void StageUpdate(); // 敵機の弾発射を実装する関数
};

図8 「MainScene.cpp」ファイルに追加するコード

#define _USE_MATH_DEFINES
#include <math.h>

MainScene::MainScene() {
  StageInitialize(); // 追加したパラメータの初期化
}
void MainScene::Update() {
  for (auto itr = enemy_shot.begin(); itr != enemy_shot.end();) {
    if (!(*itr).flag) itr = enemy_shot.erase(itr);
    else { (*itr).Update(); itr++; }
  }
  StageUpdate(); // ステージの更新
}
void MainScene::Draw() {
  for (auto itr = enemy_shot.begin(); itr != enemy_shot.end(); ++itr)
    (*itr).Draw(); // 敵機の弾の描画
}
void MainScene::StageInitialize() {
  enemy_span = 0; enemy_shot_base = 0;
}
void MainScene::StageUpdate() {
  if (enemy_span++ >= 50) {
    double shot_v = 2.0; int shot_num = 36;
    for (int i = 0; i < shot_num; i++) {
      double angle = enemy_shot_base + M_PI / 18 * i; // 発射角度
      enemy_shot.push_back(Shot()); // インスタンスを末尾に追加
      enemy_shot.back().Shoot(enemy.x, enemy.y, shot_v * cos(angle),
                              shot_v * sin(angle), true); // 発射
    }
    enemy_shot_base += 0.1; // 基準の角度を更新
    enemy_span = 0; // 発射間隔を初期化
  }
}

図10 「Info.h」ファイルに追加するコード

#include "Object.h"

// 2 オブジェクトの当たり判定用関数
void Collision(Object *obj1, Object *obj2);

図11 「Info.cpp」ファイルに追加するコード

#include <math.h>
void Collision(Object *obj1, Object *obj2) {
  double dx = obj1->x - obj2->x; // X 座標の差
  double dy = obj1->y - obj2->y; // Y 座標の差
  double ds = obj1->hit_size + obj2->hit_size; // 半径の合計
  // 有効フラグが立っているかどうかの確認
  if (!obj1->flag || !obj2->flag) return;
  // 三平方の定理を使用
  if (pow(dx, 2) + pow(dy, 2) <= pow(ds, 2)) {
    // 当たり判定後の処理
    obj1->CollisionResult();
    obj2->CollisionResult();
  }
}

図12 「Object.h」ファイルに追加するコード

class Object {
public:
  int hit_size; // 当たり判定エリアの半径
  // 当たり判定後の処理用関数
  virtual void CollisionResult() {}
};

図13 「Player.h」ファイルに追加するコード

class Player : public Object {
public:
  int hp_now, hp_max; // 体力の現在値、最大値
  void CollisionResult(); // 当たり判定後の処理用関数
};

図14 「Player.cpp」ファイルに追加するコード

Player::Player() {
  hp_now = hp_max = 3; // 体力の初期化
}
void Player::SetImage() {
  hit_size = 8;
}
void Player::CollisionResult() {
  if (hp_now-- < 0) flag = false;
}

図15 「Enemy.h」ファイルに追加するコード

class Enemy : public Object {
public:
  int hp_now, hp_max;
  void CollisionResult();
};

図16 「Enemy.cpp」ファイルに追加するコード

Enemy::Enemy() {
  hp_now = hp_max = 100; // 体力
  flag = true; // 有効フラグを立てる
}
void Enemy::SetImage() {
  hit_size = 32;
}
void Enemy::CollisionResult() {
  if (hp_now-- < 0) flag = false;
}

図17 「Shot.h」ファイルに追加するコード

class Shot : public Object {
public:
  // 当たり判定後の処理用関数
  void CollisionResult();
};

図18 「Shot.cpp」ファイルに追加するコード

void Shot::SetImage() {
  hit_size = 8;
}
void Shot::CollisionResult() { flag = false; }

図19 「MainScene.cpp」ファイルに追加するコード

void MainScene::Update() {
  // 自機の弾と敵機の当たり判定処理
  for (int i = 0; i < player.shot_max; i++)
    Collision(static_cast<Object*>(&player.shot[i]), static_cast<Object*>(&enemy));
  // 自機と敵機の弾の当たり判定処理
  for (auto itr = enemy_shot.begin(); itr != enemy_shot.end(); itr++)
    Collision(static_cast<Object*>(&player), static_cast<Object*>(&(*itr)));
}
void MainScene::Draw() {
  DrawFormatString(0, 0, GetColor(255, 255, 255), "Player : %d", player.hp_now);
  DrawFormatString(GetWidth() - 120, 0, GetColor(255, 255, 255), "Enemy : %d", enemy.hp_now);
}

図20 「Info.h」ファイルに追加する コード

// ゲームシーンの取得用関数
int GetGameScene();
// ゲームシーンの設定用関数
void SetGameScene(int val);

図21 「Info.cpp」ファイルに追加するコード

int g_GameScene; // シーン管理用変数
int GetGameScene() { return g_GameScene; }
void SetGameScene(int val) { g_GameScene = val; }

図22 「TitleScene.h」ファイルに 記述するコード

#pragma once
class TitleScene {
private:
  int wait; // 待ち時間
public:
  TitleScene();
  bool Update();
  void Draw();
};

図23 「TitleScene.cpp」ファイルに記述するコード

#include "DxLib.h"
#include "TitleScene.h"
#include "Info.h"

TitleScene::TitleScene() {
  SetBackgroundColor(100, 100, 100); // 背景を灰色に
  wait = 30;
}
bool TitleScene::Update() {
  // スペースキーを押したら、true を返す
  if (wait-- < 0 && GetKey(KEY_INPUT_SPACE)) return true;
  return false;
}
void TitleScene::Draw() {
  DrawFormatString(200, 200, GetColor(255, 255, 255), " タイトルです.");
  DrawFormatString(200, 400, GetColor(255, 255, 255), " スペースキーを押してください.");
}

図25 「ResultScene.h」ファイルに記述するコード

#pragma once
class ResultScene {
public:
  bool Update();
  void Draw();
};

図26 「ResultScene.cpp」ファイルに記述するコード

#include "DxLib.h"
#include "ResultScene.h"
#include "Info.h"

bool ResultScene::Update() {
  if (GetKey(KEY_INPUT_SPACE)) return true; // メインシーンに遷移
  return false;
}
void ResultScene::Draw() {
  // ゲームクリア時
  if (GetGameScene() == 2) {
    SetBackgroundColor(255, 255, 255); // 背景を白色に
    DrawFormatString(300, 200, GetColor(0, 0, 0), " ゲームクリア !!");
  }
  // ゲームオーバー時
  else {
    SetBackgroundColor(255, 100, 100); // 背景を赤色に
    DrawFormatString(300, 200, GetColor(0, 0, 0), " ゲームオーバー...");
  }
  DrawFormatString(300, 360, GetColor(0, 0, 0), " スペースキーを押すと");
  DrawFormatString(300, 380, GetColor(0, 0, 0), " タイトルに戻ります.");
  DrawFormatString(300, 420, GetColor(0, 0, 0), " 終了には、ESC キー.");
}

図29 「Main.cpp」ファイルに追加するコード

#include "TitleScene.h"
#include "ResultScene.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
         LPSTR lpCmdLine, int nCmdShow)
{
  TitleScene ts = TitleScene(); 
  ResultScene rs = ResultScene();
  while (ProcessMessage() == 0 && ScreenFlip() == 0 &&
      ClearDrawScreen() == 0) {
    // ms.Update(); ms.Draw(); は消してその部分に以下を追加
    int t = 0;
    switch (GetGameScene()) {
      case 0:
        if (ts.Update()) { ms = MainScene(); SetGameScene(1); break; }
        ts.Draw();
        break;
      case 1:
        if((t = ms.Update()) != 0) { SetGameScene(t); break; }
        ms.Draw();
        break;
      default:
        if (rs.Update()) { ts = TitleScene(); SetGameScene(0); break; }
        rs.Draw();
        break;
    }
  }
}

図30 「MainScene.h」ファイルに追加 するコード

class MainScene {
public:
  // void Update(); 行は削除
  int Update();
};

図31 「MainScene.cpp」ファイルに追加するコード

// void MainScene:Update() { 行を次の行に置き換えてから太字部分をブロック末尾に追加
int MainScene::Update() {
  if (player.hp_now <= 0) { return 3; }
  if (enemy.hp_now <= 0) { return 2; }
  return 0;
}
void MainScene::StageUpdate() {
  if (enemy_span++ >= 50) {
    // 体力が半分より大きいとき
    if (enemy.hp_now > enemy.hp_max / 2) {
        // このブロックに既存のコードを挿入
    }
    // 体力が半分以下のとき、ランダムな角度に多数の弾を発射
    else {
      double shot_v = 1.0 + GetRand(40) / 10.0;
      int shot_num = 2;
      for (int i = 0; i < shot_num; i++) {
        double angle = M_PI * (GetRand(3600) / 10.0) / 180;
        enemy_shot.push_back(Shot());
        enemy_shot.back().Shoot(
          enemy.x, enemy.y, shot_v * cos(angle), shot_v * sin(angle), true
        );
      }
    }
  }
}

バーティカルバーの極意(Vol.62掲載)

投稿日:2019.09.25 | カテゴリー: コード

著者:飯尾 淳

 しばらくデータ分析の話題から遠ざかっているような気がしますが、 ちょっとしたトレーニングをするつもりで前回、前々回と同様にプログラミングの話を続けましょう。今回は、状態遷移図に基づくシステムの動作原理を考えます。最初に簡単なケースを考え、その後で少しブラッシュアップして仕様をアップデートします。
 ところで、状態遷移図は「GraphViz1」というツールで描画します。この連載のテーマである「バーティカルバー」(垂直棒または縦棒)を用いた表現も指定できますが、今回は縦横にこだわらず柔軟に表現してみましょう。

シェルスクリプトマガジン Vol.62は以下のリンク先でご購入できます。

図2 メッセージ出力プログラム

#!/usr/bin/env python

import random

class Node:
    def __init__(self, label):
        self.label = label
        self.nodes = []

    def addNode(self, node):
        self.nodes.append(node)

    def nextNode(self):
        return random.choice(self.nodes)

    def putLabel(self):
        print(self.label, end="")
        return self

    def main():
        cur = n1 = Node(" ガ")
        n2 = Node(" ン")
        n3 = Node(" ズ")
        n4 = Node(" ダ")
        e = Node("")
        n1.addNode(n2); n1.addNode(n2)
        n2.addNode(n1); n2.addNode(n3)
        n2.addNode(n4); n2.addNode(e)
        n3.addNode(n4)
        n4.addNode(n2); n4.addNode(n2)

        while(cur != e):
            cur = cur.putLabel().nextNode()
        print()

    if __name__ == "__main__":
        main()

図4 メッセージ出力プログラムの改良版(gangan2.py)

#!/usr/bin/env python

import random

class Node:
    def __init__(self, label):
        self.label = label
        self.nodes = []

    def addNode(self, node):
        self.nodes.append(node)

    def nextNode(self):
        n = random.choice(self.nodes)
        self.nodes.remove(n)
        return n

    def putLabel(self):
        print(self.label, end="")
        return len(self.nodes)

def main():
    cur = n1 = Node("ガ")
    n2 = Node("ン")
    n3 = Node("ズ")
    n4 = Node("ダ")
    n1.addNode(n2); n1.addNode(n2)
    n2.addNode(n1); n2.addNode(n3) 
    n2.addNode(n4)
    n3.addNode(n4)
    n4.addNode(n2); n4.addNode(n2)

    while (cur.putLabel() > 0):
        cur = cur.nextNode()
    print()

if __name__ == "__main__":
    main()

  • shell-mag ブログの 2019年9月 のアーカイブを表示しています。

  • -->