アルゴリズムは使用するプログラミング言語に引きづられる

Written by じび on 10月 9th, 2018

某所で5分以内にプログラムを考えるという課題がありました。

最初にプログラミング言語を選択するのですが、最近は swift ばかりなので swift を選択しました。

その後に出たお題は「文字列を逆順にする。ただし、プログラミング言語にある逆順にする命令などは使わないこと」というものです。

そこで私の思考は、以下のようになりました。

  1. 文字列は文字の配列
  2. 配列を処理するならイテレータ
  3. 先頭から文字をとっていき、新しい配列の先頭にインサートしていけばいける

IDEなしだったので、仮想コードですが、以下のような感じに書きました。

let src = "hogemoge"
var dest = ""

for char in src {
    dest.insert(0, char)
}

しかし、帰りの電車で、C言語ならもっと効率良くできることに気づきました。

  1. 最初と最後の文字をスワップ
  2. 最初+1と最後-1の文字をスワップ
  3. 上記の処理を「文字数 / 2」回繰り返す
unsinged char *src = "hogemoge";
unsigned char swap;

for (int i = 0, int last = strlen(src) - 1; i < strlen(src) / 2; i++, last--, ) {
    swap = src[i]
    src[i] = src[last]
    src[last] = swap
}

なぜ、思いつかなかったのだろうと考えたのですが、最初に言語を選択していたため、そこでよく使う手法に囚われていたのです。swift だと文字列を文字単位で扱うことはあまりないため、配列として処理しようと考えてしまったのです。それに対してC言語はビット単位やバイト単位で扱うことが多いので、すんなりと効率が良いアルゴリズムに導かれたのでした。

「オブジェクト指向プログラミング入門 第二版 (ティモシイ・A. バッド)」の「1.2 言語と思考」にも、APLのプログラマが行列のソートで解決した話が載っていましたが、まさにその通りのことを身を以て体験したのでした。

 

[shell][iOS] クローンからシミュレーターでの実行までやってくれるスクリプト

Written by じび on 10月 5th, 2018

大きめの iOS アプリの開発をやっていると、クローンもライブラリのダウンロードもビルドも全てにおいて時間がかかるようになります。
それぞれを個別に人間が実行すると面倒なので、Git のクローンからシミュレーターでの実行まで、連続してやってくれるシェルスクリプトを作りました。

#!/bin/sh -e

if [ $# -ne 1 ]; then
    echo "Usage:runMyProject branch" 1>&2
    exit 1
fi

Repository="https://github.com/UserName/MyProject"
ProjectFile="MyProject.xcodeproj"

echo "===== git clone ====="
git clone -b $1 ${Repository} .

echo "===== carthage bootstrap ====="
carthage bootstrap --platform ios --no-use-binaries --cache-builds

echo "===== open Xcode ====="
open ${ProjectFile}
sleep 20

echo "===== Xcode run ====="
osascript -e 'tell application "Xcode"
    activate
    run active workspace document
end tell'
  • ファイル名やシェル変数の Repository および ProjectFile は、各自の環境に合わせて変えてください。
  • 最後に iOS Simulator での実行までやってますが、ビルドで止めたいときは、run の部分を build に変えてください。

実行時は、まずディレクトリを作って、その中に入り、第一パラメーターにクローンしたいブランチ名を指定して起動します。
$ mkdir hoge
$ cd hoge
$ runMyProject develop

改良したい点としては、

  • Xcode を起動後、20秒待つのではなく、立ち上がり完了を検知するようにしたい。
  • iOS シミュレーターの種類を指定できるようにしたい。
 

日和号弐号機の設計

Written by じび on 10月 4th, 2018

我が家にはソーラーパネルで発電し、バッテリーに電気を貯める、ポータブル太陽光蓄電システム「日和号改」があります。

今年もキャンプに持って行ったのですが、バッテリーがへたってしまい、あまり電気を貯められなくなりました。
バッテリーだけ買い換えても良いのですが、設計から4年も経ち、電力の使用事情も変わって来ました。
そこで増えた電力量を計算の上、弐号機を設計することにしました。

1日に使用する電力量

iPhone のバッテリー 約3,000mAh * 3.7V -> 11.1Wh -> 12Wh
変換時のロスを20%として 12 * 1.2 -> 14.4Wh -> 15Wh
一日に5台充電するとして、15 * 5 -> 75Wh

必要なソーラーパネル

1日の発電量は、ソーラーバルのW数 * 3h
必要なソーラーパネルの発電能力は、75 / 3 -> 25wh

必要なバッテリー

1日で消費される電力量が、バッテリーの25%までになるように設計する。
75Wh * 4 -> 300Wh
12Vバッテリーの場合、300Wh / 12V -> 25Ah

初号機は不要になるので、使える部品は再利用します。
コントローラー、シガーソケット、スイッチなと。

ソーラーパネルは30wのものがあるので、それを使います。
バッテリーは、これくらいの容量になると車用のが安いのですが、屋内に設置するので、ガスが出ない通信機器用の密閉型にします。
バッテリーは25Ahのだと割高なので、思い切って50Ahのにしましょう。

 

iPhone 5S フロントパネル交換

Written by じび on 9月 17th, 2018

iPhone 5S のフロントパネルをホームボタンごと交換しました。
しばらく前にバッテリーを交換したのですが、フロントパネルと液晶パネルの接着剤が剥がれていました。
そのまま取り付け取り外しをしていたら、ホームボタンまで効かなくなったのて、丸ごと交換しました。

開けて見たところ、ホームボタンのリボンケーブルが千切れていました。

新しいタッチパネルはちょっと動きが悪いのと、ボタンの押し込みが純正よりも重いのですが、概ね好調です。

 

[Swift] Swift Package Manager

Written by じび on 8月 1st, 2018

Swift Package Manager とは、Apple純正のSwift用ライブラリ管理ツールです。
CocoaPodsやCarthageみたいなものですね。
Swift3から使用できるそうなので、試して見ました。

ライブラリの作り方

まずは取り込まれるライブラリ側の作り方です。
コマンドラインにて、フォルダを作り、ライブラリ用に初期化します。
$ mkdir Increment
$ cd Increment
$ swift package init
Creating library package: Increment
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/Increment/Increment.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/IncrementTests/
Creating Tests/IncrementTests/IncrementTests.swift
Creating Tests/IncrementTests/XCTestManifests.swift
$

このままコマンドラインで開発を続けることもできるのですが、Xcode Projectを作って、Xcode上で開発できるようにしてみましょう。

$ swift package generate-xcodeproj
generated: ./Increment.xcodeproj
$

以下のようにするとコマンドライからXcodeで開けます。
$ open Increment.xcodeproj
$

デフォルトで Sources/Increment/Increment.swift が作成されているので、書き換えます。
今回はInt型にincrementメソッドを追加してみました。

extension Int {
    public var increment: Int {
        return self + 1
    }
}

テストコード(Tests/IncrementTests/IncrementTests.swift)も書きましょう。

import XCTest
@testable import Increment

final class IncrementTests: XCTestCase {
    func testExample() {
        XCTAssertEqual(1.increment, 2)
    }

    static var allTests = [
        ("testExample", testExample),
    ]
}

書き換えた後はテストを実行して、ビルドおよびテストが通ることを確認してください。
コマンドライの場合は、以下の通りです。
$ swift test
Compile Swift Module 'Increment' (1 sources)
Compile Swift Module 'IncrementTests' (2 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/IncrementPackageTests.xctest/Contents/MacOS/IncrementPackageTests
Test Suite 'All tests' started at 2018-08-01 08:08:00.046
Test Suite 'IncrementPackageTests.xctest' started at 2018-08-01 08:08:00.047
Test Suite 'IncrementTests' started at 2018-08-01 08:08:00.047
Test Case '-[IncrementTests.IncrementTests testExample]' started.
Test Case '-[IncrementTests.IncrementTests testExample]' passed (0.206 seconds).
Test Suite 'IncrementTests' passed at 2018-08-01 08:08:00.253.
Executed 1 test, with 0 failures (0 unexpected) in 0.206 (0.207) seconds
Test Suite 'IncrementPackageTests.xctest' passed at 2018-08-01 08:08:00.254.
Executed 1 test, with 0 failures (0 unexpected) in 0.206 (0.207) seconds
Test Suite 'All tests' passed at 2018-08-01 08:08:00.254.
Executed 1 test, with 0 failures (0 unexpected) in 0.206 (0.207) seconds

最後にgitリポジトリを作って、’1.0.0’として登録しておきます。

$ git init
Initialized empty Git repository in /Users/hide/Documents/tmp/SoftwareDesign/sd201807/HelloWorldLibrary/.git/
$ git add .
$ git commit -am 'Version 1.0.0'
[master (root-commit) 7a9fdf6] Version 1.0.0
7 files changed, 70 insertions(+)
create mode 100644 .gitignore
create mode 100644 Package.swift
create mode 100644 README.md
create mode 100644 Sources/HelloWorldLibrary/HelloWorldLibrary.swift
create mode 100644 Tests/HelloWorldLibraryTests/HelloWorldLibraryTests.swift
create mode 100644 Tests/HelloWorldLibraryTests/XCTestManifests.swift
create mode 100644 Tests/LinuxMain.swift
$ git tag 1.0.0

アプリの作り方

続いて、ライブラリを使うアプリ側の作り方です。
初期化のオプションに –type=executable が付くのがライブラリとは異なります。

$ mkdir IncrementApp
$ cd IncrementApp
$ swift package init --type=executable
Creating executable package: HelloWorldApp
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/HelloWorldApp/main.swift
Creating Tests/
$

ここで Package.swift ファイルが作られているので、それを書き換えます。
デフォルトでは以下のようになっています。

// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "HelloWorldApp",
    dependencies: [
        // Dependencies declare other packages that this package depends on. 
        // .package(url: /* package url */, from: "1.0.0"),
    ],  
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
        .target(
            name: "HelloWorldApp",
            dependencies: []),
    ]   
)

package.dependencies[]にIncrementへのパスとバージョンを記述します。
ここではローカルのパスを指定していますが、GitHubのリポジトリを指定することも可能です。

    dependencies: [
        // Dependencies declare other packages that this package depends on. 
        .package(url: "../Increment", from: "1.0.0"),
    ],  

package.targets[0].target.dependenciesにて、IncrementAppで使用するライブラリを記述します。

        .target(
            name: "IncrementApp",
            dependencies: ["Increment"]),

続いて、Sources/IncrementApp/main.swiftにアプリの実行コードを記述します。
1から10までの数値をインクリメントしたものを表示します。

import Increment

_ = (1...10).map { print($0.increment) }

これで完成です。
最後にアプリを実行して見ます。
$ swift run
Compile Swift Module 'IncrementApp' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/IncrementApp
2
3
4
5
6
7
8
9
10
11

参考

  • Software Designe 2018年7月号