20200122のJavaに関する記事は13件です。

JConsoleがlocalで接続できないとき

知りたい情報をドストレートに射抜いてくれる日本語記事は検索しても出てこなかったので記します。

解決の助けになった記事(英語)
https://community.oracle.com/thread/1177644

現象

jconsoleなるJavaのプロセスを監視するものを使う必要が生じたので、常駐してるJavaプロセスにローカルでアクセスしにいったところ、4つあるうち1つのプロセスだけアクセスできなかった。
無題.png
ローカルなのになんで失敗するの?接続が成功しませんでした?

対処法

目的のjarファイルに監視するオプションを付与してあげるとJconsoleで監視できるようになった。
例)コマンドプロンプトでJMXで監視するオプションを付与して実行する。

コマンド(win10)
java -Dcom.sun.management.jmxremote -jar 目的のjar.jar

普段、意識することはなかったですが監視対象にするにはオプションを付ければいいのですね。
逆に成功した他のプロセスは誰かが起動時にオプション付けるようにbat組んでくれてたんでしょうね。

JMXとは?(番外編)

参照元:Oracleの公式ドキュメント いわく

「Java Management Extensions (JMX) は、Java アプリケーションをモニタおよび管理するための仕様です。 」

JMXガイド↓ まとめようと思ったけどめんどくさかった
https://docs.oracle.com/javase/jp/8/docs/technotes/guides/management/agent.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java基本文法メモ

変数と定数

宣言

/* 変数宣言 */
boolean varA; // boolean型/宣言のみ
varA = true; // 代入のみ
byte varB; // 8bit(-128~127)
short varC; // 16bit(-32768~32767)
int varD; // 32bit(約-21億~約 21億)
long varE; // 64bit(なんかいっぱい)
float varF; // 32bit浮動小数点数
double varG; // 64bit浮動小数点数
char varH; // 16ビットUnicode文字
String varI // 文字列型(参照型)

/* 定数宣言 */
static final data_type varJ = valA; // static + final修飾子

配列

固定長配列

/* 宣言 */
data_typeA[] arrayA = new data_typeA[index_max_value];
data_typeB[] arrayB = {valA, valB, valC, valD, valE};
data_typeC[] arrayC = new data_typeC[] {valF, valG, valH};
data_typeD[] arrayD;
// X arrayD = {valI, valJ, varl}
arrayD = new data_typeD[]{valI, valJ, varl}

/* arraysクラス */
Arrays.toString(arrayD); // "[valI, valJ, vall]"
Arrays.sort(arrayD);     // {vall, valJ, valI}

可変長配列(コレクション)

/* List(インターフェース) */
// X List<data_typeA> listA = new List<>();
List<data_typeA> listA =  new ArrayList<>();
List<data_typeB> listB =  new LinkedList<>();
List<data_typeC> listC =  new CopyOnWriteArrayList<>();
List<data_typeD> listD = Arrays.asList(valA, valB); // 読専
listD.add(valD);         // 末尾に追加
listD.add(indexA, valE); // 途中に挿入
listD.set(indexA, valF); // 置換
listD.get(indexA);       // 値の取得
listD.indexOf(valF);     // 位置の取得
listD.size();            // 要素数の取得
listD.contains(valF);    // 存在の確認
listD.remove(valF);      // 削除

/* --- 以下Listの実装クラス ------------------------------- */
/* ArrayList .. 検索に強い */
// ArrayListにしか存在しないメソッドを使う場合は下記で宣言(以下同様)
ArrayList<data_typeE> listE =  new ArrayList<>();
ArrayList listF = (ArrayList<data_typeE>)listE.clone(); // コピー

/* LinkedList .. 追加/削除に強い */
LinkedList<data_typeG> listG =  new LinkedList<>();
listG.push(); // 先頭に追加
listG.pop();  // 先頭から削除

/* CopyOnWriteArrayList .. 同期化不要/マルチスレッドに強い */
CopyOnWriteArrayList<data_typeH> listH =  new CopyOnWriteArrayList<>();

連想配列(コレクション)

/* Map(インターフェース) */
// X Map<Integer, data_typeA> mapA = new Map<>();
Map<Integer, data_typeA> mapA = new HashMap<>();
Map<Integer, data_typeB> mapB = new LinkedHashMap<>();
Map<Integer, data_typeC> mapC = new ConcurrentHashMap<>();
Map<Integer, data_typeD> mapD = new TreeMap<>();

mapA.put(keyA, valA);     // 末尾に追加
mapA.put(keyA, valB);     // 置換
mapA.get(keyA);           // 値の取得
mapA.size();              // 要素数の取得
mapA.containsKey(keyA);   // キーの検索
mapA.containsValue(valB); // 値の検索
mapA.remove(keyA);        // 削除

/* --- 以下Mapの実装クラス ------------------------------- */
/* HashMap ... 検索に強い */
HashMap<Integer, data_typeE> mapE = new HashMap<>();

/* LinkedHashMap .. 挿入した順番を保持 */
LinkedHashMap<Integer, data_typeF> mapF = new LinkedHashMap<>();

/* ConcurrentHashMap .. 同期化不要/マルチスレッドに強い */
ConcurrentHashMap<Integer, data_typeG> mapG = new ConcurrentHashMap<>();

/* TreeMap .. キーの大小を意識した部分集合 */
TreeMap<Integer, data_typeH> mapH = new TreeMap<>();

集合(コレクション)

// X Set<data_typeA> setA =  new Set<>();
Set<data_typeA> setA =  new HashSet<>();
Set<data_typeB> setB =  new LinkedHashSet<>();
Set<data_typeC> setC =  new TreeSet<>();
Set<data_typeD> setD =  new HashSet<>(ListA); // List->Set

setD.add(valA);      // 値の追加/上書き
setD.remove(valB);   // 値の削除
setD.size();         // 要素数の取得
setD.contains(valC); // 値の検索

/* --- 以下Setの実装クラス ------------------------------- */
/* HashSet .. 検索に強い */
HashSet<data_typeA> setA =  new HashSet<>();

/* LinkedHashSet .. 追加/削除に強い */
LinkedHashSet<data_typeB> setB =  new LinkedHashSet<>();

/* TreeSet .. キーの大小を意識した部分集合 */
TreeSet<data_typeC> setC =  new TreeSet<>();

ほか

Queueとその実装型 ... FIFO
Queue<data_typeA> queueA = new ArrayBlockingQueue<>(intA);
queueA.offer(valA); // 追加
queueA.peek();      // 出力
queueA.poll();      // 出力/削除
Dequeとその実装型 ... Queueの拡張型。両端から追加削除可能。
// LinkedListはListとDequeの実装型
Deque<data_typeA> dequeA = new LinkedList<>();
dequeA.offerFirst(valA); // 先頭に値の追加
dequeA.offerLast(valB);  // 末尾に値の追加
dequeA.peekFirst(valC);  // 先頭の値の出力
dequeA.peekLast(valD);   // 末尾の値の出力
dequeA.pollFirst(valE);  // 先頭の値の出力/削除
dequeA.pollLast(valF);   // 末尾の値の出力/削除

参考:[Java] スタックキューのメモ

分岐

If文

if (conditionA){ 
    statementA // 文、処理
} else if (conditionB) {
    statementB // 文、処理
} else if (!conditionC) {
    statementC // 文、処理
} else {
    statementD // 文、処理
}

switch文

switch (varA) {
    case valA:     // varA = valA の場合
        statementA // 文、処理
        // break文 ... コードブロックの実行を途中終了
        break;
    case valB:
    case valC:     // varA = valB, valC の場合
        statementB // 文、処理
        break;
    case default   // varA = valA,valB,valC 以外の場合
        statementC // 文、処理
        break;
}

反復

For文

/* 指定した回数文繰り返す */
for (data_type varA = valA; varA <= valB; valC++) {
    statementA // 文、処理
}

/* 配列コレクションからの繰り返し */
for (data_type varB : collectionA) {
    statementB // 文、処理
}

/* forEachとラムダ式の組み合わせ(collectionBの要素を出力する) */
collectionB.forEach(varC -> System.out.println(varC)); 

While文(Do-While文)

/* 条件式がTrueの間繰り返す */
while (conditionA) {
    statementA // 文、処理
} 

do { 
    statementB // 文、処理 
} while (conditionB);

/* 条件式がTrueになるまで繰り返す場合 */
while (!conditionC){
    statementC // 文、処理
}

do { 
    statementD // 文、処理 
} while (conditionD);

Break文とContinue文

while (conditionA) {
    switch(varA){
        case valA: // statementA,Bを通る
            statementA // 文、処理
        case valB: // statementBのみ通る
            statementB // 文、処理
            /* break文 ... コードブロックの実行を途中終了 */
            break;
        default:
            statementC // 文、処理
            /* continue文 ... 実行制御を次の反復処理に移す */
            continue;
    } 
}

例外処理 ... エラーをチェックする

/* try ... 対象処理 */
try{
    statementA
/* catch ... 例外処理 */
} catch (xxxException e){
    e.printStackTrace();    // 例外メッセージ(基本これ)
    e.getClass().getName(); // 例外クラス名のみ
    e.getMessage();         // 例外詳細メッセージのみ
    StackTraceElement[] ste = e.getStackTrace(); // 例外の一覧
/* finally ... try/catchのあと行う処理 */
} finally{
    statementB // 文、処理
}
/* 例外の強制的な生成 */
throw new ExceptionClassA();

クラス

クラスの基本

package scope1.packageA;
import scopeB.libC;

public class ClassA{
    /* 始めに呼ばれるメソッド */
    // mainの引数パターンは他に(String... args), (String args[])
    public static void main(String[] args){
        ClassB instanceA = new ClassB("naiyo");
        System.out.println(instanceA.getMethodA());
    }
}

private class ClassB{
    private data_type _fieldA;    
    /* コンストラクタ */
    Class2(){
        this._fieldA = "";
    }
    Class2(data_type1 varA){
        this._fieldA = varA;
    }
    /* セッター */
    data_type setMethodA(data_type varB){
        this._fieldA = varB; // 引数とフィールド名は同じ
    }
    /* ゲッター */
    data_type getMethodA(){
        return this._fieldA;
    }
}

修飾子

/* アクセス修飾子 */
private class1{}         // 同クラスからのみアクセスできる
protected class class1{} // 同クラスとサブクラスからのみ
class class1{}           // 同パッケージからのみ
public class class1{}    // 全てのクラスから

/* 他修飾子 */
abstract      // 抽象クラス、抽象メソッド
static        // インスタンス化の必要がない
final         // 上書きされない(定数もこれ)
synchronized  // 複数プロセス時排他制御を行う
native        // ネイティブクラス、ネイティブメソッド
strictfp      // IEEE754に則って浮動小数点数を演算処理する
transient     // シリアライズの対象から除外
volatile      // フィールド値のキャッシュを抑制する
const         // 多言語の定数修飾子、Javaでは使用せず

/* アノテーション */
@Deprecated       // 非推奨であることを明示
@Override         // 上書きしていることを明示
@SuppressWarning  // 警告表示を抑制

/* 順番 */
@Annotation 
public protected private
abstract static final synchronized native strictfp

継承(多態性)

継承の基本

/* 親クラス */
protected class ClassA{
    protected data_type fieldA;
    protected Class1(data_type varA){ // 親クラスのコンストラクタ
        this.fieldA = varA;
    }  
    protected void methodA(data_type varB){ // 親クラスのメソッド
        statementA
    } 
}

/* 子クラス */
public class ClassB extends ClassA{
    public ClassB(data_type varC){ // 子クラスのコンストラクタ
        super(varC); // 親クラスのコンストラクタを呼び出す
    }
    @Override // オーバーライド修飾子(前述)
    public void methodA(data_type var2){
        statementB // 文、処理
    }
}

抽象クラス ... 雛型、共通の処理を実装したい

/* 抽象クラス */
protected abstract class ClassA{
    protected data_type fieldA;
    public Class1(data_type varA){
        this.fieldA = varA
    }
    // オーバーライドされる前提のメソッド(抽象メソッド)
    public abstract void methodA(data_type varB); 
}
/* 子クラス */
protected abstract class ClassB{
    @Override
    public abstract void methodA(data_type varB){
        statementA // 文、処理
    }
}

インターフェース ... 抽象メソッドと定数しか定義ができない(原則)

/* インターフェース */
public interface InterfaceA{
    /* 基本的に以下のように、型の羅列を行う */
    data_type CONST_A = "CONST_A"; // public static finalは省略可
    data_type methodA(data_type varA);

    /* ---- 以下Java8から追加。個人的に非推奨(複雑なため) ---- */
    // defaultメソッド ... 抽象クラスの通常メソッドのようなもの
    default void methodB(data_type varB){
        statementA // 文、処理
    }
    // staticメソッド ... インスタンスなしで呼び出し可
    public static methodC(data_type varC){
        statementB // 文、処理
    }
}

/* 子クラス */
public class ClassB extends InterfaceA{
    public static void main(String[] args){     
        @Override
        public static methodB(data_type varB){
            // X ClassB.methodC
            // X @Override methodC
            InterfaceA.methodC(Interface1.CONST_A);
        }
}

色々なクラス

ジェネリックスクラス(テンプレート)

public class GenericClassA<TYPE>{
    private TYPE _fieldA;
    GenericClassA(TYPE varA){
        this._fieldA = varA;
    }
    TYPE setMethodA(TYPE varB){
        this._fieldA = varB;
    }
    TYPE getMethodA(){
        return this._fieldA;
    }
}

/* ジェネリックメソッド */
public class ClassA{
    public static <TYPE> ArrayList<TYPE> GenericMethodA(TYPE val1){
    }
}

インナークラス

public class ClassA{
    /* staticメンバークラス ... */
    static class MemberClassA{}

    /* 非staticメンバークラス ... */
    class MemberClassB{}

    public static void main(String[] args) {
        /* ローカルクラス ... */
        class LocalClassC{
            public void localMethod(){}
        }
        LocalClassC localClassC = new LocalClassC();
        localClassC.localMethod();

        /* 匿名クラス ... 定義とインスタンス化を同時にできる */
        // ArrayList型を継承した匿名クラス
        List<data_typeC> list = new ArrayList<data_typeC>() {
            public data_typeC method3() {
                statements // 文、処理
            }
        };
    }
}

public class ClassB{
    public static void main(String[] args){
        // staticメンバークラス呼び出し
        ClassA.MemberClassA cAcA = new ClassA.MemberClassA();
        // 非staticメンバークラス呼び出し
        ClassA cA = new ClassA();
        ClassA.MemberClassB cAcB = cA.new MemberClassB();
    }
}

モジュール(Java9)

module-info.java
module moduleA{ // module-info.javaというファイルに記載。
    export moduleA.lib; // 本モジュール内のライブラリを公開する
    requires moduleB;   // 本モジュールが必要とするモジュールを記載する
}

参考:モジュールシステムを学ぶ / Java Modules

enum(列挙型)
public enum EnumA{
    /* 基本 */
    elmA, elmB;
    /* 応用 - メンバ、変数、メソッドの追加 */
    elmC(0), elmD(1);
    private final int fieldA;
    private setElmA(int varA){
        this.fieldA = varA;
    }
    public int getVal(){
        return fieldA;
    }
    public void outVal(){ // values() .. 全enum要素のリスト
        for (Enum2 enums : values()) { 
            System.out.println(enums.getVal()); // 0, 1
        }
    }
}

ラムダ式(Java8)

書き方

/* (args) -> { statements // 文、処理 } */
// 一つの場合は args -> statements
Collections.sort(listA, (a,b) -> {return b - a;});

メソッド参照

/* スタティックメソッド(class::method)*/
// list.forEach(i -> String.toString(i)));
list.forEach(String::toString);

/* メンバーメソッド(this::method) */
// list.forEach(i -> this.toString(i)));
list.forEach(this::toString);

/* ジェネリックメソッド(class::<type> method) */
// list.forEach(i -> ClassA<typeA> methodA(i);));
list.forEach(ClassA::<typeA> methodA);

/* インスタンスメソッド(object::method) */
// list.forEach(i -> System.out.print(i));
list.forEach(System.out::print);

/* コンストラクタ(class::new) */
ClassA instanceA = classA::new;

関数型インターフェース
... 抽象メソッド1つしか定義されていない等、条件を満たすとラムダ式やメソッド参照の代入先になれる

@FunctionalInterface
public interface FuncInterfaceA {
    public data_typeA method(data_typeA varA);
}

/* メジャーな標準の関数型インターフェース */
// Function.apply()    値を変換する
Function<String, Integer> func = x -> x.length();
System.out.println(func.apply("mojisu")); // 6

// Predicate.test()    判定を行う
Predicate<Integer> condA = i -> i != 0 ;
Predicate<Integer> condB = i -> i % 2 == 0 ;
condA.test(2);            // true
condA.negate().test(1);   // false (negate..否定)
condA.or(condB).test(1);  // true  (or判定)
condA.and(condB).test(1); // false (and判定)

// Supplier.get()      引数なしで値を返す
Supplier nowTime = () ->  LocalDateTime.now();
System.out.println(nowTime.get()); // 2020-01-22 12:34:56

// Consumer.accept()   引数を元に処理 
Consumer<String> printA = str -> {
    System.out.println("printA: " + str);
}
Consumer<String> printA = str -> {
    System.out.println("printB: " + str);
}
Consumer<String> printAll = printA.andThen(printB); // 結合する
printAll.accept("" + System.currentTimeMillis());

参考:Java8のラムダ式を理解する / Java関数型インターフェース

ストリームAPI(Java8)

// Streamを生成
Stream<data_typeA> streamA = listA.stream(); // stream()をつける
IntStream intStreamA = IntStream.range(1,5); // 数値からStreamを作成
// 中間操作
streamA.filter(p -> p.length() > 5); // 絞り込む
streamA.map(p -> "[" + p + "]"); // 置き換える
// 終端操作
List<data_typeB> listB = streamA.collect(Collectors.toList()); // 変換
// 出力
listB.forEach(System.out::println);

/* ワンライナー */
listA.stream()
    .filter(p -> p.length() > 5)
    .map(p -> "[" + p + "]")
    .collect(Collectors.toList())
    .forEach(System.out::println);

中間操作メソッド

メソッド 処理内容
map 要素を別の値に置き換える .map(s-> s.getMethod())
flatmap 要素のStreamを結合する .flatmap(s -> s2.stream())
filter 合致した要素を絞り込む .filter(s -> s.equals(1)
limit 指定した件数に絞り込む .limit(2)
distinct ユニークな要素のみに絞り込む .distinct()
sorted 要素を並び替える .sorted((s1,s2) -> s2-s1)
range 末尾の値を含まず数列を作る IntStream.range(1,5)
rangeClosed 末尾の値を含み数列を作る IntStream.rangeClosed(1,5)

終端操作メソッド

メソッド 処理内容
forEach 繰り返し処理をする .forEach(System.out::println);
collect 結果を作成する .collect(Collectors.toList());
toArray 配列に変換する .toArray(String[]::new);
reduce 値を集約する .reduce((val1,val2) -> val1.add(val2));
toList Listにして返す .collect(Collectors.toList());
toSet Setにして返す .collect(Collectors.toSet());
joining 区切り文字で結合する .collect(Collectors.joining(","));
groupingBy 要素をグループ分けする .collect(Collectors.groupingBy(s -> s.length()));

※ あくまでメモなので、間違いがあるかもしれないですがご了承ください

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アルゴリズム 体操17

Rotate a Linked List

説明

単一リンクリストのヘッドノードと整数 nを指定すると、リンクリストを n回転させるアルゴリズム体操。

以下、2つの例があります。引数として渡されたリンクリストと整数 n = 2回転後の出力です。

n の値は、リンクリストの長さよりも大きくなる可能性があることに注意してください。
Screen Shot 2020-01-22 at 5.20.32.png

n = -2の時、
Screen Shot 2020-01-22 at 5.20.53.png

Solution

Runtime Complexity O(n)

n は リンクリストの長さです。

Memory Complexity O(1)

新しくデータ構造を使う必要はありません。ポインタのみ。

  1. まず、リンクリストの長さを見つけます。
  2. nが負の場合、またはnがリンクリストの長さよりも大きい場合、リンクリストの末尾で必要な回転数に合わせて調整します。 調整された数値は常に整数 N です(0 <= N <n)。調整された回転数が0の場合、ヘッドポインターを返すだけです。これは、回転が必要なかったことを意味します。
  3. リンクリストの最後のノードからn番目の 'x' ノードを見つけます。基本的に長さ「n-N」でノードxに到達します。このノードの前のノードの次のポインターは リストの末尾のノードになるため、NULLを指すように更新する必要があります。
  4. x から、リンクリストの最後のノードに移動します。最後のノードの次のポインターを、ヘッドノードに更新させます。
  5. 新しいヘッドノードとして new_head を作成します。 new_head は、n回の回転を実行した後のリンクリストの先頭になります。

『百聞は一見にしかず』ということで、上のアルゴリズムでn = 2の上記のリンクリストを回転させてみましょう。
Screen Shot 2020-01-22 at 5.37.14.png
Screen Shot 2020-01-22 at 5.37.29.png
Screen Shot 2020-01-22 at 5.37.44.png
Screen Shot 2020-01-22 at 5.37.57.png
Screen Shot 2020-01-22 at 5.38.11.png
Screen Shot 2020-01-22 at 5.38.23.png

実装

RotateList.java
class RotateList{

  private int getListSize(LinkedListNode head) {
    LinkedListNode curr = head;
    int listSize = 0;

    while (curr != null) {
       listSize++;
       curr = curr.next;
     }
     return listSize;
  }

  private int adjustRotatationsNeeded(int n, int length) {
    return n < 0 ? length - (n * -1) % length : n % length;
  }

   public LinkedListNode rotate_list(LinkedListNode head, int n) {

     int listSize = 0;
     listSize = getListSize(head);

     n = adjustRotatationsNeeded(n, listSize);

     if (n == 0) {
       return head;
     }

    // Find the startNode of rotated list.
    // If we have 1,2,3,4,5 where n = 2,
    // 4 is the start of rotated list

     LinkedListNode temp = head;
     int rotationsCount = listSize - n - 1;
     while(rotationsCount > 0) {
       temp = temp.next;
       rotationsCount--;
     }

     LinkedListNode new_head = temp.next;
     temp.next = null;

     LinkedListNode tail = new_head;
     while (tail.next != null) {
       tail = tail.next;
     }

     tail.next = head;
     head = new_head;

    return new_head;
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【eclipse/github】eclipseで作ったプロジェクトをgithubで共有しよう 初学者用

eclipseって?

統合開発環境(IDE)のひとつ
エディタとしてソースコードを記述できるのはもちろんのこと、サーバーソフトを内包していてより本番に近い形でプログラムを実行したりと、とてもすごいヤツ

githubって?

githubはこちら
ここでは説明しないので、各自調べましょう(出だしから投げやり)

この記事の前提

  • githubで空のリポジトリを作っている(作り方はこちら
  • eclipseをインストールしている(この記事ではJava用のeclipseを使います)

では、この記事の目的であるeclipseで作ったプロジェクトをgithubにアップロードしていきましょう

eclipseで作ったプロジェクトをgithubで共有しよう

まずは、アップロードするためのプロジェクトを作成していく
1. ファイル→新規→その他をクリック

git_eclipse00.png

  1. Web→動的Webプロジェクト→次へをクリック
git_eclipse01.png

  1. プロジェクト名に「GitTest」と入力(好きな名前でよい)
  2. 完了をクリック
git_eclipse02.png

  1. 作ったプロジェクトを右クリック
  2. チーム→プロジェクトの共有をクリック
git_eclipse03.png

1.Git→次へをクリック

git_eclipse04.png

  1. プロジェクトの親フォルダー内のリポジトリーを使用または作成にチェックを入れる
git_eclipse05.png

  1. 「GitTest」をクリック
  2. リポジトリーの作成をクリック
  3. 完了をクリック
git_eclipse06.png

  1. 「GitTest」を右クリック
  2. チーム→コミットをクリック

git_eclipse07.png


  1. 緑色の++マークをクリック
  2. コミットメッセージに「1」を入力(何でもよい)
  3. コミットおよびプッシュをクリック
git_eclipse08.png

  1. URIにコピーしてきたクローンURLを入力(こっちの記事のおまけ参照
  2. githubのユーザーIDとパスワードを入力
  3. 次へをクリック
git_eclipse09.png

  1. 次へをクリック
git_eclipse10.png

  1. プッシュの予想結果が拒否になっていることを確認する
  2. 完了をクリック
git_eclipse11.png

  1. プッシュ結果が拒否であることを確認する
  2. 閉じるをクリック
git_eclipse12.png

拒否された理由を無くそう

プッシュを拒否されたため、githubのリポジトリ内を確認してもデータがアップロードされていません
調べていても、ここを突破する方法が記載されていないことが多いので、続けてやり方を記載していきます

  1. 「GitTest」を右クリック
  2. チーム→プルをクリック
git_eclipse13.png

  1. 閉じるをクリック
git_eclipse14.png

  1. 「GitTest」を右クリック
  2. チーム→ブランチのプッシュをクリック
git_eclipse15.png

  1. プレビューをクリック
git_eclipse16.png

  1. プッシュの予想結果が拒否ではないことを確認する
  2. プッシュをクリック
git_eclipse17.png

  1. プッシュ結果が拒否ではないことを確認する
  2. 閉じるをクリック
git_eclipse18.png

  1. githubにサインインして、無事にアップロードされているかを確認する
  2. 確認できたらgithubに共有完了
git_eclipse19.png

コミット、プッシュ、プルって?

  • コミットとは、ローカルPCのリポジトリにデータを保存すること。ゲームでいうと本体へのセーブ機能
  • プッシュとは、インターネット上にあるgithubに対してローカルPCのリポジトリをアップロードすること。ゲームでいうとクラウドセーブの送信
  • プルとは、インターネット上にあるgithubに保存したリポジトリをダウンロードすること。ゲームでいうとクラウドセーブの受信

なんで最初のプッシュが拒否されたの?

簡潔にいうと、データの整合性を取るため
最初にプッシュを行った段階ではgithubの空のリポジトリの状態を受信しておらず、そのままプッシュを行うとデータを全部上書きしてしまう恐れがあるため、拒否された
プルしてgithub上のリポジトリの状態を受信することでリポジトリと自分が作ったデータとの整合性が取れ、アップロードが通るようになった

本来のやり方

空のリポジトリを作る時にcreate new fileをせず、作ったままにこの手順を実行すれば最初のプッシュが拒否されたりはしません(新しいファイルを作らなければリポジトリを操作した形跡がないので上書き保存しても問題ない)
しかし、2台目以降のPCで共有を行う場合や、うっかりファイルを作ったりなんだりしてしまったがために3日くらい詰まっていた初心者がいた為、この記事を書くに至った

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaでNumer0nの対戦ゲームを作ってみた

JavaでNumer0nの対戦ゲームを作ってみた

はじめに

今回、大学の授業でJavaでサーバ・クライアント間の通信を介した何かを作るという課題が出たので、高校生の頃、授業中によくやっていたNumer0nのゲームを作ってみようと思った。
高校生の頃、Numer0nのゲームにはまりすぎて、1手目で〇EAT〇BITEになる確率を手計算で求めて楽しんでた気がする...

この記事を読んでくださっている方は、Numer0nの基本的なルールは知っていると思うのでそこのところは割愛させていただきます。
ヌメロンWikipedia

開発環境

Java:version 7
Eclipse: Juno 4.2
OS: windows10

開発方針

今回のシステムで実装したいことは、
1. サーバ・クライアント間の通信を行い、複数のクライアントが同時にアクセスでき、ルームを作成し、対戦ができる
2. それなりに強いコンピュータ対戦もできるようにする(アルゴリズムの実装)
3. 入力ミスや数値の重複などに対応する
4. ターン制のゲームなので入力を交互に受け取るようにする

コード

コードをすべて載せると長くなってしまうので、今回はサーバ側の送受信を担当するChannelクラスと、コンピュータのアルゴリズムを実装したNumer0nAIクラスのみ掲載します。すべてのクラスと発表資料(パワポ)はGitHubに載せてあるのでよかったら見ていってください!pythonのほうでもNumeronAIを実装しているのでpythonよく使う人はそちらもどうぞ!
Javaで作るNumer0n(GitHub)
pythonのNumer0nAI(GitHub)

Channelクラスについて

クライアントからの入力を確認するとサーバがChannelを生成し、Channelとクライアントがやり取りをします。そのおかげでクライアントに意図しない例外が発生しても、おおもとのサーバはダウンしないので他のクライアントの接続は保たれます。

Channel.java
package server;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Channel extends Thread {
    JUDGE judge = new JUDGE();
    Server server;
    Socket socket = null;
    BufferedReader input;
    OutputStreamWriter output;
    String handle;
    String playertype;
    String roomnumber;
    String mynumber;
    String tekinumber;
    boolean turn;

    String ex = "926";//AIの最初の予測値
    String ca ="0123456789";//candidate number 最初は0~9まで
    String ex_number;
    List<String> old_list = new ArrayList<>();

    final char controlChar = (char)05;
    final char separateChar = (char)06;

    Channel(Socket s,Server cs){
        this.server = cs;
        this.socket = s;
        this.start();
    }

    synchronized void write(String s){
        try{
            output.write(s + "\r\n");
            output.flush();
        }catch(IOException e){
            System.out.println("Write Err");
            close();
        }
    }

    public void run(){
        List<String> s_list = new ArrayList<>();//クライアントからの入力を受け取り、ためておくリスト
        String s;
        String opponent = null;
        try{
            input = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));
            output = new OutputStreamWriter(socket.getOutputStream());
            write("# Welcome to Numr0n Game");
            write("# Please input your name");
            handle = input.readLine();
            System.out.println("new user: "+ handle);
            while(true){//HOST or GUEST入力待ち
                write("INPUT YOUR TYPE(HOST or GUEST or AI)");
                playertype = input.readLine();
                if(playertype.equals("HOST")){
                    Random rnd = new Random();
                    s = String.valueOf(rnd.nextInt(100)+100);
                    write("[HOST]ルーム番号: "+s);
                    break;
                }else if(playertype.equals("GUEST")){
                    write("[GUEST]ルーム番号を入力してください");
                    s = input.readLine();
                    write("[GUEST]ルーム番号: "+s);
                    break;
                }else if(playertype.equals("AI")){
                    write("[vs AIモード]");
                    Random rnd = new Random();
                    s = String.valueOf(rnd.nextInt(100)+100);
                    write("[HOST]ルーム番号: "+s);
                    break;
                }else{
                    write("ルーム番号入力でエラー");
                }
            }

            roomnumber  = s;    //roomnumberの決定
            System.out.println(roomnumber);
            write("対戦相手待ち");

            if(playertype.equals("AI")){
                //AIとの対戦
                write("自分の数字を決めてください(*3桁の数値*0~9まで*数字の被りなし)");

                boolean firstnum = false;
                while(firstnum == false){//最初の自分の数字が上記の条件を満たしているか
                    mynumber = input.readLine();
                    firstnum = judge.isNumber(mynumber);
                }
                write("自分の数字: "+ mynumber);
                write(handle + "からスタートです");
                tekinumber="864";
                NumeronAI numeron = new NumeronAI();
                while(true){
                    //ゲームスタート
                    boolean finish = false;

                    s = input.readLine();

                    if(s == null){
                        close();
                    }else{
                        System.out.println(s);
                        boolean numsuccess = judge.isNumber(s);//数字が定義内
                        if (numsuccess) {
                            JUDGE eatbite = judge.EatBite(s, tekinumber);
                            finish = judge.Finish(eatbite.eat);//3eatになったかどうか
                            write("["+ s +"] eat: " +String.valueOf(eatbite.eat) +" bite: "+ String.valueOf(eatbite.bite));

                            //ここからAIのターン
                            JUDGE AIeatbite = judge.EatBite(ex, mynumber);

                            NumeronAI squeeze = numeron.Squeeze(AIeatbite.eat,AIeatbite.bite,ex,ca,old_list);
                            if(squeeze.new_can_list.size()<300){
                                //System.out.println(Arrays.toString(squeeze.new_can_list.toArray()));
                                //System.out.println(squeeze.can_num);
                                ex_number = numeron.choice(squeeze.new_can_list,squeeze.can_num);
                            }else{
                                Random rnd = new Random();
                                int index = rnd.nextInt(100);
                                ex_number = squeeze.new_can_list.get(index);
                            }
                            old_list = new ArrayList<>(squeeze.new_can_list);
                            //System.out.println("残り候補数: " + String.valueOf(old_list.size()));
                            write("AIの予測値:" + ex + "        [残り候補数: " + String.valueOf(old_list.size())+"個]");
                            //System.out.println("AIの予測値: "+ ex);
                            if(mynumber.equals(ex)){
                                write("#################you lose#################");
                            }
                            ex = ex_number;

                                //ここまでがAIのターン
                        } else {
                            write(" did not send such a number");
                        }
                    }
                    if(finish){
                        write("#################you win#################");
                    }
                }

            }else{//vs人間
                while(opponent == null){//対戦相手待ち
                    opponent = server.findopponent(handle,roomnumber);
                }
                //write("対戦相手が決まりました");
                write("自分の数字を決めてください(*3桁の数値*0~9まで*数字の被りなし)");

                boolean firstnum = false;
                while(firstnum == false){//最初の自分の数字が上記の条件を満たしているか
                    mynumber = input.readLine();
                    firstnum = judge.isNumber(mynumber);
                }
                write("自分の数字: "+ mynumber);

                while(tekinumber == null){//敵の数値を取得するまで待つ
                    tekinumber = server.findopponentnumber(handle, roomnumber);
                }

                if(playertype.equals("HOST")){
                    turn = true;
                }else{
                    turn =false;
                }

                write("HOSTプレイヤーからスタートです");
                while(true){
                    //ゲームスタート
                    boolean finish = false;
                    while(true){
                        //ターンの確認
                        s_list.add(input.readLine());//入力を入れておく
                        turn = server.isTurn(handle);//turnの確認
                        if(turn == true){
                            break;
                        }
                    }

                    s = s_list.get(s_list.size()-1);
                    s_list.clear();

                    if(s == null){
                        close();
                    }else{
                        System.out.println(s);
                        boolean numsuccess = judge.isNumber(s);//数字が定義内
                        if (numsuccess) {
                            //write("judge ok");
                            boolean connectsuccess = server.singleSend(opponent,"[相手の予測] "+s);//相手がいる
                            if(connectsuccess){
                                //write("相手が存在する");
                                JUDGE eatbite = judge.EatBite(s, tekinumber);
                                finish = judge.Finish(eatbite.eat);//3eatになったかどうか
                                write("     [自分の予測]"+ s +" eat: " +String.valueOf(eatbite.eat) +" bite: "+ String.valueOf(eatbite.bite));
                                server.ChangeTurn(handle, opponent);//ターンの切り替え
                            }else{
                                write("did not find opponent");
                            }
                        } else {
                            write(" did not send such a number");
                        }


                        }
                    if(finish){
                        write("#################you win#################");
                        server.singleSend(opponent, "#################you lose#################");
                    }

                    }
            }



        }catch(IOException e){
            System.out.println("Exception occurs in Channel: "+handle);
        }
    }
    public void close(){
        try{
            input.close();
            output.close();
            socket.close();
            socket = null;
            //server.broadcast("回線切断 : " + handle);
        }catch(IOException e){
            System.out.println("Close Err");
        }
    }



}

NumeronAIクラスについて

NumeronAIクラスはコンピュータの予測部分を実装したクラス。
予測には、得られたEAT-BITE情報から考えられる候補を絞るSqueezeメソッドと、その候補の中から、良さそうな手を選ぶChoiceメソッド、良さそうな手を計算するcount_candメソッドからなります。良さそうな手とは、ある手を選んだ時に、返ってくるすべてのEAT-BITEの組み合わせから期待正解候補数が最も少ないものとしています。詳しくはnumer0nの必勝法を考えるを見てみてください。この理論に近いものを実装してます!
ちなみに平均コール数は5か6ぐらいだと思います(体感)。

NumeronAI.java
package server;

import java.util.ArrayList;
import java.util.List;

public class NumeronAI {
    List<String> new_can_list = new ArrayList<>();//candidate list
    String can_num;//candidate number


    //考えられる候補数に絞る
    public NumeronAI Squeeze(int eat,int bite,String pred_num,String ca_num,List<String> old_list){
        NumeronAI squeeze = new NumeronAI();
        List<String> can_list = new ArrayList<>();
        List<String> li = new ArrayList<>();

        if(eat == 0 && bite == 0){
            //System.out.println("--------" + String.valueOf(ca_num.length()));
            for(int i = 0; i<ca_num.length();i++){
                if(ca_num.charAt(i) != pred_num.charAt(0) && ca_num.charAt(i) != pred_num.charAt(1) && ca_num.charAt(i) != pred_num.charAt(2)){
                    li.add(String.valueOf(ca_num.charAt(i)));
                }
            }
            ca_num ="";
            StringBuilder builder = new StringBuilder();
            for(String num : li){
                builder.append(num);
            }
            ca_num = builder.substring(0,builder.length());

            for(int i = 0;i<ca_num.length();i++){
                for(int j = 0;j<ca_num.length();j++){
                    for(int k = 0;k<ca_num.length();k++){
                        if(ca_num.charAt(i)!=ca_num.charAt(j) && ca_num.charAt(i)!=ca_num.charAt(k) && ca_num.charAt(j)!=ca_num.charAt(k)){
                            can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(ca_num.charAt(k)));
                        }
                    }
                }
            }
        }else if(eat ==0 && bite ==1){
            for(int i = 0;i<ca_num.length();i++){
                for(int j = 0;j<ca_num.length();j++){
                    if(ca_num.charAt(i) != ca_num.charAt(j) && ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
                        can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(j)));
                        can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(pred_num.charAt(0)));
                        can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j)));
                        can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(pred_num.charAt(1)));
                        can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j)));
                        can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(j)));
                    }

                }
            }
        }else if(eat ==0 && bite ==2){
            for(int i = 0;i<ca_num.length();i++){
                if(ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(1)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1)));
                    can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i)));
                    can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0)));
                    can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i)));
                    can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0)));
                    can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1)));
                    can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i)));
                }
            }
        }else if(eat == 0 && bite ==3){
            can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0)));
            can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(1)));

        }else if(eat == 1 && bite ==0){
            for(int i = 0;i<ca_num.length();i++){
                for(int j = 0;j<ca_num.length();j++){
                    if(ca_num.charAt(i)!=ca_num.charAt(j) && ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) &&
                            ca_num.charAt(i)!=pred_num.charAt(2) && ca_num.charAt(j)!=pred_num.charAt(0) &&
                            ca_num.charAt(j)!=pred_num.charAt(1) && ca_num.charAt(j)!=pred_num.charAt(2)){
                    can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(j)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(pred_num.charAt(2)));
                    }
                }
            }

        }else if(eat ==1 && bite ==1){
            for(int i = 0;i<ca_num.length();i++){
                if(ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
                    can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1)));
                    can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0)));
                    can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i)));
                    can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2)));
                }
            }

        }else if(eat ==1 && bite ==2){
            for(int i = 0;i<ca_num.length();i++){
                can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1)));
                can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0)));
                can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2)));
            }

        }else if(eat ==2 && bite ==0){
            for(int i = 0;i<ca_num.length();i++){
                if(ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
                    can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i)));
                    can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(2)));
                }
            }

        }else if(eat ==3 && bite ==0){
            can_list.add(pred_num);
        }

        if(old_list.size()!=0){
            for(String num : can_list){
                if(old_list.contains(num)){
                    squeeze.new_can_list.add(num);
                    squeeze.can_num =ca_num;
                }
            }

        }else{
            squeeze.new_can_list = can_list;
            squeeze.can_num = ca_num;
        }
        //System.out.println(can_num);
        return squeeze;
    }


    //期待候補数を計算する
    public double count_cand(String pred_num,String ca_num,List<String> ca_list){
        double ave_ca = 0;
        int[][] info_list = {{0,0},{0,1},{0,2},{0,3},{1,0},{1,1},{1,2},{2,1},{3,0}};
        int sum_ex = 0;
        int sum_ex2 = 0;
        List<String> old_count_list = new ArrayList<>(ca_list);
        String ca_count_num = ca_num;
        NumeronAI squeeze2 = new NumeronAI();
        for(int[] info :info_list){
            squeeze2 = Squeeze(info[0],info[1],pred_num,ca_count_num,old_count_list);
            sum_ex=sum_ex+squeeze2.new_can_list.size();
            sum_ex2=sum_ex2+squeeze2.new_can_list.size()^2;
        }
        if(sum_ex!=0){
            ave_ca=sum_ex2/sum_ex;
        }
        return ave_ca;
    }


    //期待候補数が最小の数値を選択する
    public String choice(List<String> ca_list,String ca_num){
        List<Double> ave_list = new ArrayList<>();
        int min_index =0;
        try{
            for(String num :ca_list){
                double ave_ca = count_cand(num,ca_num,ca_list);
                ave_list.add(ave_ca);
            }
            double min =ave_list.get(0);
            for(int i =0;i<ave_list.size();i++){
                double val = ave_list.get(i);
                if(min > val){
                    min = val;
                    min_index = i;
                }
            }
            return ca_list.get(min_index);
        }catch(Exception e){
        System.out.println("チョイスミス:" + e);
        return "111";
    }
    }


}

実行結果

実行結果.PNG
今回だと、6ターンで当てられてしまいました。

感想

Javaはあまり書いたことがなかったけど一応自分の作りたかったものはできたと思います。
しかしまだまだ、デザインパターンの知識を実践するレベルには至ってないので、勉強する必要があるなぁと実感しました。(デザインパターン難しい...)
Numer0nのAI(AIとあまり言いたくないけど)を自分の手で書いてみるのは、Numer0nを知っていて、なにか作ってみたいという方には、ルールも分かりやすいのでオススメです!

あと、pythonでもNumeronAIの部分だけ作成したのでJavaは書いてないけどpythonならわかるよって方は良かったら参考にしてみてください。

Qiitaの投稿はこれが初めてなので、Qiitaの先輩方、この記事について改善点などありましたら是非よろしくお願いします<(_ _)>

これから少しずつアウトプットしていけるよう頑張ります!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaでNumer0nの対戦ゲームを作ってみた(AIも作ったよ)

JavaでNumer0nの対戦ゲームを作ってみた

はじめに

今回、大学の授業でJavaでサーバ・クライアント間の通信を介した何かを作るという課題が出たので、高校生の頃、授業中によくやっていたNumer0nのゲームを作ってみようと思った。
高校生の頃、Numer0nのゲームにはまりすぎて、1手目で〇EAT〇BITEになる確率を手計算で求めて楽しんでた気がする...

この記事を読んでくださっている方は、Numer0nの基本的なルールは知っていると思うのでそこのところは割愛させていただきます。
ヌメロンWikipedia

開発環境

Java:version 7
Eclipse: Juno 4.2
OS: windows10

開発方針

今回のシステムで実装したいことは、
1. サーバ・クライアント間の通信を行い、複数のクライアントが同時にアクセスでき、ルームを作成し、対戦ができる
2. それなりに強いコンピュータ対戦もできるようにする(アルゴリズムの実装)
3. 入力ミスや数値の重複などに対応する
4. ターン制のゲームなので入力を交互に受け取るようにする

コード

コードをすべて載せると長くなってしまうので、今回はサーバ側の送受信を担当するChannelクラスと、コンピュータのアルゴリズムを実装したNumer0nAIクラスのみ掲載します。すべてのクラスと発表資料(パワポ)はGitHubに載せてあるのでよかったら見ていってください!pythonのほうでもNumeronAIを実装しているのでpythonよく使う人はそちらもどうぞ!
Javaで作るNumer0n(GitHub)
pythonのNumer0nAI(GitHub)

Channelクラスについて

クライアントからの入力を確認するとサーバがChannelを生成し、Channelとクライアントがやり取りをします。そのおかげでクライアントに意図しない例外が発生しても、おおもとのサーバはダウンしないので他のクライアントの接続は保たれます。

Channel.java
package server;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Channel extends Thread {
    JUDGE judge = new JUDGE();
    Server server;
    Socket socket = null;
    BufferedReader input;
    OutputStreamWriter output;
    String handle;
    String playertype;
    String roomnumber;
    String mynumber;
    String tekinumber;
    boolean turn;

    String ex = "926";//AIの最初の予測値
    String ca ="0123456789";//candidate number 最初は0~9まで
    String ex_number;
    List<String> old_list = new ArrayList<>();

    final char controlChar = (char)05;
    final char separateChar = (char)06;

    Channel(Socket s,Server cs){
        this.server = cs;
        this.socket = s;
        this.start();
    }

    synchronized void write(String s){
        try{
            output.write(s + "\r\n");
            output.flush();
        }catch(IOException e){
            System.out.println("Write Err");
            close();
        }
    }

    public void run(){
        List<String> s_list = new ArrayList<>();//クライアントからの入力を受け取り、ためておくリスト
        String s;
        String opponent = null;
        try{
            input = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));
            output = new OutputStreamWriter(socket.getOutputStream());
            write("# Welcome to Numr0n Game");
            write("# Please input your name");
            handle = input.readLine();
            System.out.println("new user: "+ handle);
            while(true){//HOST or GUEST入力待ち
                write("INPUT YOUR TYPE(HOST or GUEST or AI)");
                playertype = input.readLine();
                if(playertype.equals("HOST")){
                    Random rnd = new Random();
                    s = String.valueOf(rnd.nextInt(100)+100);
                    write("[HOST]ルーム番号: "+s);
                    break;
                }else if(playertype.equals("GUEST")){
                    write("[GUEST]ルーム番号を入力してください");
                    s = input.readLine();
                    write("[GUEST]ルーム番号: "+s);
                    break;
                }else if(playertype.equals("AI")){
                    write("[vs AIモード]");
                    Random rnd = new Random();
                    s = String.valueOf(rnd.nextInt(100)+100);
                    write("[HOST]ルーム番号: "+s);
                    break;
                }else{
                    write("ルーム番号入力でエラー");
                }
            }

            roomnumber  = s;    //roomnumberの決定
            System.out.println(roomnumber);
            write("対戦相手待ち");

            if(playertype.equals("AI")){
                //AIとの対戦
                write("自分の数字を決めてください(*3桁の数値*0~9まで*数字の被りなし)");

                boolean firstnum = false;
                while(firstnum == false){//最初の自分の数字が上記の条件を満たしているか
                    mynumber = input.readLine();
                    firstnum = judge.isNumber(mynumber);
                }
                write("自分の数字: "+ mynumber);
                write(handle + "からスタートです");
                tekinumber="864";
                NumeronAI numeron = new NumeronAI();
                while(true){
                    //ゲームスタート
                    boolean finish = false;

                    s = input.readLine();

                    if(s == null){
                        close();
                    }else{
                        System.out.println(s);
                        boolean numsuccess = judge.isNumber(s);//数字が定義内
                        if (numsuccess) {
                            JUDGE eatbite = judge.EatBite(s, tekinumber);
                            finish = judge.Finish(eatbite.eat);//3eatになったかどうか
                            write("["+ s +"] eat: " +String.valueOf(eatbite.eat) +" bite: "+ String.valueOf(eatbite.bite));

                            //ここからAIのターン
                            JUDGE AIeatbite = judge.EatBite(ex, mynumber);

                            NumeronAI squeeze = numeron.Squeeze(AIeatbite.eat,AIeatbite.bite,ex,ca,old_list);
                            if(squeeze.new_can_list.size()<300){
                                //System.out.println(Arrays.toString(squeeze.new_can_list.toArray()));
                                //System.out.println(squeeze.can_num);
                                ex_number = numeron.choice(squeeze.new_can_list,squeeze.can_num);
                            }else{
                                Random rnd = new Random();
                                int index = rnd.nextInt(100);
                                ex_number = squeeze.new_can_list.get(index);
                            }
                            old_list = new ArrayList<>(squeeze.new_can_list);
                            //System.out.println("残り候補数: " + String.valueOf(old_list.size()));
                            write("AIの予測値:" + ex + "        [残り候補数: " + String.valueOf(old_list.size())+"個]");
                            //System.out.println("AIの予測値: "+ ex);
                            if(mynumber.equals(ex)){
                                write("#################you lose#################");
                            }
                            ex = ex_number;

                                //ここまでがAIのターン
                        } else {
                            write(" did not send such a number");
                        }
                    }
                    if(finish){
                        write("#################you win#################");
                    }
                }

            }else{//vs人間
                while(opponent == null){//対戦相手待ち
                    opponent = server.findopponent(handle,roomnumber);
                }
                //write("対戦相手が決まりました");
                write("自分の数字を決めてください(*3桁の数値*0~9まで*数字の被りなし)");

                boolean firstnum = false;
                while(firstnum == false){//最初の自分の数字が上記の条件を満たしているか
                    mynumber = input.readLine();
                    firstnum = judge.isNumber(mynumber);
                }
                write("自分の数字: "+ mynumber);

                while(tekinumber == null){//敵の数値を取得するまで待つ
                    tekinumber = server.findopponentnumber(handle, roomnumber);
                }

                if(playertype.equals("HOST")){
                    turn = true;
                }else{
                    turn =false;
                }

                write("HOSTプレイヤーからスタートです");
                while(true){
                    //ゲームスタート
                    boolean finish = false;
                    while(true){
                        //ターンの確認
                        s_list.add(input.readLine());//入力を入れておく
                        turn = server.isTurn(handle);//turnの確認
                        if(turn == true){
                            break;
                        }
                    }

                    s = s_list.get(s_list.size()-1);
                    s_list.clear();

                    if(s == null){
                        close();
                    }else{
                        System.out.println(s);
                        boolean numsuccess = judge.isNumber(s);//数字が定義内
                        if (numsuccess) {
                            //write("judge ok");
                            boolean connectsuccess = server.singleSend(opponent,"[相手の予測] "+s);//相手がいる
                            if(connectsuccess){
                                //write("相手が存在する");
                                JUDGE eatbite = judge.EatBite(s, tekinumber);
                                finish = judge.Finish(eatbite.eat);//3eatになったかどうか
                                write("     [自分の予測]"+ s +" eat: " +String.valueOf(eatbite.eat) +" bite: "+ String.valueOf(eatbite.bite));
                                server.ChangeTurn(handle, opponent);//ターンの切り替え
                            }else{
                                write("did not find opponent");
                            }
                        } else {
                            write(" did not send such a number");
                        }


                        }
                    if(finish){
                        write("#################you win#################");
                        server.singleSend(opponent, "#################you lose#################");
                    }

                    }
            }



        }catch(IOException e){
            System.out.println("Exception occurs in Channel: "+handle);
        }
    }
    public void close(){
        try{
            input.close();
            output.close();
            socket.close();
            socket = null;
            //server.broadcast("回線切断 : " + handle);
        }catch(IOException e){
            System.out.println("Close Err");
        }
    }



}

NumeronAIクラスについて

NumeronAIクラスはコンピュータの予測部分を実装したクラス。
予測には、得られたEAT-BITE情報から考えられる候補を絞るSqueezeメソッドと、その候補の中から、良さそうな手を選ぶChoiceメソッド、良さそうな手を計算するcount_candメソッドからなります。良さそうな手とは、ある手を選んだ時に、返ってくるすべてのEAT-BITEの組み合わせから期待正解候補数が最も少ないものとしています。詳しくはnumer0nの必勝法を考えるを見てみてください。この理論に近いものを実装してます!
ちなみに平均コール数は5か6ぐらいだと思います(体感)。

NumeronAI.java
package server;

import java.util.ArrayList;
import java.util.List;

public class NumeronAI {
    List<String> new_can_list = new ArrayList<>();//candidate list
    String can_num;//candidate number


    //考えられる候補数に絞る
    public NumeronAI Squeeze(int eat,int bite,String pred_num,String ca_num,List<String> old_list){
        NumeronAI squeeze = new NumeronAI();
        List<String> can_list = new ArrayList<>();
        List<String> li = new ArrayList<>();

        if(eat == 0 && bite == 0){
            //System.out.println("--------" + String.valueOf(ca_num.length()));
            for(int i = 0; i<ca_num.length();i++){
                if(ca_num.charAt(i) != pred_num.charAt(0) && ca_num.charAt(i) != pred_num.charAt(1) && ca_num.charAt(i) != pred_num.charAt(2)){
                    li.add(String.valueOf(ca_num.charAt(i)));
                }
            }
            ca_num ="";
            StringBuilder builder = new StringBuilder();
            for(String num : li){
                builder.append(num);
            }
            ca_num = builder.substring(0,builder.length());

            for(int i = 0;i<ca_num.length();i++){
                for(int j = 0;j<ca_num.length();j++){
                    for(int k = 0;k<ca_num.length();k++){
                        if(ca_num.charAt(i)!=ca_num.charAt(j) && ca_num.charAt(i)!=ca_num.charAt(k) && ca_num.charAt(j)!=ca_num.charAt(k)){
                            can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(ca_num.charAt(k)));
                        }
                    }
                }
            }
        }else if(eat ==0 && bite ==1){
            for(int i = 0;i<ca_num.length();i++){
                for(int j = 0;j<ca_num.length();j++){
                    if(ca_num.charAt(i) != ca_num.charAt(j) && ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
                        can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(j)));
                        can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(pred_num.charAt(0)));
                        can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j)));
                        can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(pred_num.charAt(1)));
                        can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j)));
                        can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(j)));
                    }

                }
            }
        }else if(eat ==0 && bite ==2){
            for(int i = 0;i<ca_num.length();i++){
                if(ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(1)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1)));
                    can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i)));
                    can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0)));
                    can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i)));
                    can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0)));
                    can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1)));
                    can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i)));
                }
            }
        }else if(eat == 0 && bite ==3){
            can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0)));
            can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(1)));

        }else if(eat == 1 && bite ==0){
            for(int i = 0;i<ca_num.length();i++){
                for(int j = 0;j<ca_num.length();j++){
                    if(ca_num.charAt(i)!=ca_num.charAt(j) && ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) &&
                            ca_num.charAt(i)!=pred_num.charAt(2) && ca_num.charAt(j)!=pred_num.charAt(0) &&
                            ca_num.charAt(j)!=pred_num.charAt(1) && ca_num.charAt(j)!=pred_num.charAt(2)){
                    can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(j)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(pred_num.charAt(2)));
                    }
                }
            }

        }else if(eat ==1 && bite ==1){
            for(int i = 0;i<ca_num.length();i++){
                if(ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
                    can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1)));
                    can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0)));
                    can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i)));
                    can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2)));
                }
            }

        }else if(eat ==1 && bite ==2){
            for(int i = 0;i<ca_num.length();i++){
                can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1)));
                can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0)));
                can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2)));
            }

        }else if(eat ==2 && bite ==0){
            for(int i = 0;i<ca_num.length();i++){
                if(ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
                    can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i)));
                    can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2)));
                    can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(2)));
                }
            }

        }else if(eat ==3 && bite ==0){
            can_list.add(pred_num);
        }

        if(old_list.size()!=0){
            for(String num : can_list){
                if(old_list.contains(num)){
                    squeeze.new_can_list.add(num);
                    squeeze.can_num =ca_num;
                }
            }

        }else{
            squeeze.new_can_list = can_list;
            squeeze.can_num = ca_num;
        }
        //System.out.println(can_num);
        return squeeze;
    }


    //期待候補数を計算する
    public double count_cand(String pred_num,String ca_num,List<String> ca_list){
        double ave_ca = 0;
        int[][] info_list = {{0,0},{0,1},{0,2},{0,3},{1,0},{1,1},{1,2},{2,1},{3,0}};
        int sum_ex = 0;
        int sum_ex2 = 0;
        List<String> old_count_list = new ArrayList<>(ca_list);
        String ca_count_num = ca_num;
        NumeronAI squeeze2 = new NumeronAI();
        for(int[] info :info_list){
            squeeze2 = Squeeze(info[0],info[1],pred_num,ca_count_num,old_count_list);
            sum_ex=sum_ex+squeeze2.new_can_list.size();
            sum_ex2=sum_ex2+squeeze2.new_can_list.size()^2;
        }
        if(sum_ex!=0){
            ave_ca=sum_ex2/sum_ex;
        }
        return ave_ca;
    }


    //期待候補数が最小の数値を選択する
    public String choice(List<String> ca_list,String ca_num){
        List<Double> ave_list = new ArrayList<>();
        int min_index =0;
        try{
            for(String num :ca_list){
                double ave_ca = count_cand(num,ca_num,ca_list);
                ave_list.add(ave_ca);
            }
            double min =ave_list.get(0);
            for(int i =0;i<ave_list.size();i++){
                double val = ave_list.get(i);
                if(min > val){
                    min = val;
                    min_index = i;
                }
            }
            return ca_list.get(min_index);
        }catch(Exception e){
        System.out.println("チョイスミス:" + e);
        return "111";
    }
    }


}

実行結果

実行結果.PNG
今回だと、6ターンで当てられてしまいました。

感想

Javaはあまり書いたことがなかったけど一応自分の作りたかったものはできたと思います。
しかしまだまだ、デザインパターンの知識を実践するレベルには至ってないので、勉強する必要があるなぁと実感しました。(デザインパターン難しい...)
Numer0nのAI(AIとあまり言いたくないけど)を自分の手で書いてみるのは、Numer0nを知っていて、なにか作ってみたいという方には、ルールも分かりやすいのでオススメです!

あと、pythonでもNumeronAIの部分だけ作成したのでJavaは書いてないけどpythonならわかるよって方は良かったら参考にしてみてください。

Qiitaの投稿はこれが初めてなので、Qiitaの先輩方、この記事について改善点などありましたら是非コメントよろしくお願いします<(_ _)>

これから少しずつアウトプットしていけるよう頑張ります!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

spring-batchのReader must be open before it can be readの原因と対策

現象

以下のようなbean定義をしたところエラーになり実行できなかった。

やろうとした事としては https://docs.spring.io/spring-batch/docs/current/reference/html/scalability.html#partitioning の、spring-batchのPartitioningを試している。partitioningの情報(fileName)がstepExecutionContextに入るため、beanを@StepScopeにしている。

    @StepScope
    @Bean
    public ItemReader<String> itemReader(@Value("#{stepExecutionContext['fileName']}") 
    Resource resource) throws IOException {

エラー内容は以下のとおり。

org.springframework.batch.item.ReaderNotOpenException: Reader must be open before it can be read.
    at org.springframework.batch.item.file.FlatFileItemReader.readLine(FlatFileItemReader.java:201) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:178) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]

対策

戻り値型のItemReaderFlatFileItemReaderに変更する。または、この場合はItemStreamReaderでも良い。

    @StepScope
    @Bean
    public FlatFileItemReader<String> itemReader(@Value("#{stepExecutionContext['fileName']}") 
    Resource resource) throws IOException {

理由

@StepScopeにより戻り値をAOPでプロキシするため。

@StepScopeの中身を見るとproxyMode = ScopedProxyMode.TARGET_CLASSであり、いま、戻り値型がItemReaderなのでこのインタフェースに対するプロキシが作られる。そして、このインタフェースには(ItemStreamの)openは無いので、当然openは呼ばれない。実際のインスタンスはFlatFileItemReaderでこれはopenせずにreadは出来ないため、Reader must be open before it can be readという例外になる。そういわけで戻り値型をFlatFileItemReaderか、ItemStreamReaderに変えれば正常に動作する。

参考URL

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

spring-batchのpartitioning使用時のReader must be open before it can be readの原因と対策

現象

以下のようなbean定義をしたところエラーになり実行できなかった。

やろうとした事としては https://docs.spring.io/spring-batch/docs/current/reference/html/scalability.html#partitioning の、spring-batchのPartitioningを試している。partitioningの情報(fileName)がstepExecutionContextに入るため、beanを@StepScopeにしている。

    @StepScope
    @Bean
    public ItemReader<String> itemReader(@Value("#{stepExecutionContext['fileName']}") 
    Resource resource) throws IOException {

エラー内容は以下のとおり。

org.springframework.batch.item.ReaderNotOpenException: Reader must be open before it can be read.
    at org.springframework.batch.item.file.FlatFileItemReader.readLine(FlatFileItemReader.java:201) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:178) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]

対策

戻り値型のItemReaderFlatFileItemReaderに変更する。または、この場合はItemStreamReaderでも良い。

    @StepScope
    @Bean
    public FlatFileItemReader<String> itemReader(@Value("#{stepExecutionContext['fileName']}") 
    Resource resource) throws IOException {

理由

@StepScopeにより戻り値をAOPでプロキシするため。

@StepScopeの中身を見るとproxyMode = ScopedProxyMode.TARGET_CLASSであり、いま、戻り値型がItemReaderなのでこのインタフェースに対するプロキシが作られる。そして、このインタフェースには(ItemStreamの)openは無いので、当然openは呼ばれない。実際のインスタンスはFlatFileItemReaderでこれはopenせずにreadは出来ないため、Reader must be open before it can be readという例外になる。そういわけで戻り値型をFlatFileItemReaderか、ItemStreamReaderに変えれば正常に動作する。

参考URL

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Java]eclipseでJerjey(Jax-rs)を利用したAPI作成

はじめに

mavenとかgradleを使わないで実装する方法があんまりなかったので書こうと思います。

Jerjeyの導入

  • Jerjeyから最新版をDL。
  • jaxrs-ri-(version).zipを解凍し、中の[lib]ファイルの中身をEclipceで使うTomcatの[lib]内に入れる。

プロジェクトの作成

Eclipseで動的Webプロジェクトを作成し、
パッケージ[com.sample.api]とその下にクラス[SampleApi.java]を作成する。

web.xmlの作成

WebContent/WEB-INFに[web.xml]を作成し、以下をコピペ。

filename.xml
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">

 <servlet>
  <servlet-name>jersey-app</servlet-name>
  <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>jersey.config.server.provider.packages</param-name>
    <param-value>com.api.sample</param-value><!--パッケージ名-->
  </init-param>

  <init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
 </servlet>

 <servlet-mapping>
  <servlet-name>jersey-app</servlet-name>
  <url-pattern>/api/*</url-pattern>
 </servlet-mapping>

  </web-app>

ApiSample.javaの編集

最初に作成したApiSample.javaを以下に編集。

ApiSample.java
package com.api.sample;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("/Sample")
public class ApiSample {
    @Path("/hello")
    @GET
    @Produces(MediaType.TEXT_HTML + "; charset=UTF-8")
    public String hello(@QueryParam("name") final String name){
        return "Hello!"+name+"さん。";
    }
}

実行

http://localhost:8080/プロジェクト名/api/Sample/hello

結果
Hello!nullさん。

と表示されればOK。
また、http://localhost:8080/プロジェクト名/api/Sample/hello?name=山田
と入力すれば

Hello!山田さん。

と表示されるはず。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

jarファイルに画像リソースを含める

IntelliJからjarファイルを出力すると、画像が表示されなくなる問題

Swingを用いたGUIツールを作製したとき、IntelliJ上で実行した場合は画像ファイルがきちんと表示されるが、jarファイルとして出力すると画像ファイルうまく表示できなくなるという問題に直面した。
ググったところ、よく知られた現象らしく、解決策もすぐに出てきた。以下はその解決策を自分用のメモとしてまとめたものである。

状況説明

JavaのGUIツールキットであるSwingを練習するため、砂時計アイコンが表示されるだけの簡単なプログラムを作製していた。
スクリーンショット 2020-01-22 10.42.20.png
こんなの

アイコンはhourglass.pngファイルという名前で、srcフォルダ直下に保存した。また、アイコンファイルの読み込みは以下のように記した。
ImageIcon myIcon = new ImageIcon("hourglass.png");
スクリーンショット 2020-01-22 10.49.04.png

このコードをIntelliJ上で実行すると、砂時計アイコンがきちんと表示されたプログラムが実行される。
しかし、jarファイルを出力し、ターミナル上からプログラムを実行すると、以下のようにアイコンが表示できなくなってしまう。

スクリーンショット 2020-01-22 11.23.16.png

解決策

ClassLoader.getResource()を利用する。

Javaでは、ファイルなどのリソース情報を取得する処理としてClassLoader.getResource()が用意されている。

先のコードでImageIcon myIcon = new ImageIcon("hourglass.png");としていた記述を、

ClassLoader cl = this.getClass().getClassLoader();
ImageIcon myIcon = new ImageIcon(cl.getResource("hourglass.png"));

と書き換えることで、jarファイルとして出力した後も、画像リソースがちゃんと参照されるため、画像が表示されるようになる。
スクリーンショット 2020-01-22 10.42.20.png
やったね

参照元

https://virtualwalk.hatenadiary.org/entry/20121013/1350127275
http://hiesuke.hatenablog.com/entry/2016/12/30/101639

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Android]端末からサーバへ画像のアップロード

はじめに

Androidで画像をPOSTし、サーバに保存する機能でてこずったため自分の備忘録兼、アウトプットとして書きます。プログラムのお仕事半年もしてないからいろいろおかしいかもしれないけど許してね。

追記

ご指摘を受けました。ありがとうございます!

OkHTTP2はobsoletes扱いです。最新の4.3.1を使うようにしましょう。

https://square.github.io/okhttp/changelog_3x/#version-300-rc1
https://square.github.io/okhttp/changelog/

環境

AndroidStudioでOkHttpを利用しています。

OkHttp導入

  • AndroidStudio画面左上の「Android」を「プロジェクト」に切り替え。
  • [app]内のbuild.gradleを開く。
  • dependencies内に implementation 'com.squareup.okhttp:okhttp:2.7.5' を追記。(2.7.5はvarsionによって変えてください。)
  • dependencies内にimplementation 'com.squareup.okhttp:okhttp:4.3.1' を追記。 (2020/1/24 変更)
build.gradle
//~~省略~~
dependencies{
  //~~省略~~
  implementation 'com.squareup.okhttp:okhttp:4.3.1'//追記
}

完了。

AsyncTask

Http通信で送るので非同期で行う。

OkHttpTask.java
import android.os.AsyncTask;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class HttpTask extends AsyncTask<String, Void, String> {

    String responseBody;
    public HttpTask(){}

    @Override
    protected String doInBackground(String... params) {
        String url = "送るURL"; 
        MediaType media = MediaType.parse("multipart/form-data");
        try {
            File file = new File(params[0]);
            String FileName = file.getName();
            String boundary = String.valueOf(System.currentTimeMillis());

            RequestBody requestBody = new MultipartBody.Builder(boundary).setType(MultipartBody.FORM)
                    .addFormDataPart("file", FileName, RequestBody.create(media, file))
                    .build();

            Request request = new Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build();

            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();
            responseBody = response.body().string();

            return responseBody;

        } catch (IOException e) {
            e.printStackTrace();
        }
        return responseBody;
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d("a",result);
    }
}

いろいろ変更したので書き直しました。また、変更に伴って
java.io.IOException: Cleartext HTTP traffic to example.com not permitted
のようなエラーが表示されることがあるかと思います。
これはデフォルトでHTTPS通信になったので、HTTP通信を許可する方法を書いておく必要があるからです。方法についてはこちらの方が詳しく書かれているのでどうぞ。

古いコード
OkHttpTask_old.java
/**削除
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
*/
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class OkHttpTask extends AsyncTask<String, Void, String> {
  public OkHttpTask(){}

    @Override
    protected String doInBackground(String... params) {
        //ポスト先のURL
        String url = "http://";
        File file = new File(params[0]);

        /**削除
        *ここでPOSTする内容を設定
        RequestBody requestBody = new MultipartBuilder()
                .type(MultipartBuilder.FORM)
                .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/jpg"), file))
                .build();
        */

        //ここでPOSTする内容を設定(こっちに変更)
        RequestBody requestBody = new MultipartBody.Builder()
                .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/jpg"), file))
                .build();


        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        String result="";
        try {
            Response response = client.newCall(request).execute();
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
            {
                result = response.body().string();
            }
        } catch (Exception e) {}

        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d("end:",result);
    }
}
*/

MainActivity

MainActivity.java
public class MainActivity extends AppCompatActivity {
  //送る画像のURI
  private Uri _imageUri;
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //ここで呼び出し
        new OkHttpTask().execute(url);   
}

受け取る側

Postされたファイルを保存するだけ。

UpLoad.java
@WebServlet("/Upload")
@MultipartConfig(location = "保存場所")
public class upload extends HttpServlet {

    public void doPost(HttpServletRequest req,HttpServletResponse res) throws IOException, ServletException {
        String name="no_name";
        //multipart/form-dataによって提供されるこのリクエストのすべてのPart要素を取得
        for (Part part : req.getParts()) {
            //名前の取得
            for (String cd : part.getHeader("Content-Disposition").split(";")) {
                String str = cd.trim();
                if (str.startsWith("filename")) {
                    String str2 = str.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
                    File f = new File(str2);
                    name = f.getName();
                    part.write(name);
                }
            }
        }
    }
}

参考リンク

OkHttpを初めて使ってみた話
https://qiita.com/LyricalMaestro0/items/698c77f5a964b5658bbb

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

バッチファイル入門(for文、配列、遅延環境変数)

動機

「○○系の機能の呼び出し元を知りたいから、一覧化して」
と言われて数えてみたら

  • ○○系の機能は150弱
  • Javaファイルは15000個

あったので、IDE使って150回検索するのも辛そうだったのでバッチファイルで何とかしてみた。
何故bashじゃないのかとか何故そんなことしないといけないのかは聞かないでほしい。

作った bat ファイルと実行結果

grepCallHierarchy.bat
@echo off

setlocal enabledelayedexpansion
set i=0
for /f %%a in (targetList.txt) do (
  set /a i+=1
  echo !i! %%a
  call set Arr[!i!]=%%a
)

pause

for /r %%a in (*.java) do (
  for /f "tokens=1,2,3 delims= " %%b in (%%a) do (
    for /l %%j in (1,1,%i%) do (
      if !Arr[%%j]!==%%c (
        echo %%a %%b %%c %%d
      )
    )
  )
)

targetList.txt
NantokaComponent
KantokaComponent

出力

C:\path\to\file1.java private NantokaComponent nantokaComponent;
C:\path\to\file2.java private KantokaComponent kantokaComponent;

感想(学んだこと)

for文

色んなfor文の練習になった。

  • 拡張子でディレクトリ内を再帰でファイル検索
    • for /r %%a in (*.java) do
  • ファイルを1行ごとに読み出し(delimiter(デリミタ)を使う練習も兼ねて)
    • for /f "tokens=1,2,3 delims= " %%b in (%%a) do
  • jをインクリメントしながらループ
    • for /l %%j in (1,1,148) do

配列

call set Arr[!i!]=%%a

初めて知ったんですが、バッチファイルは配列がないんですね。
Arr[1] Arr[2] ... という変数をただひたすら作ってるだけらしい。

遅延環境変数

setlocal enabledelayedexpansion

配列を添え字でループさせたいとき、遅延評価させないとずっと Arr[1] (初期値)になってしまうらしい。
むずかしい。。

遅延評価したい部分は、 Arr[%i%] ではなく Arr[!i!] のようにびっくりマークで囲うんだそう。
びっくり。

総評

楽しかった。(小並感)
作ってる途中で、そういえばPowerShellもあったな、と思った。
次はPowerShellで遊びたいと思う。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCodeでLombok

何の記事?

VS CodeでSpring Bootアプリケーション作成時、Lombokが仕事を放棄しているのではと感じたときのこと。

どんな状態?

DTOやEntityに「@Data」をつけてもgetter,setterでコンパイルエラーになるし、補完にも出てこない。

結論

放棄していない。

VS CodeでLombokを使用するにはSpring Bootの依存関係だけでなく、拡張を入れてあげる必要があるようです。

image.png

これをインストールするとVS Codeの再起動が求められます。
再起動し、ビルドが完了するとコンパイルエラーが消えています。

あともちろん補完にも出るようになります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む