Windows コマンドプロンプト 事始め

コマンドプロンプト

コマンドプロンプトを使用してやるとGUIでは面倒な操作を簡単にできます。
例えば、フォルダをたくさん作成するとかファイルをいろんな場所に移動するなど。。。

しかし、コマンドプロンプトの画面が何を意味しているのか?わからないことには使うこともできません。

ちょっと使えるようになると、とても「オレってすげぇ~」と感じるかもしれません(笑)。

コマンドプロンプトの画面

初期表示したときは、ユーザーディレクトリが表示されます。
例えば、Windowsのユーザーが「Takunoji」の場合は、下のように表示されます。

C:\User\Takunoji

そして、Cドライブをネットにさらすのはよろしくないので、画像は、別のディレクトリになっていますが、イメージとしては下のようなものです。※Usersまでは共通なので。。。

そして、上の画像にある「C:\Users」というのがカレントディレクトリになります。

CDコマンドで移動することができます、そして移動したときには、カレントディレクトリがその移動先に代わります。

細かい部分は動画にて解説しました。

ますは、CDコマンドと、DIRコマンドを覚えましょう。

単純なものですので、フォルダ表示しながら解説しました。カレントディレクトリを示すC:\などは「パス」といいファイル、もしくはディレクトリの場所を示すものです。

でわでわ。。。

android Tesseract エラー: シンボルを見つけられません

エラー: シンボルを見つけられません

シンボル: クラス Size
場所: クラス com.googlecode.leptonica.android.Pix

エラー: パッケージandroid.support.annotationは存在しません

上のようなエラーが出ました。同様に下のようなエラーも出ました。

同様に、以下のクラスも見つかりませんでした。

  • com.googlecode.leptonica.android.Binarize
  • com.googlecode.leptonica.android.Box
  • com.googlecode.leptonica.android.Boxa
  • com.googlecode.leptonica.android.Constants
  • com.googlecode.leptonica.android.Edge
  • com.googlecode.leptonica.android.JpegIO
  • com.googlecode.leptonica.android.MorphApp
  • com.googlecode.leptonica.android.Rotate
  • com.googlecode.tesseract.android.TessBaseAPI.PageSegMode

解決策

プロジェクトのbuild.gradleに以下のコードを追加する

implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

そして、足りないパッケージの追加は下の画面よりできるはず。。。

Maven エラー ~execute but there is no POM in this directory (/home/pi/repos)~

but there is no POM

ラズパイでMavenを使用してgithubから作成したプログラムをダウンロードしようとしたところ表題のようなエラーが出ました。

エラーメッセージ

he goal you specified requires a project to execute but there is no POM in this directory (/home/pi/repos). Please verify you invoked Maven from the correct directory. -> [Help 1]

こちらのサイトでは、POMファイルのあるディレクトリで実行すればOKみたいなことを記載していたので、そのようにしました。

そしたら次のようなエラーに代わりました。

Unknown lifecycle phase "pom.xml". You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]

mvn clean

とりあえずは、一度きれいにしたほうが良いと思い、「mvn clean」コマンドを実行

どうやら、成功したようです。

mvn default

次に、通常のビルドをかけようと考え、上記の「mvn default」を実行しました。
リモートデスクトップ環境なのとラズパイ2なので、まぁ遅いです。。。
※インストールしているOSはRaspberry Desltopです。。。

そして、出力されたエラーは下のようなものです。

Unknown lifecycle phase "default". You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]

初めに出たエラーと同様なものです。つまりは、mvn XXXXのXXXX部分が不適切であろうという判断ができます。

そんなわけで、初めに実行したコマンドから「pom.xml」を取り除き再度実行しました。以下のコマンドです。

mvn install

mvn install

改めて、上記のコマンドを実行したところWarninngはあるけど何とか成功しました。

でわでわ。。。

Java じゃんけんゲームを作ってみる ~基本文法をマスターする~

じゃんけんゲーム

Javaプログラミングの基本文法を理解するためにも、実際にアプリケーションを作ってみるのが手っ取り早い方法です。

教科書などを眺めても、実践に勝る学習はありません。つまりは。。。

経験に勝る知識なし!

ということです。

じゃんけんゲームの処理内容

本来は、自分で考えて仕様を考えるべきですが、初めの一歩ということで使用を提示します。

作成するクラスは「JankenPon」クラスにします。

<じゃんけんゲームの仕様>

  1. 標準入力での、0:グー、1:チョキ、2:パーと定義する
  2. ユーザーの手(入力)とCPUの手(乱数)を表示する
  3. 勝敗判定を行い、「YOU_WIN」か「YOU_LOSE」「DRAW」を表示する

この様に使用を決めたらそれぞれの項目(要件)を満たすようにプログラムを作ります。

0:グー、1:チョキ、2:パーと定義する

標準入力を受け取りグー~パーを判定します。
どのように実装したらよいでしょうか?

今回は、試しに以下のような実装をしてみましょう。

if文をマスターする

マスターするといっても、普通に使うだけですが。。。

Scanner scan = new Scanner(System.in);
int input = Integer.parseInt(scan.nextLine());
String jankenTe = null;
if (input == 0) {
    jankenTe = "グー";
} else if (input == 1) {
    jankenTe = "チョキ";
} else if (input == 2) {
    jankenTe = "パー";
} else {
    System.out.println("想定外の値です。" + input);
}

じゃんけんの手をString型の変数JankenTeに設定(代入)します。
0, 1, 2以外の値が入力されたときは想定外の値です。

ユーザーの手(入力)とCPUの手(乱数)を表示する

CPUの手を乱数を使って表示します。これはもう説明する必要はないと思います。

// 0-2の乱数を生成する
cpuTe = String.valueOf(new Random().nextInt(2));

if (cpuTe.equals("0")) {
    jankenCpu = "グー";
} else if (cpuTe.equals("1")) {
    jankenCpu = "チョキ";
} else if (cpuTe.equals("2")) {
    jankenCpu = "パー";
}

これも、if文で実装することができます。もちろん、より良いアイディアがあればそちらの実装を行うのが正しい判断です。検証するのを忘れないようにしてください。

勝敗判定を行い、「YOU_WIN」か「YOU_LOSE」「DRAW」を表示する

勝敗判定は、ちょっと良いアイディアが出ず。。。そのまま判定処理を作りました。
はっきり言ってダメダメなコードです。

String hantei = input + cpuTe;
String result = null;
if (hantei.equals("01")) {
    result = "YOU_WIN";
} else if (hantei.equals("12")) {
    result = "YOU_WIN";
} else if (hantei.equals("20")) {
    result = "YOU_WIN";
} else if (hantei.equals("00")) {
    result = "DRAW";
} else if (hantei.equals("11")) {
    result = "DRAW";
} else if (hantei.equals("22")) {
    result = "DRAW";
} else if (hantei.equals("02")) {
    result = "YOU_LOSE";
} else if (hantei.equals("10")) {
    result = "YOU_LOSE";
} else if (hantei.equals("21")) {
    result = "YOU_LOSE";
} else {
    System.out.println("想定外の値です。" + hantei);
}

何とかじゃんけんゲームができました。しかし、このようなプログラムは美しくありません。

別に「アーティスチックでないからダメ」といっているわけではなく、見ずらいしわかりずらい。

人にやさしくないプログラムだということです。

人にやさしく

ズバリ、読みやすく、理解しやすいコードが良いブログラムです。もちろん、余計なメモリを使わないとかいろいろありますが。。。

ちなみに、上のようなコードで作成したじゃんけんゲームは以下のようなコードになりました。

public static void main(String[] args) {
    // 1.初めの処理
    System.out.println("じゃんけん ...");
    Scanner scan = new Scanner(System.in);

    // 2.標準入力受付
    String input = scan.nextLine();
    String jankenTe = null;

    // 3.ユーザーの手を判定する
    if (input.equals("0")) {
        jankenTe = "グー";
    } else if (input.equals("1")) {
        jankenTe = "チョキ";
    } else if (input.equals("2")) {
        jankenTe = "パー";
    } else {
        System.out.println("想定外の値です。" + input);
    }

    String cpuTe = null;
    String jankenCpu = null;
    if (jankenTe == null) {
        // 強制終了
        System.exit(-1);
    } else {
        // 4.CPUの手を判定する
        cpuTe = String.valueOf(new Random().nextInt(2));

        if (cpuTe.equals("0")) {
            jankenCpu = "グー";
        } else if (cpuTe.equals("1")) {
            jankenCpu = "チョキ";
        } else if (cpuTe.equals("2")) {
            jankenCpu = "パー";
        }
    }
    System.out.println("ポン");
    System.out.println("あなた: " + jankenTe + " CPU; " + jankenCpu);

    // 5.勝敗判定を行う
    String hantei = input + cpuTe;
    String result = null;
    if (hantei.equals("01")) {
        result = "YOU_WIN";
    } else if (hantei.equals("12")) {
        result = "YOU_WIN";
    } else if (hantei.equals("20")) {
        result = "YOU_WIN";
    } else if (hantei.equals("00")) {
        result = "DRAW";
    } else if (hantei.equals("11")) {
        result = "DRAW";
    } else if (hantei.equals("22")) {
        result = "DRAW";
    } else if (hantei.equals("02")) {
        result = "YOU_LOSE";
    } else if (hantei.equals("10")) {
        result = "YOU_LOSE";
    } else if (hantei.equals("21")) {
        result = "YOU_LOSE";
    } else {
        System.out.println("想定外の値です。" + hantei);
    }
    // 6. 結果の表示
    System.out.println(hantei);
    System.out.println(result);
}

しかし、やはりだめなコード(個人的にそのように思う)なので、これをまともなコードに直します。

この様な行為のことをリファクタリングといいます。

リファクタリング

まずは、読みずらいところを洗い出します。
以下の部分が読みずらいと思いました。

1.if文のネスト(階層化しているところ)が無駄なネストになっている

String cpuTe = null;
String jankenCpu = null;
if (jankenTe == null) {
    // 強制終了
    System.exit(-1);
} else {
    // 4.CPUの手を判定する
    cpuTe = String.valueOf(new Random().nextInt(2));

    if (cpuTe.equals("0")) {
        jankenCpu = "グー";
    } else if (cpuTe.equals("1")) {
        jankenCpu = "チョキ";
    } else if (cpuTe.equals("2")) {
        jankenCpu = "パー";
    }
}

どこが、無駄かというとelse~の部分です。もしjannkenTeがnullになっているのならば、プログラムを強制終了するので、if-elseでわける意味がありません。無駄なコードになっているのです。

ではどのようになおすか?ズバリ下のように直します。elseが丸まる必要ないのです。

String cpuTe = null;
String jankenCpu = null;
if (jankenTe == null) {
    // 強制終了
    System.exit(-1);
}

// 4.CPUの手を判定する
cpuTe = String.valueOf(new Random().nextInt(2));

if (cpuTe.equals("0")) {
    jankenCpu = "グー";
} else if (cpuTe.equals("1")) {
    jankenCpu = "チョキ";
} else if (cpuTe.equals("2")) {
    jankenCpu = "パー";
}

処理の内容を考えてみれば、不要ですよね?なぜなら

System.exit(-1);

でプログラムは強制終了(引数に「-1」を与えているので『異常終了』)するからです。

つまり、if文の中の処理を行うとき=jankenTeがnullの時は「CPUの手を判定」より後の処理が行われません。

メソッドを利用する

その他にも、行けていないところがあります。それは、似たような処理がたくさんあるというところです。
特にif文の処理が同じような処理を行っています。

なので、メソッドを作成して同じコードを書かないようにします。

今までに、ちょこっと書いたりしました。改めて理解しましょう。

具体的には、以下のif文です。2か所、同じコードがあります。

String jankenTe = null;
if (input.equals("0")) {
    jankenTe = "グー";
} else if (input.equals("1")) {
    jankenTe = "チョキ";
} else if (input.equals("2")) {
    jankenTe = "パー";
} else {
    System.out.println("想定外の値です。" + input);
}

これをメソッドとして切り出します。具体的には下のように切り出します。staticがついているのはメインメソッドから呼び出すためです。

public static String jankenHantei(String input) {
    String jankenTe = null;
    if (input.equals("0")) {
        jankenTe = "グー";
    } else if (input.equals("1")) {
        jankenTe = "チョキ";
    } else if (input.equals("2")) {
        jankenTe = "パー";
    } else {
        System.out.println("想定外の値です。" + input);
    }
    return jankenTe;
}

そして、このコードと同じ部分を書き換えます。下のようなコードになりました。

public class JankenPon {
    public static void main(String[] args) {
        // 1.初めの処理
        System.out.println("じゃんけん ...");
        Scanner scan = new Scanner(System.in);

        // 2.標準入力受付
        String input = scan.nextLine();
        // 3.ユーザーの手を判定する
        String jankenTe = jankenHantei(input);

        String cpuTe = null;
        String jankenCpu = null;
        if (jankenTe == null) {
            // 強制終了
            System.exit(-1);
        }
        // 4.CPUの手を判定する
        cpuTe = String.valueOf(new Random().nextInt(2));
        jankenCpu = jankenHantei(cpuTe);

        System.out.println("ポン");
        System.out.println("あなた: " + jankenTe + " CPU; " + jankenCpu);

        // 5.勝敗判定を行う
        String hantei = input + cpuTe;
        String result = null;
        if (hantei.equals("01")) {
            result = "YOU_WIN";
        } else if (hantei.equals("12")) {
            result = "YOU_WIN";
        } else if (hantei.equals("20")) {
            result = "YOU_WIN";
        } else if (hantei.equals("00")) {
            result = "DRAW";
        } else if (hantei.equals("11")) {
            result = "DRAW";
        } else if (hantei.equals("22")) {
            result = "DRAW";
        } else if (hantei.equals("02")) {
            result = "YOU_LOSE";
        } else if (hantei.equals("10")) {
            result = "YOU_LOSE";
        } else if (hantei.equals("21")) {
            result = "YOU_LOSE";
        } else {
            System.out.println("想定外の値です。" + hantei);
        }
        // 6. 結果の表示
        System.out.println(hantei);
        System.out.println(result);
    }

    public static String jankenHantei(String input) {
        String jankenTe = null;
        if (input.equals("0")) {
            jankenTe = "グー";
        } else if (input.equals("1")) {
            jankenTe = "チョキ";
        } else if (input.equals("2")) {
            jankenTe = "パー";
        } else {
            System.out.println("想定外の値です。" + input);
        }
        return jankenTe;
    }
}

これで、多少はよくなりました。しかし、まだです。

Mapインターフェースを使用する

じゃんけんの判定方法ですが、すごく頭の悪いやり方です。しかし、これから見せるコードも頭の良いやり方ではありません。なぜかというと、何の工夫もないからです。

頭の良いやり方ではない方法
まずは下のような、フィールド変数(定数)とメソッドを作成します。

/** フィールド変数(定数) */
public static final String YOU_WIN = "YOU_WIN";
public static final String YOU_LOSE = "YOU_LOSE";
public static final String DRAW = "DRAW";</pre>

そして、次のメソッドを追加します。
<pre> public static String jankenHantei(String input) {
        String jankenTe = null;
        if (input.equals("0")) {
            jankenTe = "グー";
        } else if (input.equals("1")) {
            jankenTe = "チョキ";
        } else if (input.equals("2")) {
            jankenTe = "パー";
        } else {
            System.out.println("想定外の値です。" + input);
        }
        return jankenTe;
    }

作成したメソッドを使用して、メインメソッドを書き直します。

そうすると下のようになりました。

public class Chap0 {
    public static final String YOU_WIN = "YOU_WIN";
    public static final String YOU_LOSE = "YOU_LOSE";
    public static final String DRAW = "DRAW";

    public static void main(String[] args) {
        // 1.初めの処理
        Map<String, String> hanteiMap = createMap();
        System.out.println("じゃんけん ...");
        Scanner scan = new Scanner(System.in);

        // 2.標準入力受付
        String input = scan.nextLine();
        // 3.ユーザーの手を判定する
        String jankenTe = jankenHantei(input);

        String cpuTe = null;
        String jankenCpu = null;
        if (jankenTe == null) {
            // 強制終了
            System.exit(-1);
        }
        // 4.CPUの手を判定する
        cpuTe = String.valueOf(new Random().nextInt(2));
        jankenCpu = jankenHantei(cpuTe);

        System.out.println("ポン");
        System.out.println("あなた: " + jankenTe + " CPU: " + jankenCpu);

        // 5.勝敗判定を行う
        String hantei = input + cpuTe;
        String result = hanteiMap.get(hantei);
        // 6. 結果の表示
        System.out.println(hantei);
        System.out.println(result);
    }

    public static String jankenHantei(String input) {
        String jankenTe = null;
        if (input.equals("0")) {
            jankenTe = "グー";
        } else if (input.equals("1")) {
            jankenTe = "チョキ";
        } else if (input.equals("2")) {
            jankenTe = "パー";
        } else {
            System.out.println("想定外の値です。" + input);
        }
        return jankenTe;
    }

    public static Map<String, String> createMap() {
        Map<String, String> hanteiMap = new HashMap<String, String>();
        hanteiMap.put("01", YOU_WIN);
        hanteiMap.put("12", YOU_WIN);
        hanteiMap.put("20", YOU_WIN);
        hanteiMap.put("00", DRAW);
        hanteiMap.put("11", DRAW);
        hanteiMap.put("22", DRAW);
        hanteiMap.put("02", YOU_LOSE);
        hanteiMap.put("10", YOU_LOSE);
        hanteiMap.put("21", YOU_LOSE);

        return hanteiMap;
    }
}

実行結果は下のような形で出力されました。

じゃんけん ...
1
ポン
あなた: チョキ CPU; チョキ
11
DRAW

如何でしょうか?だいぶすっきりしたように見えると思います。プログラムの処理内容が理解できていれば、無図解ことではありません。「このような方法もある」というのを知っておくと後々にカッコよいコードが書けるようになります。※自分も努力いたします。。。

でわでわ。。。

Windows Cドライブの節約をする ~シンボリックを貼る~

Cドライブの節約をする

WindowsのCドライブがいっぱいになりそうなときシンボリックリンクを使用して問題の容量不足を解消できます。

正確には、ドライブの仕様先を別なドライブに変更するということです。

シンボリックリンク

例えば、Google Chormeなどのブラウザ・アプリケーションを使用するとC:\Users\ユーザー名\AppData\Local

フォルダにデータが蓄積されていきます。

これでは、少ないCドライブにデータが保存され、使用可能な領域がなくなっていきます。なのでCドライブにデータを保存せずに、指定した場所に保存する様に変更する事ができるようになります。

早い話が

シンボリックリンクを使ってデータの保存先を変更しようと言う事です。

前提条件

  1. シンボリックリンクを作成するフォルダが存在しないこと
  2. 変更先(新しく保存する場所)にファイルが存在していること

上記の注意点を踏まえて、下のコマンドを実行します。

mklink /d "シンボリックリンクを作成するフォルダのパス" "新しく保存する場所"

具体的には下のようなコマンドを実行しました。コマンドの実行をしてエラーが出るときは上に記載した、前提条件を満たしていない事が予想されますので見直してみてください。

コマンドの確認とエラーメッセージも見ましょう。

mklink /d "C:\Users\Takunoji\AppData\Local\Android" "D:\AndroidStudio4.1"

これでデータの保存先をCドライブからDドライブに移動できました。

以上です。

Andoroid アプリを作る ~Javaでスマホアプリ環境構築~

Andoroid アプリを作る

そろそろと、Androidアプリの作成に入りたいと思います。
今までに考えてきた、目標達成アプリの作成に着手します。細かい部分に関しては、Gitに記載しています。

Android Studioのインストール

Androidのダウンロードページからインストーラーをダウンロードします。

ダウンロードしたインストーラーを起動します。

インストールディレクトリの指定以外はそのまま次へを選択しました。

AndroidStudio

起動すると下のような画面が開きます。

セットアップウィザードで、SDKのインストール先を聞かれますが、これもそのままの値を使用します。

つまりは、ディレクトリの設定以外はいじらないということです。

そして、インストール完了、結構時間がかかりました。

まずは。。。

Androidのアプリ作成について理解します。ここでのポイントは、大まかに理解するところです。

アプリ作成の土台になるAndoroidのアプリはフレームワークになっていて、多少の仕組みがあります。その一つにライフサイクルというものがあり、画面がどのように開いて、閉じて、アプリを終了するか?
その処理の流れを決定しているものが「フレームワーク」です。

  1. Androidのアーキテクチャ
  2. Java Android 〜スマホアプリではじめるJava〜
  3. Java Android 2〜Androidアプリの見た目を作る〜
  4. Java Android 3〜Androidアプリの見た目を変更する〜
  5. Java Android 6〜計算アプリのJavaコードを書く〜

プロジェクトの作成

「Create New Project」を選択します。

そして、Empty Activityを選択します。

さらに、プロジェクト名を入力します。日本語にすると文字化けしたときに面倒なので英語にしました。
あと、使用するプログラミング言語を選択できるのでJavaを選択しました。
Javaだと、OpenCVや、OpenGLなどと連携。。。Kotlinでもできるのかもしれませんが、大体のことは大体できるようになるので、こちらの言語を選択しました。

Androidの最低バージョンの選択として、6(Nougat)約5年前(2020-02-12現在)を選択しました。

一番下のチェックボックスはチェックを入れませんでした。有料ライブラリもあるようなので、後程追加する方向で作業を行おうと考えました。

ワークスペース(開発の画面)が開いたら、しばらくGradleのインストールなどの処理が走りますのでちょっと待機します。
下の方に、次のようなプログレスバーが見れます。

とりあえずは動かしてみました。次は環境設定を行います。

よくよく見るとビルドエラーが出ています。

Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:

これに関しては、こちらのページに詳細があるようです。

そして、EventLogの部分に詳細なエラーないようがあるのでそれを見て解決します。

1 error
Consult IDE log for more details (Help | Show Log) (2 m 45 s 517 ms)
8:51 Android Studio is using the following JDK location when running Gradle:
D:\Apps\AndroidStudio\jre
Using different JDK locations on different processes might cause Gradle to

そして、調べてみるとおかしなところに気が付きました。

参考サイト

おかしなところ

  1. AndroidStudioのインストール先をDドライブにした。
  2. JDKの設定をしていない

上のものは、自分の予想でしたが、JDKの設定以外は関係ありませんでした。

JDKの設定

File -> Project Structure

実際に使用しているJDKとインストールしたSDKを指定します。

しかしまだエラーが出ます。

import org.jetbrains.plugins.gradle.tooling.internal.ExtraModelBuilder

そして

unable to resolve class org.jetbrains.plugins.gradle.tooling.internal.ExtraModelBuilder

つまるところは、このクラスのインポートが必要ということで。。。

Gradleで依存関係の追加を行う必要があるということでした。Gradleの使い方はこちらのサイトを参考にしました。

下のコードをbuild.gradleに追加します。コピー元はこちらです。

/**
 * The buildscript block is where you configure the repositories and
 * dependencies for Gradle itself—meaning, you should not include dependencies
 * for your modules here. For example, this block includes the Android plugin for
 * Gradle as a dependency because it provides the additional instructions Gradle
 * needs to build Android app modules.
 */

buildscript {

    /**
     * The repositories block configures the repositories Gradle uses to
     * search or download the dependencies. Gradle pre-configures support for remote
     * repositories such as JCenter, Maven Central, and Ivy. You can also use local
     * repositories or define your own remote repositories. The code below defines
     * JCenter as the repository Gradle should use to look for its dependencies.
     *
     * New projects created using Android Studio 3.0 and higher also include
     * Google's Maven repository.
     */

    repositories {
        google()
        jcenter()
    }

    /**
     * The dependencies block configures the dependencies Gradle needs to use
     * to build your project. The following line adds Android plugin for Gradle
     * version 4.0.0 as a classpath dependency.
     */

    dependencies {
        classpath 'com.android.tools.build:gradle:4.0.0'
    }
}

/**
 * The allprojects block is where you configure the repositories and
 * dependencies used by all modules in your project, such as third-party plugins
 * or libraries. However, you should configure module-specific dependencies in
 * each module-level build.gradle file. For new projects, Android Studio
 * includes JCenter and Google's Maven repository by default, but it does not
 * configure any dependencies (unless you select a template that requires some).
 */

allprojects {
   repositories {
       google()
       jcenter()
   }
}

そうするとAndroidStudioに下のようなダイアログ?が出ます。

クリックしますとビルドが始まりマス。

これでもダメでした。。。

調べてみると、Android4.1での問題があるようです。こちらの記事に詳細がありますのでそれを参照すると、AndroidStudioをアップグレードしてください、ということだったのでそのようにしようとしました。

ディスクの空き容量の問題で断念しました。仕方ないので別のPCで実装することにします。。。
別のPCはMACです。

でわでわ。。。

関連記事一覧

AngularJS PHP Ecllipse ~簡単なウェブアプリケーション実装~

AngularJS PHP Ecllipse

表題の通りのフレームワークと、API、IDEを使用して実装を進めようと思います。
必要な環境は下の記事にセットアップ方法を記述しています。

AngularJSに関しては、PHP(HTML)ファイルに下のような記述を行うと使用することができます。

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
<script src="script.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

設計をする

実装するにも、まずは設計をしないと始まりません。ただし、堅苦しく行いません。作るものは「31アイス」のレジ機能です。設計は次の通りです。

  1. 初期画面に開始ボタンを作成して表示する
  2. 多言語対応をする
  3. ログイン後、メニュー画面を表示する
  4. メニュー画面では、31アイスのフレーバー、コーン or カップの選択を行い、会計をする

環境構築

参考サイト;PHPUnitのインストール

  1. Eclipseを使用しますが、これにプラグインを追加します。Eclipse PDTです。
  2. Eclipseの実行の構成を開きます。

    3.構成の内容を入力します。単一のテストを行う設定だと、JavaProjectではPHPUnitの実行クラスを選択できません。
  3. PHPUnitテストを実行する

余談:Composerのインストール(for windows)はここからインストーラーをダウンロードできます。ダウンロードページはこちらです。

そして、実行の構成部分に関してはこちらのサイトを参照しました。

画面の実装

画面側は、AngularJSでの実装になります。
作成するのは、初期画面とログインのモーダル画面です。

ちなみに、ログインのモーダル画面はここからコピッて使用しました。

ちなみに、自分の作成したものは下のような感じです。

今後も更新していきます。

でわでわ。。。

基本情報技術者試験 ~暗記物「画像処理」~

静止画処理

静止画の基本

画像データの持ち方:(X, Y, D)

  1. X軸とY軸での座標を使用して表示する点の位置を決定する

  2. D = 濃度の情報(8ビットであれば256階調)
    ※2進数で8ビットで並ぶと2の8乗=256

  3. イメージとしては下のようなもの(8bit画像) ※白 = 0

  4. よく聞くRGBは24bit画像で、(X, Y, (R,G,B))となる、画像がイマイチ。

濃度とか色に関して

  • 8ビット画像では、0~256の色を選択する形
  • 24ビット画像では、RGB(赤、緑、青)の濃度をせっていし、各色を表現する => (8bit, 8bit, 8bit)

画像処理ソフト

  1. Adobe Lightroom
  2. GIMP
  3. Fotor
  4. PIXLR EDITOR

画像処理ライブラリ

  • OpenCV
    ※機械学習~背景補完などの処理APIが入っている
     静止画~動画を扱える

動画処理

1枚の画像をフレームとして扱い、1秒間に使用するフレームの数をフレームレートという。

以下、有名なファイル規格(拡張子) 名前 説明
JPEG 画像圧縮、国際規格(動画用の圧縮規格)
MPEG 動画圧縮、ISO規格(動画用の圧縮規格)
MP4 MPEG4のこと
MOV Quick timeで使用している
VRML 3次元グラフィックデータ(映像)
AVI Windows系のOSで使用しているWMVを格納する圧縮ファイル

コンピュータグラフィック(CG)

下のような処理が一般的にある

名前 説明
エイリアス 画像処理における意味では、ギザギザが見えることをいう
アンチエイリアシング 斜線や曲線に出るギザギザを目立たなくする、手段として「ぼかし」などがある
テクスチャマッピング 3Dモデリングされたもの(オブジェクト)の表面に画像を貼り付け質感を出す
ブレンディング 半透明の度合いを表現する。透明度情報を重ね合わせる。
レイトレーシング 光線などを追跡することで、観測される像の趣味レーションを行う
クリッピング 画像全体から表示する部分を抜き取って表示する
シューティング 表示している物体の影を描画する(ピクセル単位で行うときはピクセルシェーダという)
モーフィング ある形状から別の形状に変化させる事
レンダリング データを表示できるように、映像化する処理
ポリゴン 多角形体のこと、3次元モデル以外でも使用する 
 キーフレーム法 フレームともう一つのフレームの間を補完する処理を行いアニメーションを作成する

Robocode ワークショップ ~Javaに触れてみよう~

イントロダクション

Robocodeを使用して、Javaプログラミングを始めるきっかけとしてほしい、もしくはJavaという言語で遊べるということを紹介しようと考えました。

以前、Robocodeを紹介する記事を書きました。のでよかったらご覧ください。
そして、実際にワークショップを開きたいと考えております。そのために必要なことをまとめました。

ワークショップを開くための実行準備メモといったところです。

アジェンダ

そもそも「アジェンダ」って何よ?と思い、調べました。

会議で論ずる事項(議題)の表。比喩的に、課題項目。

つまり、「やることリスト」という理解です。

Robocodeアジェンダ

Robocodeのワークショップとして実行しようと考えているのは以下のものです。

  1. PCにRobocodeをインストールする
  2. サンプルバトルの起動、およびゲームの内容確認
  3. 自分のRoboの作成(コードは自動生成される)
    4.自分のRoboをバトルに参加させてみる
  4. Roboの動きとコードの内容を見比べて内容を大まかに理解する
  5. Javaコードを書いて、動きを変えてみる
  6. 動きを定義するメソッド「run」「onScannedRobot」「onHitByBullet」「onHitWall」の改造をしてみる
  7. 起動確認と実装アイディアの話し合い
  8. みんなで作成したRoboで対決する
  9. ワークショップの感想と今後の目標や、やりたいことの発表

この様なワークフローでワークショップを開こうと考えておりますが、必要になるものや、前もって調べておく(理解しておく)必要があるものがあるので、それを以下に記載いたします。

1.Robocodeをインストール

RobocodeのダウンロードはSourceForgeからできます。

そして、細かい情報はWikiがあります。

プログラミングに詳しくなくても、まったく問題ありません。このレベルのプログラミングは「アイディア」が最も重要です。

プログラムの細かい部分に関しては調べて理解すればよいし、もっと本格的な改造などを使用と考えなければJavaプログラミングをイチから学習する必要はありません。

もし、イチから学習したいと思ったらぜひやってください。
自分のお勧めする学習手順は以下のリンクにあります。よかったらどうぞ。

Java はじめて 学習フロー

2.サンプルバトルの起動、およびゲームの内容確認

実際にサンプルバトルを起動したときの画像が下のものになります。

早い話が、最後まで生き残ることがこのゲームの勝利条件です。

そのために、以下のメソッドに定義する処理(動き)を工夫して、他のプレーヤーに負けないようにすることが主な目的になります。

3.自分のRoboの作成(コードは自動生成される)

やり方に関しては、こちらの記事の「Roboを作る」に記載していますが、この部分は、チュートリアル的に作業を行う感じになります。

4.自分のRoboをバトルに参加させる

これは画面操作のみです。

  1. 新しバトルを開く

  2. 自作のRoboをバトルに追加する

5.Roboの動きとコードの内容を見比べて内容を大まかに理解する

Roboを動かす処理は大きく4つあります。

  1. 通常(デフォルト)の動き(run)
  2. 敵Roboをスキャンしたときの処理(onScannedRobot)
  3. 弾に当たったときの処理(onHitByBullet)
  4. 壁にぶつかったときの処理(onHitWall)

それぞれの動きを定義しているのが、上の強調表示している名前がそうです。この名前は、メソッドというものの名前になります。

Javaプログラミングのルール

Javaはプログラムをすべて「クラス」で表現します。そして、クラスの中には「フィールド変数(属性というときもあります)」と「メソッド(振る舞いを示す)」を定義することができ、「{}」で囲った部分がクラスとメソッドの範囲を示します。

クラスの書き方

/**
  * 「/**」出始めるコメント部分をJavaDocコメントといいます。
  */
public class クラス名 {
    /** JavaDocコメント */
    int 変数名;
    /**
     * JavaDocコメント、メソッドの説明
     */
    public 返り値 メソッド名(引数) {
        // 通常のコメント部分
        /*
         * 「/*」で始まるコメント部分は通常のコメントとして扱います。
         */
         // メソッドの処理を書きます。
    }
}

これはJavaプログラミングのルールなので、どんなクラスでも「フィールド変数」と「メソッド」の2つの要素が存在します。※必ずでこの2つがある必要はありません。

具体的には、下のようなコードです。※抜粋しています。

クラスの定義:作成したRoboの名前は「FirstRobot」

/**
 * FirstRobot - a robot by (your name here)
 */
public class FirstRobot extends Robot
{
   // 4つの動きを定義しているメソッドの定義があります。
}

そして、4つの動きにに対応する処理(メソッド)は以下のようになっています。

メソッドの定義:各アクションの定義

  1. 通常(デフォルト)の動き(run): ゲーム開始時のデフォルトの動きを定義します。

    /**
    * run: FirstRobot's default behavior
    */
    public void run() {
    aliveTime = 0;
    // Initialization of the robot should be put here
    showStatus();
    // After trying out your robot, try uncommenting the import at the top,
    // and the next line:
    
    // setColors(Color.red,Color.blue,Color.green); // body,gun,radar
    aliveTime = 0;
    // Robot main loop
    while(true) {
        // Replace the next 4 lines with any behavior you would like
        ahead(10);
        turnGunRight(360);
    }
    }
  2. 敵Roboをスキャンしたときの処理(onScannedRobot)

    /**
    * onScannedRobot: What to do when you see another robot
    */
    public void onScannedRobot(ScannedRobotEvent e) {
    // Replace the next line with any behavior you would like
    fireBullet(120);
    }
  3. 弾に当たったときの処理(onHitByBullet)

    
    /**
    * onHitByBullet: What to do when you're hit by a bullet
    */
    public void onHitByBullet(HitByBulletEvent e) {
    // Replace the next line with any behavior you would like

}


4. 壁にぶつかったときの処理(onHitWall)
```java
/**
 * onHitWall: What to do when you hit a wall
 */
public void onHitWall(HitWallEvent e) {
    // Replace the next line with any behavior you would like
    turnRight(90);
}

ちなみに、「弾に当たったとき」「壁にぶつかったとき」「スキャンしたとき」のように「~のとき」処理が動くような仕組みのことを「イベントハンドラ」と呼び、よく「~のイベントを受け取ったとき。。。」などのように話をします。

6.Javaコードを書いて、動きを変えてみる

上に示した、各イベントに対応するメソッド=「run」「onScannedRobot」「onHitByBullet」「onHitWall」に定義してある処理を変更してみます。
実際に使用できるコードはある程度決まっていて詳細に関しては、こちらのJavaDocというドキュメントに記述があります。

JavaDocとは

JavaDocはプログラムを書くときにクラスやメソッドの説明を書くときに使用するコメント文です。

そして、Roboを動かすために使用できるメソッドはこのリンク先に記載があります。

表にまとめると以下のようになります。

表A

返り値 メソッド名 振る舞い(処理の内容)
void ahead(double distance) ロボットを前方に移動させます。
void back(double distance) ロボットを後方に移動させます。
void doNothing() このロボットの今回の順番では、何も動作を行いません。
void finalize() システムによって呼び出され、ロボットのクリーンアップ (終結処理) を行います。
void fire(double power) 弾丸を発射します。
Bullet fireBullet(double power) 弾丸を発射します。
double getBattleFieldHeight() 現在のバトルフィールドの高さを取得します。
double getBattleFieldWidth() 現在のバトルフィールドの幅を取得します。
double getEnergy() ロボットの現在のエネルギーを戻します。
double getGunCoolingRate() 大砲の冷却速度を戻します。
double getGunHeading() 大砲の向きを 360 度形式で戻します。
double getGunHeat() 大砲の現在の熱さを戻します。
double getHeading() ロボットの現在の向きを 360 度形式で戻します。
double getHeight() ロボットの高さを戻します。
String getName() ロボットの名前を戻します。
int getNumRounds() 現在のバトルのラウンド数を戻します。
int getOthers() 敵ロボットの残り台数を戻します。
double getRadarHeading() レーダーの向きを 360 度形式で戻します。
int getRoundNum() 現在のラウンドが、 バトルの第何ラウンドかを戻します (1~getNumRounds() の範囲)
long getTime() 現在のゲーム時刻を戻します。
double getVelocity() このロボットの移動速度を戻します。
double getWidth() ロボットの幅を戻します。
double getX() ロボットの X 座標の位置を戻します。
double getY() ロボットの Y 座標の位置を戻します。
void onBulletHit(BulletHitEvent event) このロボットが発射したいずれかの弾丸が他のロボットに当たったとき、 このメソッドが呼び出されます。
void onBulletHitBullet(BulletHitBulletEvent event) このロボットが発射したいずれかの弾丸が他の弾丸に当たったとき、 このメソッドが呼び出されます。
void onBulletMissed(BulletMissedEvent event) このロボットが発射したいずれかの弾丸がはずれたとき (壁に当たったとき)、 このメソッドが呼び出されます。
void onDeath(DeathEvent event) このメソッドは、ロボットが死んだときに呼び出されます。 このイベントが通知されるようにするには、 ロボットのコードでこのメソッドをオーバーライドする必要があります。
void onHitByBullet(HitByBulletEvent event) このロボットに弾丸が命中したとき、このメソッドが呼び出されます。
void onHitRobot(HitRobotEvent event) このロボットが他のいずれかのロボットと衝突したとき、 このメソッドが呼び出されます。
void onHitWall(HitWallEvent event) このロボットが壁に衝突したとき、このメソッドが呼び出されます。
void onRobotDeath(RobotDeathEvent event) このメソッドは、 他のいずれかのロボットが死んだときに呼び出されます。 このイベントが通知されるようにするには、 ロボットのコードでこのメソッドをオーバーライドする必要があります。
void onScannedRobot(ScannedRobotEvent event) このロボットが他のロボットを発見したとき、 このメソッドが呼び出されます。
void onWin(WinEvent event) このロボットがバトルに勝ったとき、このメソッドが呼び出されます。
void resume() stop() による停止中の動作があれば、その動作を再開します。
void run() 各ロボットのメイン・メソッド。
void scan() 他のロボットを探します。
void setAdjustGunForRobotTurn(boolean newAdjustGunForRobotTurn) ロボットが回転するときに、 大砲が自動的に逆方向に回転するように設定します。
void setAdjustRadarForGunTurn(boolean newAdjustRadarForGunTurn) 大砲が回転するときに、 レーダーが自動的に逆方向に回転するように設定します。
void setAdjustRadarForRobotTurn(boolean newAdjustRadarForRobotTurn) ロボットが回転するときに、 レーダーが自動的に逆方向に回転するように設定します。
void setColors(Color robotColor, Color gunColor, Color radarColor) このメソッドは、ロボットの色を設定するために呼び出します。
void stop() 動作をすべて停止し、 後で resume() 呼び出しを使って再開できるよう、保存します。
void stop(boolean overwrite) 動作をすべて停止し、 後で resume() 呼び出しを使って再開できるよう、保存します。
void turnGunLeft(double degrees) ロボットの大砲を回転させます。
void turnGunRight(double degrees) ロボットの大砲を回転させます。
void turnLeft(double degrees) ロボットを回転させます。
void turnRadarLeft(double degrees) ロボットのレーダーを回転させます。
void turnRadarRight(double degrees) ロボットのレーダーを回転させます。
void turnRight(double degrees) ロボットを回転させます。

JavaDocには詳細な情報が記述されているので、このドキュメントを読んで理解できるとかなり強いプログラマーとして君臨できます(笑)

とりあえずは、JavaDocにあるメソッドを実装して動かしてみるのが、一番です。

7. 動きを定義するメソッド「run」「onScannedRobot」「onHitByBullet」「onHitWall」の改造をしてみる

具体的に実装を行います。JavaDocを参考に、各メソッドにそれぞれのメソッドを実装し、プログラムを実行して動きを確認してみます。

以前作成した動画で丁度良いのがあったのでそれを載せます。

具体的には、デフォルトの動き「run()」メソッドの定義と動きを確認してモノです。

ポイントとしては以下の通りです。上に記載した表Aから抜粋しました。 返り値 メソッド名 振る舞い(処理の内容)
void ahead(double distance) ロボットを前方に移動させます。
void back(double distance) ロボットを後方に移動させます。

コードとしては、次のようなものです。

while(true) {
   ahead(100);
   turnGunRight(360);
   back(100);
   turnGunRight(360);
}

下の「while(true)」と書いてある部分は次に書いてある「{」から「}」までの間を無限ループする処理を書いています。デフォルトの動きなので、無限ループしている処理なのでしょう。

8. 起動確認と実装アイディアの話し合い

上の表Aから各メソッドの中に、それぞれのコードを書いたり消したりしながら、Roboを最強な動きにできるように、アイディアを出し合ったり、プログラムの内容を理解したり、みんなでワイワイやると面白いだろうな、というのが自分の思惑ですが、果たしてどうなるでしょうか?

9. みんなで作成したRoboで対決する

この部分に関しては、Robocodeのウェブサーバーがあるのでそれをダウンロード、起動といった準備が必要になります。

この部分に関しては、後日追記します。

でわでわ。。。

Robocodeの記事はこちらです。

Java ネットワーク ~Socket通信アプリを作る~

イントロダクション

以前から中途半端になっていた「プロコンゲーム」の作成に関して、進展がありました。
テキストRPGと合体させた形にしようと思いました。
詳細に関しては後日。。。

取り入れる要素としては、テキストRPGを取り入れることにしようと思います。

このテキストRPGとU16-プログラミングコンテストを組み合わせたようなものを作成しようと考えています。

ユースケースとしては、下のようなものです。

Socket通信について

JavaFXで作成した画面にクライアントアプリからアクセスします。
<JavaFX画面>

そのアクセス時に、使用するのがSocket通信です。
具体的には下のようなコードを書きます。

/**
 * クライアントのリクエストを受け付けるサーバー。
 * 通称プロコンサーバー
 *
 * @author 実装者の名前
 */
private class MainServer extends Thread {
    /** サーバ */
    private ServerSocket server;
    /** サーバー停止フラグ  */
    private boolean isStop;

    public MainServer() throws Exception {
        server = new ServerSocket(ProConServerConst.SERVER_PORT);
    }

    public void run() {
        isStop = false;
        ExecutorService service = Executors.newCachedThreadPool();

        try {
            while (isStop == false) {
                System.out.println("Run FxServer");
                Socket socket = server.accept();
                service.submit(new ProConServer(socket));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            server = null;
        }
    }
    public void finalize() {
        try {
            if (server != null) server.close();
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            server = null;
        }
    }
}

finalizeメソッドはガベージコレクションでインスタンスが破棄されるときに動くメソッドなので、メモリの開放処理をいれています。

Executerクラス

Executerフレームワークを使用して、複数スレッドの処理を実行します。このときに使用している

ProConServer

クラスには、

Runable

インターフェースの実装と

Observable

クラスを継承しています。

これにより、ProConRPGServerクラスがクライアントから送信された初期情報を受け取ったときに受信したデータを

Observable

を継承した

ProConRPGLogic

クラスで受け取れるようにします。

図にすると下のようなイメージです。

  1. クライアントAPからアクセス
  2. MainServerでリクエスト受信
  3. ProConServerクラスを新しいスレッドで起動
  4. それぞれのスレッドでクライアントAPからのリクエストを待機、処理を行う

ProConRPGLogicクラス

コードは下のように定義します。

public class ProConRPGLogic extends Application implements Games, Observer {

このクラスは、インナークラスにMainServerを持っています。そして、このクラス自体は画面を表示します。JavaFXのメイン処理を行います。

つまり、下のようなイメージになります。

ProConRPGLogicクラスで画面を起動して、インナークラスのMainServerでSocket通信でデータを送ってくるクライアントアプリからのリクエストを待ちます。

実装としては、下のようなコードです。JavaFXのApplicationクラスを継承しているので、「start()」メソッドをオーバーライドして、画面を起動しまします。もちろん、呼び出し元では、「launch()」を呼びます。
<呼び出し元>

public static void main(String[] args) throws Exception {
    ProConRPGLogic logic = new ProConRPGLogic();
    ProConRPGEngine target = new ProConRPGEngine(logic);
    target.start();

}

<ProConRPGLogic>

@Override
public void start(Stage primaryStage) {
    try {
        exeServer();
    } catch (Exception e1) {
        e1.printStackTrace();
    }
    primaryStage.initStyle(StageStyle.TRANSPARENT);
    System.out.println("Hello");
    // FXMLのロード
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/ProConTitleView.fxml"));
    VBox root = null;

    try {
        root = (VBox) loader.load();
        root.setStyle("-fx-background-color: transparent;");
    } catch (Exception e) {
        e.printStackTrace();
    }

    Scene scene = new Scene(root);
    scene.setFill(null);
    scene.getStylesheets().add(getClass().getResource("/views/ProConTitleView.css").toExternalForm());
    primaryStage.setTitle("Video Processing");
    primaryStage.setScene(scene);
    primaryStage.show();

}

まだ実装できていませんが、リクエストを受信後、黒い四角の部分にクライアントからのイメージを表示、そのほか名前などを表示し、スタートボタンでゲーム開始という形で実装しようと考えています。

そして、クライアントアプリに関して

クライアントAP

単純にSocketクラスを使用します。

/**
 * プロコンRPGを開始する。
 */
public void exevuteRpg() throws Exception {
    BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
    // 送受信するクラス
    ClientData data = createInitData();
    // 初期リクエストを送信する
    this.sendRequest(output, data);

    input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    System.out.println("exevuteRpg Client: " + this.getResponse(input));

    output = new ObjectOutputStream(socket.getOutputStream());
    this.sendRequest(new PrintWriter(socket.getOutputStream()), "bye");
    // サーバーとの通信処理
    while (isStop == false) {
        input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        output = new ObjectOutputStream(socket.getOutputStream());
        // サーバーからのレスポンスを取得する
            String response = this.getResponse(input);
            String request = handleResponse(response);
System.out.println("exevuteRpg Client Recieve: " + request);
        // 処理の待機処理(U16プロコンサーバーに習う)
//          Thread.sleep(ProConServerConst.WAIT);
        data.setCommand("bye");
        this.sendRequest(output, data);
        //isStop = true;
    }
}

このクラスも、サーバー側と同じような実装になります。localhostの2000番ポートにアクセスして、データをサーバーに送信、レスポンスを受信します。
<送信>

/**
 * リクエストをプロコンサーバーへ送信する。
 *
 * @param message
 * @throws IOException
 */
public void sendRequest(ObjectOutputStream request, ClientData message) throws IOException {
    if (isEmpty(message)) {
        throw new IOException("リクエストメッセージが入っていません");
    }
    request.writeObject(message);
    request.flush();
//      request.close();
}

初回送信時には、クラスをサーバーに送信するのでObjectOutputStreamを使用しました。

<受信>

/**
 * サーバーから受信したデータを受け取る。
 *
 * @param response
 * @return
 * @throws IOException
 */
public String getResponse(BufferedReader response) throws IOException {

    String line = null;
    StringBuilder build = new StringBuilder();
    int ch = -1;
    System.out.println("*** Client ***");
    while ((ch = response.read()) != -1) {
        build.append((char) ch);
        if (ch == 10 || ch == 13) {
            break;
        }
    }
    //response.close();
    System.out.println("Client Recieve: " + build.toString());
    return build.toString();
}

受信に関しては、レスポンスがテキストで帰ってくるように設計したのでBufferedReaderを使用しています。

注意点としては、サーバーとクライアントでINとOUTが混同しやすいというところです。
<クライアント>

  1. 送信:OutputSteamを使用
  2. 受信:InputStreamを使用する

<サーバー>

  1. 受信:OutputSteamを使用する
  2. 送信:InputStreamを使用する

処理の順番が逆になります。自分は結構混乱しました。。。

イメージの送受信

Socketでのデータ送信(ネットワーク経由のデータ送信)では、データを一度直列化する必要があります。なので、送信するデータクラスは下のようにSerializableインターフェースを実装する日宇町があります。

public class SocketTest implements Serializable { ... }

そして、イメージなどの大きなデータはbyte配列で送信する必要があります。具体的に下のように書きます。ちなみに、lombokを使用しているのでgetter setterは実装していません。

<データクラス>

/**
 * クライアント(ゲームプレーヤー)のデータクラス。
 *
 * @author 実装者の名前
 *
 */
@Data
public class ClientData implements Serializable {
    /** アクセスコード */
    private String accessCd;
    /** プレーヤー番号 */
    private int playerNo;
    /** プレーヤーの名前 */
    private String name;
    /** 生年月日 */
    private String birthDay;
    /** 32 x 32の画像データ(透過PNG) */
    byte[] imageByte;
    /** 32 x 32の画像データ(透過PNG) */
    BufferedImage image;

    /** 送信するコマンド */
    private String command;
}</pre>

<イメージの変換処理>
<pre>/**
 * イメージファイルを取得して、バイト配列に変換する
 * 取得するイメージファイルは、src/main/resources/char以下のPNGファイル)
 *
 * @param fileName ファイルの名前(拡張子は除く)
 * @return
 */
protected byte[] imageToByte(String fileName) {
    byte[] result = null;
    try {
        URL imgUrl = Paths.get("resources/char_img/" + fileName + ".png").toUri().toURL();
        BufferedImage img = ImageIO.read(imgUrl);
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        // イメージをバイト配列に書き込み
        ImageIO.write(img, "png", outStream);

        result = outStream.toByteArray();
        //result = ByteBuffer.allocate(ProConServerConst.MAX_IMG_SIZE).putInt(outStream.size()).array();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return result;
}

<バイト配列からイメージ>

// バイト配列からBufferedImage
BufferedImage image = ImageIO.read(new ByteArrayInputStream(playerImage));

マルチスレッド処理

このゲームでは複数のプレーヤーが遊ぶ予定です。なので、複数のプレーヤーを受け付けるための実装が必要になります。

クライアントからの受付をする

Socket通信なので、受付待機と受付後の処理を実装します。下のメソッドはThreadクラスのrunメソッドをオーバーライドして実装していますので、複数スレッドでの実行が可能となっています。

@Override
public void run() {
    isStop = false;
    ExecutorService service = Executors.newFixedThreadPool(4);

    try {
        System.out.print("Run FxServer");
        Socket socket1 = server1.accept();
        System.out.println(" accept!");

        ProConServer pro1 = new ProConServer(socket1, logic);

        service.submit(pro1);

        // ProConServerからの通知待機
        synchronized(pro1) {
            System.out.println("sync MainServer");
            while(pro1.isReady() == false) {
                pro1.wait();
            }
            Platform.runLater(() -> {
                try {
                    logic.setClientData(pro1.getFirstRequest(), ProConServerConst.PLAYER1_NO);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (server1 != null) server1.close();
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }
}

ポイントとしては、Executorクラスを使用しているので、複数スレッドでの処理が簡単に実装できるというところです。
<通知処理>

// 通知
synchronized(this) {
    System.out.println("sync ProConServer");
    setReady(true);
    notify();
}

<待機処理>

// ProConServerからの通知待機
synchronized(pro1) {
    System.out.println("sync MainServer");
    while(pro1.isReady() == false) {
        pro1.wait();
    }
    Platform.runLater(() -> {
        try {
            logic.setClientData(pro1.getFirstRequest(), ProConServerConst.PLAYER1_NO);
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
}

そして、下のコードでは、他のクラスの処理の完了町を行う処理を実装しています。
Observerパターンを使用(java.util.current.Observable)を使用した方法でも実装できそうでしたが、うまくいきませんでした。

でわでわ。。。

関連ページ一覧

[Eclipse セットアップ](http://zenryokuservice.com/wp/2020/09/01/%e9%96%8b%e7%99%ba%e7%92%b0%e5%a2%83%e6%a7%8b%e7%af%89%ef%bd%9ewindows%e7%89%88eclipse%e3%81%ae%e8%a8%ad%e5%ae%9a%ef%bd%9e/)

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

JavaFX関連ページ

  1. Eclipse SceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~
  3. JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜
  4. Java プロコンゲーム 〜見た目の作成(SceneBuilderの使用)〜

ステップアップ関連ページ一覧

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine

JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜

オブジェクト指向関連ページ

  1. [オブジェクト指向の概念1〜OracleDocのチュートリアル1〜](https://zenryokuservice.com/wp/2019/10/301. /%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e6%8c%87%e5%90%91%e3%81%ae%e6%a6%82%e5%bf%b5-%e3%80%9coracledoc%e3%81%ae%e3%83%81%e3%83%a5%e3%83%bc%e3%83%88%e3%83%aa%e3%82%a2%e3%83%ab%ef%bc%91/)
  2. オブジェクト指向の概念2〜クラスとは〜

Java Discord

  1. IntelliJ IDEA Discord Botを作る〜Gradle環境のセットアップ〜
  2. Java Discord セットアップ〜Hello Discord〜
  3. Java Discord ピンポン〜Discordプログラム〜
  4. Java Discord Listener実装〜コマンドを好きなだけ追加しよう〜