20190215のJavaに関する記事は11件です。

Java program string examples with emoji

What about Java and JavaScript? They are similar but I will focus on Java. You can define the string just fine…

String emostring ="????";
However, that’s where troubles begin. If you try to find the length of the string (emostring.length()), Java will tell you that the string contains 8 characters. To get the proper length of the string in terms of “unicode code points”, you need to type something like emostring.codePointCount(0, emostring.length()) (this returns 4, as expected). Not only is this longer, but I also expect it to be much more computationally expensive.

What about accessing characters? You might think that emostring.charAt(1) would return the second character (?), but it fails. The problem is that Java uses UTF-16 encoding which means, roughly, that unicode characters can use one 16-bit word or two 16-bits, depending on the character. Thus if you are given a string of bytes, you cannot tell without scanning it how long the string is. Meanwhile, the character type in Java (char) is a 16-bit word, so it cannot represent all Unicode characters. You cannot represent an emoji, for example, using Java’s char. In Java, to get the second character, you need to do something awful like…

new StringBuilder().appendCodePoint(
emostring.codePointAt(emostring.offsetByCodePoints(0, 1))).toString()
I am sure you can find something shorter, but that is the gist of it. And it is far more expensive than charAt.

If your application needs random access to unicode characters in a long string, you risk performance problems.

Other language implementations like PyPy use UTF-32 encoding which, unlike Java’s UTF-16 encoding, supports fast random access to individual characters. The downside is increased memory usage. In fact, it appears that PyPy wants to move to UTF-8, the dominant format on the Web right now. In UTF-8, characters are represented using 1, 2, 3 or 4 bytes.

There are different trade-offs. If memory is no object, and you expect to use emojis, and you want fast random access in long strings, I think that UTF-32 is superior. You can still get some good performance with a format like UTF-8, but you will probably want to have some form of indexing for long strings. That might be difficult to implement if your language does not give you direct access to the underlying implementation.

More annoying than performance is just the sheer inconvenience to the programmer. It is 2018. It is just unacceptable that accessing the second emoji in a string of emojis would require nearly undecipherable code.

Java program to remove duplicate elements in array

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

Codewars で複数のプログラミング言語で全ての問題を解いていきたい時に便利な操作

クリックすると私が解いた問題が見れます。
# 今回は画像(スクショ)だけで手抜き~!

# Codewars についてご存じない方は、先に『【Codewars】ブラウザでコーディングの基礎からトレーニングできるサイト (ブラウザでvimが使えて32種類のプログラミング言語に対応。4000個以上の問題が投稿されています!)』 をお読み頂くようお願い致します。

image.png

image.png

image.png

image.png

このような感じで、View Profile メニューから Kata タブを選択することで、他の言語で解き忘れがないか確認できます。すでにやった問題を自分の学習中の言語全てで解いてみたい方におススメです。

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

CodinGame の TRON BATTLE で FloodFill アルゴリズムを実装してみた

# この記事は、『CodinGame はBOT(AIプログラム)でバトルするのが正しい楽しみ方かもしれません』 の続きです。

以下のようなデバッグ出力ができるように CodinGame の TRON BATTLE プログラムを改造してみた。

  • P=0 という出力から、自機のプレイヤー番号は0であることが分かる。
  • Input{X0:2, Y0:2, X1:10, Y1:0} という出力からプレイヤー0のスタート位置(tail)は、(2, 2) であることと、現在位置(head)の座標が (10, 0) であることが分かる。 *自機のプレイヤー(プレイヤー0)のヘッドから見て現時点で到達可能であるマスが+記号で表示されている。ちなみにマイナス記号は何もない印である。
P=0
Input{X0:2, Y0:2, X1:10, Y1:0}
+ + + + + + + + + + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

1. 出来たソース

using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;

class Player
{
    static void Main(string[] args) {
        Player control = new Player();
        string[] numbers;
        Input[] inputs;
        // game loop
        while (true) {
            numbers = Console.ReadLine().Split(' ');
            int N = int.Parse(numbers[0]);
            int P = int.Parse(numbers[1]);
            Console.Error.WriteLine("P={0}", P);
            inputs = new Input[N];
            for (int i = 0; i < N; i++) {
                numbers = Console.ReadLine().Split(' ');
                int X0 = int.Parse(numbers[0]);
                int Y0 = int.Parse(numbers[1]);
                int X1 = int.Parse(numbers[2]);
                int Y1 = int.Parse(numbers[3]);
                inputs[i] = new Input(i, X0, Y0, X1, Y1);
            }
            Input me = inputs[P];
            string dir = control.HandleInputs(me, inputs);
            control.DumpMap();
            Console.WriteLine(dir);
        }
    }
    Cell[,] map = new Cell[30, 20];
    Queue<Cell> ffQueue = new Queue<Cell>();
    private Player() {
        for(int y=0; y<20; y++) {
            for(int x=0; x<30; x++) {
                map[x, y] = new Cell(x, y, -1);
            }
        }
    }
    private string HandleInputs(Input me, Input[] inputs) {
        Console.Error.WriteLine(me);
        foreach(var input in inputs) {
            if (input.X1 < 0) DeleteIdsFromMap(input.Id);
            else AddInputToMap(input);
        }
        ExecuteFloodfill(me);
        if (CanMoveTo(me, -1, 0)) return "LEFT";
        if (CanMoveTo(me, 1, 0)) return "RIGHT";
        if (CanMoveTo(me, 0, -1)) return "UP";
        if (CanMoveTo(me, 0, 1)) return "DOWN";
        return "?";
    }
    void AddInputToMap(Input input) {
        this.map[input.X1, input.Y1].V = input.Id;
    }
    void DeleteIdsFromMap(int id) {
        for(int y=0; y<20; y++) {
            for(int x=0; x<30; x++) {
                if (map[x, y].V == id) map[x, y].V = -1;
            }
        }
    }
    bool CanMoveTo(Input me, int xOffset, int yOffset) {
        int x = me.X1+xOffset;
        int y = me.Y1+yOffset;
        if (x < 0) return false;
        if (x > 29) return false;
        if (y < 0) return false;
        if (y > 19) return false;
        return map[x, y].V == -1 || map[x, y].V == 9;
    }
    bool IsEmptyCell(Cell center, int xOffset, int yOffset) {
        int x = center.X+xOffset;
        int y = center.Y+yOffset;
        if (x < 0) return false;
        if (x > 29) return false;
        if (y < 0) return false;
        if (y > 19) return false;
        return map[x, y].V == -1;
    }
    void DumpMap() {
        for(int y=0; y<20; y++) {
            for(int x=0; x<30; x++) {
                if (map[x, y].V == -1) Console.Error.Write("-");
                else if (map[x, y].V == 9) Console.Error.Write("+");
                else Console.Error.Write(map[x, y].V);
                Console.Error.Write(" ");
            }
            Console.Error.WriteLine();
        }
    }
    void ExecuteFloodfill(Input me) {
        for(int y=0; y<20; y++) {
            for(int x=0; x<30; x++) {
                if (map[x, y].V == 9) map[x, y].V = -1;
            }
        }
        Cell c = map[me.X1, me.Y1];
        if (IsEmptyCell(c, -1, 0)) ffQueue.Enqueue(map[c.X-1, c.Y]);
        if (IsEmptyCell(c, 1, 0)) ffQueue.Enqueue(map[c.X+1, c.Y]);
        if (IsEmptyCell(c, 0, -1)) ffQueue.Enqueue(map[c.X, c.Y-1]);
        if (IsEmptyCell(c, 0, 1)) ffQueue.Enqueue(map[c.X, c.Y+1]);
        FloodfillLoop();
    }
    void FloodfillLoop() {
        while(ffQueue.Count > 0) {
            Cell c = ffQueue.Dequeue();
            if(map[c.X, c.Y].V != -1) continue;
            c.V = 9;
            if (IsEmptyCell(c, -1, 0)) ffQueue.Enqueue(map[c.X-1, c.Y]);
            if (IsEmptyCell(c, 1, 0)) ffQueue.Enqueue(map[c.X+1, c.Y]);
            if (IsEmptyCell(c, 0, -1)) ffQueue.Enqueue(map[c.X, c.Y-1]);
            if (IsEmptyCell(c, 0, 1)) ffQueue.Enqueue(map[c.X, c.Y+1]);
        }
    }
}
class Input
{
    public int Id;
    public int X0;
    public int Y0;
    public int X1;
    public int Y1;
    public Input(int id, int x0, int y0, int x1, int y1) {
        this.Id = id;
        this.X0 = x0;
        this.Y0 = y0;
        this.X1 = x1;
        this.Y1 = y1;
    }
    public override string ToString() {
        return String.Format("Input{{X0:{0}, Y0:{1}, X1:{2}, Y1:{3}}}", X0, Y0, X1, Y1);
    }
}
class Cell
{
    public int X;
    public int Y;
    public int V;
    public Cell(int x, int y, int v) {
        this.X = x;
        this.Y = y;
        this.V = v;
    }
    public override string ToString() {
        return String.Format("Cell{{X:{0}, Y:{1}, V:{2}}}", X, Y, V);
    }
}

2. 最後に

TRON BATTLE については書く記事としてはこれで終わりになるかもしれません。
C# で挑戦される方の「手始め」の参考にでもなればと思い投稿してみました。

# Wood 1 League を抜け出したいのだが…

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

JPAのModelでメンバ変数を作る方法

当方、java歴一ヶ月未満の初心者です。
自分用の備忘録として残します。


やりたかった事

tableからfindしてきたmodelのクラスに
カラムに存在しないフィールド名のパラメータを持たせたかった。
phpでは(あまりおすすめできないけど)そのまま変数宣言すれば普通に使えたので
javaでもできると思った。

だめだった例

Hogeテーブルにnameカラムは無く
外部からとってきたり、動的にhogeで処理させたいような時

@Entity
public class hoge {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

こうしたら

Caused by: java.sql.SQLException: Column 'name' not found.

怒られた。
PHPみたいに、nullで入ってたりはくれず
見るデータがないからダメらしい

解決法

@Transientアノテーションを使って、マッピング対象外にする。
本来は永続化対象外にする為のアノテーションらしいが
その影響でマッピング対象外になるらしい(違かったらすいません)

@Entity
public class hoge {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Transient
    private String name;

怒られなくなりました


javaを勉強していると
いかに自分がPHPで適当なコーディングしていたかがよく分かります。

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

streamを学んだ(ListをMap<Integer,List>に変換したい)

List形式のデータをMap>形式に変換する

今まで愚直にfor使っていたので、メモ。

DBから取得した、リスト形式のデータを
フィルタリングした上で、Map形式に変換したい(そのほうがjspで表示するときに楽だった)なと思った時に使った。

List<myClass> resList = myClassDao.query(insMap);

// フィルタリング
List<myClass> dataList = resList.stream()
        .filter(c -> c.getHogeId() != null)
        .collect(Collectors.toList());

// Mapに変換
Map<Integer, List<myClass>> res = dataList.stream().collect(
        Collectors.groupingBy(myClass::getHogeId)
);

これで、こんな感じのデータが

[
    {
        id:1,
        hogeId:1,
        data:"a"
    },
    {
        id:2,
        hogeId:1,
        data:"b"
    },
    {
        id:3,
        hogeId:2,
        data:"c"
    },
    {
        id:4,
        hogeId:null,
        data:"d"
    }
]

こうなります。多分。

{
    1:[
        {
            id:1,
            hogeId:1,
            data:"a"
        },
        {
            id:2,
            hogeId:1,
            data:"b"
        }
    ],
    2:[
        {
            id:3,
            hogeId:2,
            data:"c"
        }
    ]
}

もっといいやり方があればぜひ教えてください!

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

SpringBoot アプリをサービスとして動かす方法

概要

  1. Fully Executable Jarの作成
  2. confファイルの作成
  3. サービス登録

1. Fully Executable Jarの作成

Fully Executable Jarという形式のJarにするとJarの先頭にスクリプトをつけて出力してくれる。
このスクリプトがそのままサービス起動用のスクリプトとして使用できる。

作成の仕方は、pom.xmlの<build>タグの中身を次のようにする

pom.xml
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <executable>true</executable>
            </configuration>
        </plugin>
    </plugins>
</build>

<executable>true</executable>がキモ

2. confファイルの作成

実行するJarファイルと同名で拡張子だけ.confに変えたファイルを作成する。
内容は環境変数の定義とjavaに渡すオプションとjarに渡す実行時引数。

環境変数は普通にexport

export LANG="ja_JP.UTF8"

javaのオプションはJAVA_OPTS

JAVA_OPTS="-Xms1024M -Xmx1024M"

実行時引数はRUN_ARGS

RUN_ARGS="--spring.profiles.active=production"

サービス登録

CentOS7などのsystemdでは/etc/systemd/system/にserviceファイルを作成すればOK

/etc/systemd/system/hoge.service
[Unit]
Description = <サービスの説明>

[Service]
ExecStart = /home/application/hoge.jar
Restart = always
Type = simple
User = application
Group = application
SuccessExitStatus = 143

[Install]
WantedBy = multi-user.target

これで

$ sudo systemctl start hoge

とかができる

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

タスクキル方法

下記エラーで実行が妨げられた場合、すでに使っているアドレスを一度キルしないといけないみたい。

org.jboss.netty.channel.ChannelException: Failed to bind to: /0.0.0.0:[ポート番号]
Caused by: java.net.BindException: Address already in use: bind

方法(Windows):コマンドで
netstat -nao | find "[ポート番号]"で使用しているProcessNoを探す
出たら
taskkill /f /pid (探したProcessNo)
で、キルしてやって再度実行すればおk。

要は一人しか使えないものに対して
すでに使ってるお前(ProcessNo)をシメて(taskkillして)、おれが使う的な感じ。

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

Address already in useの対処法(Windows)

下記エラーで実行が妨げられた場合、すでに使っているアドレスを一度キルしないといけないみたい。

org.jboss.netty.channel.ChannelException: Failed to bind to: /0.0.0.0:[ポート番号]
Caused by: java.net.BindException: Address already in use: bind

方法(Windows):コマンドで
netstat -nao | find "[ポート番号]"で使用しているProcessNoを探す
出たら
taskkill /f /pid (探したProcessNo)
で、キルしてやって再度実行すればおk。

要は一人しか使えないものに対して
すでに使ってるお前(ProcessNo)をシメて(taskkillして)、おれが使う的な感じ。

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

【Java】2つのListから1つの配列リストへ

はじめに

積み上げ棒グラフを作るのにタイトルのことをやる必要があるので検証しました。
最初はクラス固定で実装しましたが、ジェネリクスを使って汎用的にしようとしたら躓いたので忘れないようにメモ。

環境

java8

ソース

2つのIntegerのリストからInteger配列の1つのリストへ
2つのリストはサイズが同じ前提です。

Integer版
private List<Integer[]> convertTwoListToArray1(List<Integer> list1, List<Integer> list2) {
    List<Integer[]> list = new ArrayList<>();
    for (int i = 0; i < list1.size(); i++) {
        list.add(new Integer[] { list1.get(i), list2.get(i) });
    }
    return list;
}

  
  
汎用的にしようとしたジェネリクス版がこちら

ジェネリクス版
@SuppressWarnings("unchecked")
private <T> List<T[]> convertTwoListToArray2(List<T> list1, List<T> list2) {
    List<T[]> list = new ArrayList<>();
    for (int i = 0; i < list1.size(); i++) {
        Object[] tmpArray = new Object[] { list1.get(i), list2.get(i) };
        list.add((T[]) tmpArray);
    }
    return list;
}

最後に

ジェネリクスの配列が作れなくて躓いたけど、Objectの配列をキャストすることで解決しました。

以上

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

CodinGame はBOT(AIプログラム)でバトルするのが正しい楽しみ方かもしれません

『【CodinGame】ブラウザでコーディングの基礎からトレーニングできるサイト (疑似ゲーム開発環境を使って学べます。解答は25種類のプログラミング言語から選択して記述可能!)』 という記事で、CodinGame に対してなにやら否定的なコメントを書いてしまいましたが、Twitter で「codingame」を検索してみると、「CodinGame はBOT(AIプログラム)でバトルするのが正しい楽しみ方」的な発言がみられたので、AIについては素人ながら挑戦してみました。

  • まだ、挑戦し始めなのでログ(ブログ)っぽく、やったことをそのまま記述…
  • 勝ち方の指南なんてできないので…「他の人が自分もやってみたい」と思えるような紹介風で…

という目標で書いてます。

長くなる(と思う)ので記事分けながら書いて、あとでマトメの記事が上手くできればいいなと考えています。

それでは、以下本文へ

1. https://www.codingame.com/start にアクセスします。

image.png

2. 「Sign up with Google」を選択します。

image.png

3. サインアップ完了後、https://www.codingame.com/home に自動的に遷移します。

image.png

4. https://www.codingame.com/multiplayer に遷移します。

image.png

5. https://www.codingame.com/multiplayer/bot-programming に遷移します。

image.png

6. TRON BATTLE のリプレイ動画

  • 以下のツイート内の画像をクリックすると「TRON BATTLE のリプレイ動画」に飛びます。
    この動画を見て分かるように、各プレイヤーの車は異なった色のリボンを残しながら進んでいきます。

  • 各プレイヤーの車は自分のリボンも他人のリボンも踏んではいけません(踏んだらアウト)。もちろん場外に出てもいけません。上記に違反した時点でそのプレイヤーはアウトとなり、そのプレイヤーのリボンがゲーム画面から消えます(ここもポイント!)。

  • 最後までアウトにならずに生き残ったプレイヤーの勝ちです。(実際には1位、2位、…と順位がつきます)

7. TRON BATTLE のメイン画面の「JOIN」を押してプログラム編集画面(IDE)を開きます

image.png

image.png

8. コードエディタに初期に表示される内容(C#の場合)

解答に使うプログラミング言語は、C#, C++, Java, Javascript, Python3, Bash, C, Clojure, Dart, F#, Go, Groovy, Haskell, Kotlin, Lua, ObjectiveC, OCaml, Pascal, Perl, PHP, Python2, Ruby, Rust, Scala, Swift, VB.NET の中から自由に選べます。

CodinGame のプログラミング問題はほとんど(全て?)、刻々と標準入力から情報を読み取り、刻々と標準出力に指示を書き出すというループから成り立っています。

  • このおかげでプログラミング言語間の差異を吸収しやすくなっています。ユーザーが書くプログラムを取り巻く親プロセスのプログラムは共通の物が使えるからです。
  • static void Main(string[] args) に合わせて、全プログラムを static メソッドで書こうとするとクラスを導入する際にハマることがありますのでご注意。
コードエディタに初期に表示される内容(C#の場合)
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;

/**
 * Auto-generated code below aims at helping you parse
 * the standard input according to the problem statement.
 **/
class Player
{
    static void Main(string[] args)
    {
        string[] inputs;

        // game loop
        while (true)
        {
            inputs = Console.ReadLine().Split(' ');
            int N = int.Parse(inputs[0]); // total number of players (2 to 4).
            int P = int.Parse(inputs[1]); // your player number (0 to 3).
            for (int i = 0; i < N; i++)
            {
                inputs = Console.ReadLine().Split(' ');
                int X0 = int.Parse(inputs[0]); // starting X coordinate of lightcycle (or -1)
                int Y0 = int.Parse(inputs[1]); // starting Y coordinate of lightcycle (or -1)
                int X1 = int.Parse(inputs[2]); // starting X coordinate of lightcycle (can be the same as X0 if you play before this player)
                int Y1 = int.Parse(inputs[3]); // starting Y coordinate of lightcycle (can be the same as Y0 if you play before this player)
            }

            // Write an action using Console.WriteLine()
            // To debug: Console.Error.WriteLine("Debug messages...");

            Console.WriteLine("LEFT"); // A single line with UP, DOWN, LEFT or RIGHT
        }
    }
}

9. さて、TRON BATTLE の課題(問題)文は以下のような内容です

(長いので折りたたみ中。展開してご覧ください)

◎The Goal
◎目標

In this game your are a program driving the legendary tron light cycle and fighting against other programs on the game grid.

このゲームであなたが目指すのは、ゲームグリッド上で、伝説のトロンライトサイクルを運転して他のプログラムと戦うことのできるプログラムです。

The light cycle moves in straight lines and only turn in 90° angles while leaving a solid light ribbon in its wake. Each cycle and associated ribbon features a different color.
Should a light cycle stop, hit a light ribbon or goes off the game grid it will be instantly deactivated.

ライトサイクルは真っすぐに進むか90°の角度でしか曲がれず、起動時から固形分からなる光のリボンを残しながら進みます。それぞれのライトサイクルと関連付けられたリボンは異なる色を放ちます。
ライトサイクルが停止せざるを得ない、または光のリボンに衝突した、またはゲームグリッドの外に出た場合、そのライトサイクルは即座に非活性化されます。

The last cycle in play wins the game. Your goal is to be the best program: once sent to the arena, programs will compete against each-others in battles gathering 2 to 4 cycles. The more battles you win, the better your rank will be.

最後まで残ったライトサイクルがゲームの勝者となります。あなたの目標はベストプログラムを目指すことです: アリーナに送られれば(訳注: SUBMITボタンを押せば)、プログラム達が、2~4台でのライトサイクルバトルでお互いに競争となります。より多くかつほどあなたのランクが上がります。

◎Rules
◎ルール

Each battle is fought with 2 players. Each player plays in turn during a battle. When your turn comes, the following happens:

それぞれのバトルは2プレイヤーで戦います。それぞれのプレイヤーが順番にプレイします。あなたのターンが来たら、以下が発生します:

  • Information about the location of players on the grid is sent on the standard input of your program. So your AI must read information on the standard input at the beginning of a turn.
  • グリッド上のプレイヤーの位置情報があなたのプログラムの標準入力に送信されます。そのため、あなたのAIはターンの最初に標準入力上の情報を読み込まなければなりません。
  • Once the inputs have been read for the current game turn, your AI must provide its next move information on the standard ouput. The output for a game turn must be a single line stating the next direction of the light cycle: either UP, DOWN, LEFT or RIGHT.
  • 現在のゲームターンのための情報を読み込んだら、AIは次の移動のための情報を標準出力に提供しなければなりません。ゲームターン時の出力は、ライトサイクルの次の移動方向を宣言する一行の出力でなければなりません: UP, DOWN, LEFT, RIGHT のいずれかを出力します。
  • Your light cycle will move in the direction your AI provided.
  • あなたのライトサイクルはAIが出力した方向に動きます。
  • At this point your AI should wait for your next game turn information and so on and so forth. In the mean time, the AI of the other players will receive information the same way you did.
  • この時点で、あなたのAIは次のゲームターンの情報を待たなければなりません。後は、ここまでの繰り返しとなります。一方で、他のプレイヤーのAIもあなたと同様に情報を受け取ります。

If your AI does not provide output fast enough when your turn comes, or if you provide an invalid output or if your output would make the light cycle move into an obstacle, then your program loses.

もし、あなたのAIがあなたのターンが来た時に、十分高速に出力を提供できない場合、または妥当でない出力をした場合、または出力に従うとライトサイクルが障害物に衝突してしまう等の場合には、あなたのプログラムの負けとなります。

If another AI loses before yours, its light ribbon disappears and the game continues until there is only one player left.

もし他のAIがあなたより前に負けた場合は、その光のリボンは消滅し、一人のプレイヤーのみが残るまでゲームは継続します。

The game grid has a 30 by 20 cells width and height. Each player starts at a random location on the grid.

ゲームグリッドは、30x20 のセルで構成されます。それぞれのプレイヤーはグリッド上のランダムな位置からスタートします。

◎Victory Conditions
◎勝利条件

Be the last remaining player
最後まで残るプレイヤーとなること。

◎Game Input
◎ゲームの入力

Input for one game turn
ゲームターン毎の入力

Line 1: Two integers N and P. Where N is the total number of players and P is your player number for this game.

一行目: N と P の2つの整数。Nはプレイヤーの総人数で、Pはこのゲームでのプレイヤー番号です。

The N following lines: One line per player. First line is for player 0, next line for player 1, etc. Each line contains four values X0, Y0, X1 and Y1. (X0, Y0) are the coordinates of the initial position of the light ribbon (tail) and (X1, Y1) are the coordinates of the current position of the light ribbon (head) of the player. Once a player loses, his/her X0 Y0 X1 Y1 coordinates are all equal to -1 (no more light ribbon on the grid for this player).

続くN行: プレイヤー毎に一行。最初の行はプレイヤー0に対するもの、次の行はプレイヤー1、という形になります。それぞれの行は4つの値 X0, Y0, X1, Y1 を含みます。(X0, Y0) は光のリボンの初期位置(tail)で (X1, Y1) はプレイヤーの光のリボンの現在位置(head)です。あるプレイヤーの負けが決定すると、そのプレイヤーの X0 Y0 X1 Y1 の値hあ全て -1 となり、そのプレイヤーの光のリボンはグリッド上には存在しないことを意味します。

Output for one game turn
ゲームターン毎の出力

A single line with UP, DOWN, LEFT or RIGHT

UP, DOWN, LEFT, RIGHT のいずれかを一行で出力。

Constraints
制約

2 ≤ N ≤ 2
0 ≤ P < N
0 ≤ X0, X1 < 30
0 ≤ Y0, Y1 < 20

Your AI must answer in less than 100ms for each game turn.
あなたのAIは各ゲームターンに対して100ms未満で応答しなければなりません。

10. とりあえず、壁への激突、リボンへの激突を避ける目的で作ったプログラム

まったくAI的なことしてませんが、ゲームターン毎に隣(上下左右)のセルだけ見て、障害物がなければそちらに進む(判定順序: 左⇒右⇒上⇒下)。毎ターン、自キャラも含めて位置情報を二次元配列に格納(死んだキャラのリボン情報の消去も一応実装済み。初期は2キャラしかいないのでテストできませんw)。

  • コメントに大体書いたので一点だけ補足すると、ライトサイクルが曲がるとき90°までしか曲がれない(来た方向に戻るようなことはできない)というのをどう表現しようかと迷っていたんですが、自キャラの光のリボンも配列(マップ)に記録して障害物と見做しているので、とりあえず障害物判定するだけでいける方向に進めば良いことだと気づきました。
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;

class Player
{
    static void Main(string[] args) {
        Player control = new Player();
        string[] inputs;
        Position[] positions;
        // game loop
        while (true) {
            inputs = Console.ReadLine().Split(' ');
            int N = int.Parse(inputs[0]); // total number of players (2 to 4).
            int P = int.Parse(inputs[1]); // your player number (0 to 3).
            Console.Error.WriteLine("P={0}", P);
            positions = new Position[N];
            for (int i = 0; i < N; i++) {
                inputs = Console.ReadLine().Split(' ');
                int X0 = int.Parse(inputs[0]); // starting X coordinate of lightcycle (or -1)
                int Y0 = int.Parse(inputs[1]); // starting Y coordinate of lightcycle (or -1)
                int X1 = int.Parse(inputs[2]); // starting X coordinate of lightcycle (can be the same as X0 if you play before this player)
                int Y1 = int.Parse(inputs[3]); // starting Y coordinate of lightcycle (can be the same as Y0 if you play before this player)
                positions[i] = new Position(i, X0, Y0, X1, Y1);
            }
            string dir = control.HandleVehicless(positions, P);
            control.DumpMap();
            Console.WriteLine(dir);
        }
    }
    // 自分も含めて誰かが通った座標を記憶しておくために使う。
    // 誰も通ってない場合は -1。通った、または現在いるマスに対してはプレイヤーのメンバーIDを格納する。
    int[,] map = new int[30,20];
    // メインコントロールクラスのコンストラクタ(map内の値を-1(=誰も通ってない)に初期化しておく。)
    private Player() {
        for(int y=0; y<20; y++) {
            for(int x=0; x<30; x++) {
                map[x, y] = -1;
            }
        }
    }
    private string HandleVehicless(Position[] positions, int myIndex) {
        Position me = positions[myIndex]; // me = 自分の座標情報
        Console.Error.WriteLine(me); // me を標準エラーに出力(public override string ToString()の定義による)
        foreach(var p in positions) { // (me も含めて)全キャラの座標を通ってはいけない場所に登録。
            AddToMap(p); // ただし、死にキャラの場合はそのキャラの座標情報を全消去する。
        }
        // 上下左右のマスを判定し通ってはいけない場所でなければその方向を返す。
        if (!FoundFromMap(me, -1, 0)) return "LEFT";
        if (!FoundFromMap(me, 1, 0)) return "RIGHT";
        if (!FoundFromMap(me, 0, -1)) return "UP";
        if (!FoundFromMap(me, 0, 1)) return "DOWN";
        return "LEFT"; // ここに来た時点でどの方向も通れないが一応正式な値の一つとして "LEFT" を返す。
    }
    void AddToMap(Position p) {
        if (p.X1 < 0) {
            DeleteMemberIdsFromMap(p.Id); // 現在座標がマイナス値で来たら死にキャラなのでマップから消す。
            return;
        }
        this.map[p.X1, p.Y1] = p.Id; // 配列にプレイヤーのメンバーIDを登録する。
    }
    void DeleteMemberIdsFromMap(int id) {
        for(int y=0; y<20; y++) {
            for(int x=0; x<30; x++) {
                if (map[x, y] == id) map[x, y] = -1;
            }
        }
    }
    // map を検索して通れない場所の場合 true を返す。通れる場合は false。
    // me(自機の座標)に xOffset と yOffset を加えた場所について判定(検索)する。
    bool FoundFromMap(Position me, int xOffset, int yOffset) {
        int x = me.X1+xOffset;
        int y = me.Y1+yOffset;
        if (x < 0) return true;
        if (x > 29) return true;
        if (y < 0) return true;
        if (y > 19) return true;
        return map[x, y] != -1;
    }
    // デバッグ用に 30x20 のマップを表示(現在生きているメンバーのIDを表示。空のマスは '-' を出力)
    void DumpMap() {
        for(int y=0; y<20; y++) {
            for(int x=0; x<30; x++) {
                if (map[x, y] == -1) Console.Error.Write("-"); // -1の場合はマイナス記号を出力。
                else Console.Error.Write(map[x, y]); // -1でなければプレイヤーID(0以上)を出力。
                Console.Error.Write(" ");
            }
            Console.Error.WriteLine();
        }
    }
}
// キャラクターの座標を登録・記憶しておくための入れ物。
// Main 関数が受け取る標準入力の情報を格納するための構造体のようなもの。
// Player インスタンスの各メソッドの引数は標準入力とのやり取りを意識せず、この構造体を期待できる。
class Position
{
    public int Id;
    public int X0;
    public int Y0;
    public int X1;
    public int Y1;
    public Position(int id, int x0, int y0, int x1, int y1)
    {
        this.Id = id;
        this.X0 = x0;
        this.Y0 = y0;
        this.X1 = x1;
        this.Y1 = y1;
    }
    // デバッグなどで出力される際のフォーマットを制御する。
    public override string ToString()
    {
        //return "{X0:" + X0 + ", Y0:" + Y0 + ", X1:" + X1 + ", Y1:" + Y1 + "}";
        return String.Format("{{X0:{0}, Y0:{1}, X1:{2}, Y1:{3}}}", X0, Y0, X1, Y1);
    }
}

11. アリーナでリーグ戦をする前に「PLAY MY CODE」ボタンで確認

image.png

12. 対戦実行速度を上げてサクサクデバッグ

image.png

image.png

13. アリーナ(リーグ戦)に挑戦

image.png

image.png

14. リーグ戦でボスに勝ったら以下のような画面が表示されます

  • 最初のリーグではプレイヤーの数は2ですが、リーグが上がっていくと増えていくみたいです。

image.png

15. リーグ戦で勝てず上位リーグに上がれなかった場合の対処法

image.png

image.png

image.png

image.png

他にも負けた相手がいる場合には、同様の手順でIDEに読み込んで対戦しながらプログラム(AI)を強くするとよいでしょう。

16. 最後に

AIを作るノウハウを持っていないことと、強いプログラムを記事で晒すのはいいアイディアではないかなと思ってますので、今回は TRON BATTLE を紹介しましたが、次はまた別のプログラムについて紹介したいと思っています。以下のツイートの画像をクリックしていただければ、そのゲームのリプレイ画面が表示されます。
もし、分かりにくいところなどありましたらコメント等をよろしくお願いいたします。それでは…

P.S.

https://www.codingame.com/multiplayer/bot-programming/tron-battle/leaderboard

image.png

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

じゃんけんゲームjava練習

Jankengame.java
import java.util.Scanner;

public class Jankengeme {

    public static void main(String[] args) {

        int playerHand;
        int cpuHand;
        Scanner sc = new Scanner(System.in);
        String rpfHands[] = {"グー","チョキ","パー"};
        int replay;
        int replay2=1;

     try {
        do{


        //プレイヤー側の処理

        System.out.println("数字を入力してください。0:グー、1:チョキ、2:パー");
        playerHand = sc.nextInt(); //標準入力で数字を入力させる
        System.out.println("あなたの出した手は" + rpfHands[playerHand]); //プレイヤーの手出力

        //コンピュータ側の処理

         cpuHand = (int)(Math.random()*3); //ランダムメソッドでコンピュータの出す手を決める
         System.out.println("コンピュータの出した手は" + rpfHands[cpuHand]); //コンピュータの手出力

         //判定

         Result result1 = new Result();
         result1.result(cpuHand,playerHand);

         System.out.println("もう一度やりますか? 0:はい 1:いいえ");

         replay = sc.nextInt();

      }while(replay!=replay2);

            } catch( java.lang.ArrayIndexOutOfBoundsException e) {

                System.err.println("エラー" + e.getMessage());

                } finally {

                        System.out.println("終了します");
                    }

                        sc.close();
        }
}
Result.java

public class Result {

       String result;
       int rock = 0;
       int scissors = 1;
       int paper = 2;

        public void result(int a, int b){

            if(a == b){

                result = "あいこです";

            }else if((a == rock && b == scissors) || (a == scissors && b == paper ) ||
                    (a == paper && b == rock )){

                result = "コンピュータの勝ち。あなたは負け";


            }else if((a == rock && b == paper) || (a == scissors && b == rock ) ||
                    (a == paper && b == scissors )){

                result = "あなたはの勝ち。コンピュータの負け";


        }

            System.out.println(result);

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