Java プロコンゲーム 〜見た目の作成(SceneBuilderの使用)〜

今回からは、プロコンゲーム(プログラミングコンテスト向けゲーム)の作成を始めようと思います。

前回作成した、設計(UMLのユースケース図)より順番に作成して行きます。

1.バッチをダブルクリックする

「1.バッチをダブルクリックする」の部分に関しては、作成したプログラムを起動するためのバッチ。。。

Windowsの場合は、「〜.bat」でMacやLinuxの場合は「〜.sh」というファイルで作成したプログラム(JARファイル)を起動するものなので作成するのは
最後になります。

プレーヤ受付画面

早速、プレーヤ受付画面の作成を始めます。
そして、設計するのにはUMLの「クラス図」を使用します。
細かい書き方などは下のリンク先に記載しています。

  1. UML 世界を作る 〜RPGでの世界を作る場合〜
  2. UMLの書き方(読み方)〜概要とクラス図〜
  3. UMLツール Star UML〜ユースケース図を書いて見た〜
  4. UMLツール 〜Star UMLを使う〜

そして、作成したクラス図は下のようなものです。

起動するメインクラスは、ProconServerクラスです。
そして、このクラスはJavaFXのパッケージにあるjavafx.application.Applicationを継承して作成します。
ここで、上のクラスを継承して実装することにより、画面表示を行うための細かい処理(Xサーバーへのアクセス及び、描画処理)を自分で作成しなくてよくなります。

つまり、作成するアプリに集中できるわけです。
その代わり、このフレームワークの使用方法を理解する必要があります。「JavaFXの〜」にあるリンクからOracleのドキュメントページに遷移できます。

自分の作成した記事は以下になります。
初心者でもわかる。。。というより作って動かして。。。とやってみるのが一番なのでその手順と実装サンプル、動かしてみたときのイメージを記載しています。

  1. JavaFX チュートリアル〜今度こそ、初めてでも大丈夫:Label〜
  2. JavaFX チュートリアル〜今度こそ、初めてでも大丈夫2:Label〜
  3. JavaFX チュートリアル〜今度こそ、初めてでも大丈夫3:Button〜

本題: 受付画面作成

本題に入ります。今回作成するのは、プロコンゲーム(プロコンサーバー)のはじめの画面、プレーヤ受付画面を作成します。
と言っても、順序立ててやって行きます。

とりあえずの見た目を作る

兎にも角にも、入力する部品(ボタンなど)がないと動かすのも、受け付けるのも設計の通りにはいかないので、ここから始めます。
俗にいうモックの作成です。

そして、作成するのに使用するのはEclipseを使用しますのでプロジェクトの作成から入ります。

  1. プロジェクトエクスプローラーを右クリックします。
  2. JavaFXプロジェクトを作成します。
  3. プロジェクト名をつけます。使用するJDKは1.8です。JShellとか使用する予定がないので。。。

作成したプロジェクトは下のような感じです。

以前追加した、シーンビルダーというプラグインが入っているので、使用します。下は操作したときの動画です。今回作成するものではありませんので。。。

そして、作成したものは、下のような見た目です。

作成したときの動画は以下になります。途中で落ちましたが(笑)とりあえずは、使用するPCのスペックでメモリ不足(だと思う)により落ちる可能性があるので、File -> Save Asなどで時々保存すると良いと思います。

今回作成したのは、プレーヤーの受付部分を1行だけ作成しました。とりあえずはプレーヤー1人の受付を実装し、うまくいくのなら他ものもの同様に作成する。。。そんな感じで行こうと思います。

今回はここら辺で。。。
でわでわ。。。

関連ページ

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 4Boolean
  5. Java Basic Level 5If 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 9Training 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 〜テストスイートの作り方〜


Java プロコンゲーム 〜設計2画面の入力フロー〜

今回からは、プロコンゲーム(プログラミングコンテスト向けゲーム)の作成を始めようと思います。

今までに。テキストRPGを作成しようと色々と調査してきましたが、どうしても自然言語処理が必要になるため一時中止にしようと思います。
しかし、今までやったことは無駄にしません、RPG風に作成します。

設計2:受付処理

参考にするアプリケーションはU-16プログラミングコンテストです。これと同様に以下のような手順でプレーヤの参加を受付ます。

  1. 画面を開き、ゲームに参加するプレーヤーの使用するポート番号と表示するIMGを画面上に表示する
  2. 参加するプレーヤーの人数が確定したらスタートボタンでゲームを開始する
  3. ゲームのマップを表示する
  4. プレーヤーの配置を行う
  5. タイマーを開始して制限ターン数を表示、カウントダウンする

まずは、Map描画

今回作成するマップはダンジョンRPGをイメージにしているので通行できない部分(迷路のような)、とか罠とか、アイディアはつきませんが、マップの難易度(レベル)を設けて、それぞれの難易度でマップの生成を行うような実装を考えております。

JavaFX

画面の表示処理にはJavaFXを使用しますので、基本的な書き方はこちらの記事を参考にしてください。
早速、JavaFXの実装に入ります。

Map作成

実装したコードでは下のように表示されました。
以前作成したコードをちょいといじって動かしました。

ポイントになるコードは下のように実装しました。

/**
 * Canvasに背景を描画する
 * @param vBox Canvasを追加する領域
 */
public void createBackGround(VBox vBox) {
    String lightGrass = "grass_light.png";
    String deepGrass = "grass_deep.png";
    String soilBasic = "soil_basic.png";
    GridPane grid = new GridPane();

    for (int j = 1; j < 5; j++) {
        for (int i = 1; i <= 5; i++) {
            grid.add(createImageLbl(lightGrass), j, i);
        }
    }

    vBox.getChildren().add(grid);
}

単純に5x5マスにイメージファイル(ラベル)を表示しているだけです。この要領でゲームのマップを作成しようと思います。
ここで、問題が1つあります。マップにより難易度、を設けるので、その難易度とマップの内容を関連付けるのにどのようなロジックで行うか?ここがポイントになります。

ちょいと頭をひねります。。。

UMLについて

以前に下のようなことを記事にしました。

  1. UML 世界を作る 〜RPGでの世界を作る場合〜
  2. UMLの書き方(読み方)〜概要とクラス図〜
  3. UMLツール Star UML〜ユースケース図を書いて見た〜
  4. UMLツール 〜Star UMLを使う〜

今回はここら辺で。。。
でわでわ。。。

関連ページ

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 4Boolean
  5. Java Basic Level 5If 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 9Training 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 〜テストスイートの作り方〜


Java プロコンゲーム 〜プログラミングコンテスト向けゲーム〜

今回からは、プロコンゲーム(プログラミングコンテスト向けゲーム)の作成を始めようと思います。

今までに。テキストRPGを作成しようと色々と調査してきましたが、どうしても自然言語処理が必要になるため一時中止にしようと思います。
しかし、今までやったことは無駄にしません、RPG風に作成します。

設計から

設計といえばUMLを使用します。
まずは、ゲームで実現したい動きのイメージを作成します。ここら辺を考えるのに時間がかかりました(笑)。

実現するイメージから入る

起業するにも、夢を実現するにも、まずは実現することを具体化します。
早い話が、以下のようなことです。

実際にどのような形でアプリ(事業 or 夢)を動かす(実現、収益を出す...etc)か?

そして、そのイメージを作るためにUMLが使えるので使用すると言うわけです。

ユースケース図

まずは、全体の流れとしてユースケース図を作成します。参考にするのは、「U-16プログラミングコンテスト」です。

自分のイメージとしては下のような形です。

以前に下のようなことを記事にしました。

  1. UML 世界を作る 〜RPGでの世界を作る場合〜
  2. UMLの書き方(読み方)〜概要とクラス図〜
  3. UMLツール Star UML〜ユースケース図を書いて見た〜
  4. UMLツール 〜Star UMLを使う〜

キーポイント

仮にも、プログラミングコンテストなので、教育的な要素が必要になります。と言うか。。。「ぶっこみたい」と思っています。

現状では以下のようなところが決まっています。

  1. プログラムを組んで動かすこと。
  2. 物事を実現するための順序を考えること

これだけです。。。

今後増えていくと思うのですが、それは次回以降に。。。

でわでわ。。。

関連ページ

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 4Boolean
  5. Java Basic Level 5If 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 9Training 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 〜テストスイートの作り方〜


Java Network 〜Javaでホームページにアクセスする仕組み〜

今回は、JavaでWebページにアクセスする処理を作るときの内容を記載します。

サンプルコードはGithubにアップしてあります。

1.ウェブにアクセス

プログラムでウェブにアクセスする部分に関して記載します。コードの説明になりますが。。。

System.out.println("*** execute ***");
String url = "https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8";
Document doc = null;
try {
    doc = Jsoup.connect(url).get();
} catch (IOException e) {
    e.printStackTrace();
}

変数の「url」にアクセスします。
処理の内容としては以下の通りです。

  1. アクセスするURLを指定します。つまり変数に代入します。
  2. そして、取得したHTMLをDocumentクラスに変換して取得します。doc = Jsoup.connect(url).get();
  3. 取得するときに例外(IOException)が出る可能性がある→メソッドの定義にthrows IOExceptionがある、のでtry chatchで囲む

2.HTMLの取得

これも同様に、コードから見ていきます。

Elements eles = doc.getElementById("toc").children();
for (int i = 0; i < eles.size(); i++) {
    Element item = eles.get(i);
    System.out.print("wholeText(): " + item.wholeText());
    System.out.println(" / text(): " + item.text());
    printIndex(item, i);
}

Jsoupのフレームワークを使うと言う部分になります。
ドキュメント(Document)クラスを中心にして取得します。

doc.getElementById("toc").children()

このコードでid="toc"と記述されたHTMLを取得します。
実際には[Wikiの「武器」ページ](https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8)から目次の部分を取得します。

具体例参照するぺーじのHTML
![](http://zenryokuservice.com/wp/wp-content/uploads/2020/03/スクリーンショット-2020-03-23-20.49.38-300x192.png)

<div id="toc" class="toc" role="navigation" aria-labelledby="mw-toc-heading"><input type="checkbox" role="button" id="toctogglecheckbox" class="toctogglecheckbox" style="display:none"><div class="toctitle" lang="ja" dir="ltr"><h2 id="mw-toc-heading">目次</h2><span class="toctogglespan"><label class="toctogglelabel" for="toctogglecheckbox"></label></span></div>

目次のタグ部分です。はじめのタグ(一番外側のタグです)を取得しています。

よくJSで以下のような実装を行いますが、それと同じです。

var tag = document.getElementById("タグのID");

取得したタグからタグの中にある子供のタグを取得します。

## タグの取得
例えば、下のようなHTMLから。。。

<div class="toctitle" lang="ja" dir="ltr"><h2 id="mw-toc-heading">目次</h2><span class="toctogglespan">
    <label class="toctogglelabel" for="toctogglecheckbox"></label></span>
</div>

以下のようなコードを実行したとします。

Document doc = Jsoup.connect(url).get();
// HTMLボディの取得
Element body = doc.body();
Elements eles = body.getElementById("toctitle");
eles.text();

と実装すると「目次」が取得できます。(間違ってたらごめんなさい。。。)大切なのは、子供のタグを取得(Elements)してElements#child()子供のタグを取得すると言うわけです。

## 結論から言うと
実装して動かしてみるのが一番ですが、サンプルコードとして。。。

Element body = doc.body();
Elements eles = body.getElementsByTag("h2");
System.out.println("size: " + eles.size());
Elements eles = doc.getElementById("toc").children();
for (int i = 0; i < eles.size(); i++) {
    Element item = eles.get(i);
    System.out.print("wholeText(): " + item.wholeText());
    System.out.println(" / text(): " + item.text());
    printIndex(item, i);
}

## 関連ページ

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 4Boolean
  5. Java Basic Level 5If 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 9Training 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 〜テストスイートの作り方〜


Java HTML解析 〜Wikipedia 武器 ページの解析3〜

前回は、目次の表示を行いました。

しかし、このままでは、インデックスがちゃんと表示されないので、インデックスをちゃんと表示できるように一工夫する必要があります。

インデックスがうまくいかない

前回のコードでは、「id=toc」のタグを取得してから中にあるタグを単純に表示するだけです。というか表示用のメソッドの記述がありませんでした。

それは、インデックスをちゃんと表示するためのメソッドを用意したためです。
対象になる部分は以下のような処理です。

// System.out.println("*** Get Content ***");
Elements eles = doc.getElementById("toc").children();
for (int i = 0; i < eles.size(); i++) {
    Element item = eles.get(i);
    printIndex(item, i);
}

「printIndex(item, i);」の部分です。
このメソッドを下のように変更すると単純にタグの中身を表示できます。
System.out.println(item.text());

インデックスの処理

結論から言うと、インデックス部分かどうかの判定をして、インデックスであれば。。。と言う処理を行ってやれば良いと言うところですが、ちょっと面倒でした。

作成した処理は以下のようなものになります。
Gitにアップしてあります

private void printIndex(Element row, int num) {
//      System.out.println("index" + num + ": " + row.text());
    if (row.childrenSize() != 0) {
        printChild(row.children());
    }
}

private void printChild(Elements eles) {
    for (Element ele: eles) {
        if (ele.childrenSize() != 0) {
            printChild(ele.children());
        } else {
            printElement(ele);
        }
    }
}
private void printElement(Element ele) {
    if (ele.text().contains(".")) {
        print(ele,"-   ", ": ");
    } else if (ele.text().matches("[0-9]{1,2}")) {
        print(ele,"", ": ");
    } else {
        if (ele.text().equals("")) {
            return;
        }
        println(ele, "", "");
    }
}
private void print(Element ele, String prefix, String safix) {
    if (safix != "") {
        System.out.print(ele.text() + safix);
    } else {
        System.out.print(prefix + ele.text());
    }
}
private void println(Element ele, String prefix, String safix) {
    if (safix != "") {
        System.out.println(ele.text() + safix);
    } else {
        System.out.println(prefix + ele.text());
    }
}

メソッド呼び出しの順番は以下のようになっています。

  1. printIndex(): タグの子供を取得
  2. printChild(): タグの子供がいる場合は再起処理、そうでない場合は文字を取得して表示
  3. printElement(): ⑴を参照
  4. print(改行なし) or println(改行あり)
⑴ 以下のような条件分岐を行う
A. 文字列に「.」を含む場合
B. 文字列が「0-9」の数字の場合
C. 上記以外の場合

それぞれに対し、下のような処理を行います。※改行しない場合

       if (safix != "") {
            System.out.print(ele.text() + safix);
        } else {
            System.out.print(prefix + ele.text());
        }

表示する文字の手前(prefix)とあと(safix)に値があればそれを表示すると言う処理を行っています。

このプログラムで、取得した値は以下のように表示されます。

*** execute ***
*** Get Content ***
目次
1: 武器のエネルギー
1.1: 運動エネルギー
1.2: 人力
1.3: 火・燃焼
1.4: 生物(兵器)
1.5: 電気
1.6: 光線
1.7: 毒・化学物質
1.8: その他
2: 武器の構造
2.1: 柄
2.2: 柄頭
2.3: 刃
2.4: 刀身・剣身
2.5: 鎖物・縄
2.6: 鉤
2.7: 暗器
2.8: 機械
3: 歴史
3.1: 石器・自然物
3.2: 金属製武器の登場
3.3: 銃の登場
3.4: 近代
3.5: 第二次大戦後
4: 日本の武器の歴史
4.1: 古代
4.2: 中世
4.3: 近世
4.4: 近代
4.5: 現代
4.6: 現在
5: 玩具としての武器
6: スポーツに用いられる武器
7: 象徴・祭器としての武器
8: 架空の武器
9: 武器の分類
10: 主な武器の種類
10.1: 刀剣類
10.2: 鈍器類
10.3: 竿状武器(ポールウェポン)
10.4: 投擲武器
10.5: 射出武器
10.5.1: 暗器・格闘武器
10.6: その他の武器
11: 脚注
12: 参考文献
13: 関連項目
14: 外部リンク

でわでわ。。。

関連ページ

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 4Boolean
  5. Java Basic Level 5If 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 9Training 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 〜テストスイートの作り方〜


Java HTML解析 〜Wikipedia 武器 ページの解析2〜

前回は、とりあえずでWikiのページ(武器)を取得する処理を実装しました。
これは、以下のような処理を行っています。

  1. 単純にURLで対象のHTMLのH2タグを取得
  2. 文字列でコンソールに表示

しかし、これでは意味がないので取得したいものを取得できるようにWikiページの構成を考えていきます。

Wikiページの中身

とりあえずは目次を取得することを考えます。
Wikiページの「目次」に関して、タグの属性に注目してみます。目次部分のHTMLをはじめの部分を抜き出してみました。

<div id="toc" class="toc" role="navigation" aria-labelledby="mw-toc-heading">
<input type="checkbox" role="button" id="toctogglecheckbox" class="toctogglecheckbox" style="display:none"><div class="toctitle" lang="ja" dir="ltr"><h2 id="mw-toc-heading">目次</h2><span class="toctogglespan">
<label class="toctogglelabel" for="toctogglecheckbox"></label></span></div>
<ul>
<li class="toclevel-1 tocsection-1"><a href="#武器のエネルギー"><span class="tocnumber">1</span> <span class="toctext">武器のエネルギー</span></a>
<ul>
<li class="toclevel-2 tocsection-2"><a href="#運動エネルギー"><span class="tocnumber">1.1</span> 

これの構成を見てみると大元(一番上)のタグのidとclassに注目してみると目次部分のHTMLにはID=「toc」とあります。
そしてその「toc」内に全ての内容が記載されているのでこれを取得すれば、目次部分が取得できます。

そして、以下のような構成で内容が記載されています。

<div id="toc" class="toc" /> => 全体のタグ
    「目次」
    toclevel-1 => トピックレベル1の項目
    toclevel-? => トピックレベル?の項目
       tocsection-? => 各セクション1〜?までの項目

なので、Javaのコードでは以下のような処理を行います。

  1. 「id=”toc"」のタグを取得
  2. それぞれの値をコンソールに出力

Jsoupを使用するとここら辺が簡単にできます。

Javaでの処理

public void execute() {
    // System.out.println("*** execute ***");
    String url = "https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8";
    Document doc = null;
    try {
        // Wikiページへアクセス、HTMLを取得する
        doc = Jsoup.connect(url).get();
    } catch (IOException e) {
        e.printStackTrace();
    }
    // System.out.println("*** Get Content ***");
    Elements eles = doc.getElementById("toc").children();
    for (int i = 0; i < eles.size(); i++) {
        Element item = eles.get(i);
        printIndex(item, i);
    }
}

これは自分が作成したものですが、以下のような処理を行っています。

  1. 「id="toc"」のタグを取得
  2. タグの子供(タグ内にあるタグ)
    <div id="toc" class="toc" role="navigation" aria-labelledby="mw-toc-heading"><input type="checkbox" role="button" id="toctogglecheckbox" class="toctogglecheckbox" style="display:none"><div class="toctitle" lang="ja" dir="ltr"><h2 id="mw-toc-heading">目次</h2><span class="toctogglespan"><label class="toctogglelabel" for="toctogglecheckbox"></label></span></div>
    <ul>
    <li class="toclevel-1 tocsection-1"><a href="#武器のエネルギー"><span class="tocnumber">1</span> <span class="toctext">武器のエネルギー</span></a>
    <ul>
    <li class="toclevel-2 tocsection-2"><a href="#運動エネルギー"><span class="tocnumber">1.1</span> <span class="toctext">運動エネルギー</span></a></li>

    上の「武器のエネルギー」などが含まれるタグを取得

  3. 取得したタグの文字列部分を取得

こんな感じの処理を行っています。

問題点

このままでは、取得したいタグの番号をつけている部分「1.1、2 ...」という数字があるので、混乱してしまいます。
本当であれば、これらは各項目のインデックスであり、項目の順番を示すものですので、これをちゃんと表示してやる必要があります。イメージとしては下のような感じです。

目次
1: 武器のエネルギー
1.1: 運動エネルギー
1.2: 人力
1.3: 火・燃焼
1.4: 生物(兵器)

これらの表示を行うために、頭をひねる必要があります。
これは次回にしようと思います。

でわでわ。。。

関連ページ

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 4Boolean
  5. Java Basic Level 5If 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 9Training 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 〜テストスイートの作り方〜


Java HTML解析 〜Wikipedia 武器 ページの解析〜

タイトルにあるページの解析を行います。解析する内容は、表示されている武器の一覧を作るための情報を抜き取るような形です。

ページの解析

HTMLはタグで、ツリー状に出来上がっているので、そこを基準にして解析します。

そして、忘れてはいけないのが「目的」です。今回の目的は、武器の一覧を作成することですので、以下のような項目を取得することを目的にしようと思います。

  1. 武器の種類(刀、鉄砲、戦車etc...)
  2. 武器を使うためのエネルギー源
  3. 現実か、架空のものか( Yes or No)
  4. その武器に対する説明、逸話など

上のような解析をしたいと思います。
駄菓子菓子!自然言語処理ができるわけでもなし、完全に、独自理論での実装になります。

ステップアッププログラミング!

何はともあれ、いきなりすごいことはできないので一歩ずつ進みます。
千里の道も一歩から、プログラミングの良いところは「理解すれば、すぐできる」というところです。ギターとか、ドラムとかのように毎日の練習は必要ありません。その代わり勉強が必要かもしれないけど(笑)

タグを取得

タグを取得します。実装したコードはこちらになります。Githubですので、ダウンロードも可能です。

public void execute() {
    System.out.println("*** execute ***");
    String url = "https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8";
    Document doc = null;
    try {
        doc = Jsoup.connect(url).get();
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.out.println("*** Get Content ***");
    Element body = doc.body();
    Elements eles = body.getElementsByTag("h2");
    System.out.println("size: " + eles.size());
    for (int i = 0; i < eles.size(); i++) {
        Element item = eles.get(i);
        System.out.print("wholeText(): " + item.wholeText());
        System.out.println(" / text(): " + item.text());
    }
}

前回作成したコードよりもスッキリしています。シンプルに「h2タグ」を取得してそれをコンソールに出力しているだけです。

HTML解析 Lv1: ポイントでデータ取得

上のコードは、h2タグを取得しているだけですが、これを、「〜タグを取って、次は〜」というように、順番に必要なデータを取得していくのも1つの手段だと思います。小難しい「人工知能」など使わなくてもいけます(笑)多分ね。。。

そして、ちょいと考えてみたのが、下のような手順です。

  1. Wikiをターゲットにして、Wikiページから調べたい情報を取得するために、Wikiページの構成を調べる
  2. 構造を理解し、必要な情報を欲しい形で取得できるようにプログラム設計を行う
  3. 実装、テスト、成果物(実行結果)を使用してテキストRPGを作る

こんな感じの実装でいけると思います。
ダメだったら、また別な方法を考えます(笑)

そんなもんでしょう(笑)

関連ページ

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 4Boolean
  5. Java Basic Level 5If 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 9Training 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 〜テストスイートの作り方〜


UML 世界を作る 〜RPGでの世界を作る場合〜

現在(2020-03-15)自分で作成しているものになりますが、テキストRPGを作成しようとしています。Java言語を使用しています。

プログラム作成(アプリ作成)である程度の規模になった場合は、設計をしてからでないと収集がつかなくなります。
違う見方をすると「面白いもの」を作ろうとしたら「設計」が必要になるということです。

RPGの世界を作る

「RPGの世界」と言ってもいろんな意味があるので具体的に、小説や脚本を作るレベルでの「世界」を作ろうということです。

世界の定義

世界、小説を作る側からすると「プロット」というらしいです。漫画や、脚本でも同様らしいです。この情報は人から聞いたものなのでこのように記載しています。

どんな世界を描くか?

自分は「プログラマ」ではないので、人(作家など)がプロットを作ることを考えて、それをプログラマ的にアプローチしていきます。

どんな風に?

ズバリ、プロットを作る工程をシステム化します。これができたらかなりすごいことになると思いますが、理想通りにいかない想定です。
理由は、どうしても、「予測」する部分が発生するので、いわゆる人工知能(AI)処理が必要になるためです。

では、どうやるか?いわゆるフレームワークを作成する想定です。つまり、1つの(RPGで使用する)ストーリーを作成するための手順を作り、必要な情報(作成するストーリーのオリジナルな部分)を入力(作成)すれば、ストーリーとして使用できるレベルにまとめるツールとして作成するという意味です。手順としては以下の通りです。

  1. 物語を構成する項目を設定していきます。(キャラクター、世界(観)、文書のストーリー)
  2. 物語の世界を描くために、世界の始まり(創世神話)を作成する、必要なければこれを入力しない(NULL)に設定する
  3. 物語の世界に存在する世界を一覧します。(書き出します)
  4. 文書によるストーリー、キャラクターを作成します。

上記の内容を作成すると、自然と物語が作成できるというものです。
ぶっちゃけた話、フレームワークまで行きませんが、執筆する作品を部分的に作成していても、1つにまとめることが可能であろうと思っています。

できるかどうかはわかりません

しかし

文章作成のシロート目線からして、骨組みだけでもある程度の形になるのであれば、十二分に作品として作成することが可能になるはずです。
つまり、より多くの人のイメージや、想像した世界観を伝えやすい形にできるのではなかろうか?と考えています。

UMLを作る

結果から記載します。

上記の図が、クラス図になります。
ここの図には、クラス名とそれに対するプロパティ(世界には国がある)を表しています。世界のクラス図です。

具体的に、上のクラス図は文章に置き換えると下のようになります。

1. 世界には神話がある
2. 世界には国がある
3. 世界には自然がある

実際に世界にはもっとたくさんのものがあり、存在しています。しかし、これらを全部クラス図に落とし込むのは至難の技です、なので階層的に表現して行きます。

・世界→国→町
・自然→気候→地形(山、川など)

クラスで表現するもの(事)は上のように階層的に表現して行くと、1つの場所に描く内容が少なくて済みます。そして、それぞれ階層化、カプセル化するので一部を変更しても、他に影響がないように修正することができます。
これが「オブジェクト指向の良いところ」になります。

UML作成関連

UMLの書き方
UMLツール Star UML〜ユースケース図を書いて見た〜
UMLツール 〜Star UMLを使う〜

Java Network 〜HTMLからデータ取得2〜

今回は、HTMLからのデータ取得を行う処理を実装しようと思います。その2回目です。

HTMLからデータ取得

HTMLからデータを取得する、つまりインターネットにアクセスして特定のウェブページを見る(閲覧)などして自分らが必要な情報を取得する、ということをプログラムにやらせようという分けです。

前提として、プログラム(PC)は人間ほど柔軟な思考ができるわけでもなく、我々人間が指示(プログラム)した通りにしか動いてくれません。なので一工夫が必要になります。

最近では、人工知能なんてものもありますので、この分野は広く開拓できそうです。
初めから複雑なことはできないので、1つずつ段階的に実装していきます。

データ取得Lv2

前回は、データの取得、HTMLを取得するという部分を実装しました。ソースはGithubにアップしてあります。
下のようなコードを実装しました。

// ⑴ URLを指定する
String targetUrl = "https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8";
// ⑵取得したHTMLをオブジェクトにするためのクラス
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
    builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}
// ⑶ 指定したURLにアクセス、HTMLの取得
try {
    URL urlCls = new URL(targetUrl);
    urlCls.openConnection();
    InputStream inp = (InputStream) urlCls.getContent();
    Document html = builder.parse(inp);
} catch(MalformedURLException e) {
    e.printStackTrace();
} catch(IOException ie) {
    ie.printStackTrace();
} catch (SAXException e) {
    e.printStackTrace();
}

ここで使用しているクラスはJDKに入っているもので「〜.jar」をダウンロードとかしなくても使用できるコードになります。

そして、あくまでもHTMLを取得するまでの処理なのでここからがHTMLの読み込み、必要なデータの取得になります。

HTMLの読み込み

早速コードを見ていきます。

    try {
        URL urlCls = new URL(targetUrl);
        // 指定のURLにアクセス(コネクションの取得)
        urlCls.openConnection();
        // HTML文書の入力ストリーム(ファイルと同じ扱いです)
        InputStream inp = (InputStream) urlCls.getContent();
        Document html = builder.parse(inp);
        // 取得したHTMLの「ulタグ」を全て取得する
        NodeList nodes = html.getElementsByTagName("ul");
        for (int i = 0; i < nodes.getLength(); i++) {
           // 子ノードを取得し再起処理を行う loopPrint(nodes.item(i).getChildNodes());
        }

    } catch(MalformedURLException e) {
        e.printStackTrace();
    } catch(IOException ie) {
        ie.printStackTrace();
    } catch (SAXException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";
}
/** 再起処理を行うメソッド */
private void loopPrint(NodeList list) {
    String emp = System.getProperty("separator") + "\t\t";
    for (int i = 0; i < list.getLength(); i++) {
        Node node = list.item(i);
        if (node.hasChildNodes()) {
            loopPrint(node.getChildNodes());
        } else {
            if ("#text".equals(node.getNodeName())) {
                System.out.println("NodeName: " + node.getNodeName() + " -> Value: "+ node.getNodeValue());
            }
        }
    }
}

上の実装では「再起処理」がポイントになります。
取得したHTMLはタグで階層状になっているので階層をどんどん下がって、次のタグへ。。。というような処理が必要になります。このような時にしようするのが「再起処理」です。

つまるところは、以下のような処理です。

  1. ulタグのはじめの部分を取得
  2. タグの子ノードの有無を確認
  3. 子持ちなら、同じメソッドを呼び出す、そうでないなら中身をコンソールに表示
  4. これをルートノードの子供の数だけ繰り返す

こんな実装をしています。しかし、ulタグを取得しているだけなので、ちょっと実用的ではありません。

まとめ

駄菓子菓子、読み込み中身を取得しても、必要なデータのみを読み込むのに、色々と処理を書かないといけないので、ライブラリを使用して実装し直すことにします。使用するライブラリはJsoupです。
でわでわ。。。



Java Network 〜HTMLからデータ取得1〜

今回は、HTMLからのデータ取得を行う処理を実装しようと思います。

HTMLからデータ取得

HTMLからデータを取得する、つまりインターネットにアクセスして特定のウェブページを見る(閲覧)などして自分らが必要な情報を取得する、ということをプログラムにやらせようという分けです。

前提として、プログラム(PC)は人間ほど柔軟な思考ができるわけでもなく、我々人間が指示(プログラム)した通りにしか動いてくれません。なので一工夫が必要になります。

最近では、人工知能なんてものもありますので、この分野は広く開拓できそうです。
初めから複雑なことはできないので、1つずつ段階的に実装していきます。

データ取得Lv1

データの取得、HTMLを取得するという部分を実装します。
結論からいうと下のようなコードになります。

// ⑴ URLを指定する
String targetUrl = "https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8";
// ⑵取得したHTMLをオブジェクトにするためのクラス
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
    builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}
// ⑶ 指定したURLにアクセス、HTMLの取得
try {
    URL urlCls = new URL(targetUrl);
    urlCls.openConnection();
    InputStream inp = (InputStream) urlCls.getContent();
    Document html = builder.parse(inp);
} catch(MalformedURLException e) {
    e.printStackTrace();
} catch(IOException ie) {
    ie.printStackTrace();
} catch (SAXException e) {
    e.printStackTrace();
}

ここで使用しているクラスはJDKに入っているもので「〜.jar」をダウンロードとかしなくても使用できるコードになります。
処理の内容としては、以下の通りになります。

⑴ URLを指定する

これは、説明するまでもないような気もしますが、ポイントになるので。。。
文字列の変数「targetUrl」に、アクセスするURLを設定します。
現状のコードでは、固定値になりますが、今後この部分を引数に変更して動的なURLにアクセスできるように変更します。

⑵取得したHTMLをオブジェクトにするためのクラス

Documentを使用して取得したHTMLから必要な情報を取得します。実際にHTMLの文字列を取得することもできますが、取得したいデータは、記載されている内容なので、タグの部分は無視したいためこのような方法を使いました。
ちなみに、これ(Documentクラス)も余計な情報をふんだんに持っているので、今後はJsoupを使用して実装する予定です。これを使うにはリンク先のJARファイルをダウンロード、ビルドパスに設定という手順を踏む必要があります。→この部分に関してはこちらの記事を参照ください。この記事ではJSONライブラリ(json-path-2.1.0.jar)を追加しています。下のような記事です。

⑶ 指定したURLにアクセス、HTMLの取得

ここまできたら、あとはメソッドを呼び出すだけです。
ちょっと注意が必要なのはURL#getContent()の返り値がObujectなので「何でも返す」というところです。当然本当はStringを返しているのにFileで受け取ろうとすればExceptionがでます。このメソッドの用途を明確にして取得するもの(HTMLやイメージファイルなど)をはっきりさせて実装する必要があります。

まとめ

今回は、HTMLを取得するのに以下のクラスを使用してやりました。

  1. URLクラス: インターネット上のコンテンツ(HTMLなど)にアクセスする
  2. Documentクラス: 取得したコンテンツをドキュメント(HTMLやXML)として扱う ※同じ名前で違う機能のものがあるので注意が必要です。
  3. [InputStream](): 読み込みよう入力ストリームです。この「ストリーム」に関してはこちらの記事を参照ください。クラスの実装例でInputStreamを使用しています。
  4. DocumentBuilderFactory: DocumentBuilderクラスを取得するためのクラスです。
  5. DocumentBuilder: Documentクラスを取得するためのクラスです。

これらのクラスを使用して、インターネット上のHTMLファイルを読み込み、コンテンツ(HTML文書)を取得、までの実装になります。こちらのGitにあるソースは、文書の読み込みも実装しています。次回は読み込み部分の処理について記載したいと思います。

でわでわ。。。