プログラミングしたい日記

いつもプログラミングとか音楽聞いてたりする人の日記です

突発でCODE RUNNER - 予選Bに参加してきた

突発でCODE RUNNNERの予選Bに参加してきました。
この記事も突発で書いた記事なので文章がおかしいかも...?

CODE RUNNERとは

どこまで全力で、走りきれるか!?
参加者全員が同時に対戦する、まったく新しいプログラミングコンテスト始動。どこまで全力で、走りきれるか。文字通り「マラソン」型のバトルです。最後まで勝ち続ける、アルゴリズムを実装し、日本一の学生プログラマに輝け!

ニコニコ生放送(予選B): CODE RUNNER 予選B 実況中継 - 2014/11/02 19:30開始 - ニコニコ生放送

参加の意図

暇だったので、「プログラミング」とニコニコ生放送で検索したらたまたまこの放送が引っかかり、「これ面白そう」と思ったので競技数分前に準備して参加しました。(なんでこんなタイミングに...って思われそう(笑))

NetBeansが偶然起動していたのでプロジェクト作ってクラス作って参加しました。

どんな感じのコードを書いたか

使った言語はもちろんJavaです。他のやつはわからないし時間の無駄だと思ったので使いませんでした。

まずは、とにかく点を取っておこうと無限ループ+sleep(1250)程度でattackしていました。
これでは点を取れないので、部屋が変わらない限りは

FOR (J = 0; J < 2; J++) {
 IF (J == 0) {
  攻撃するSKILLIDを1追加して攻撃。もし使ったやつが今まで使った中で一番攻撃力が高ければそのIDを保存。
 } ELSE {
  今まで使った中で一番攻撃力が戦ったIDで攻撃
 }
}

みたいな感じのコードで戦っていました。

しかし、このコードにはバグがあり、部屋が変わるとなんとダメージが通らなくなってしまうのです。(原因がよくわからなかった)
このバグが、新しいコードを作成している時に発覚したので5分くらいロスしましたし非常にめんどくさかったです...orz

最終的なソースコードは記事の最後に長いですが書いておきます。

トラブルの発生

22:30頃にAPIの受付が非常に悪くなり、TIMEOUTが頻発しました。
もちろん自分だけではなく、他の人も同じような現象が発生していました。
主催エンジニアチームが頑張って対応してくれたのですが、3,4回目で予選Bは打ち切られました...(結果は反映される模様)

まだいけると思ったのですがコードを書き終えた頃にはもう遅かったです...
次回やるのであれば改善してまたやって欲しいですね。

感想

この手の競技プログラミングは初めてですし、とても楽しかったです。
何の準備もせず突発でやったのもありますし、まだまだスキルが低いせいで順位は結構低めでしたorz

次回もあるのであればさっき書いたように、サーバーを改善してまだ戻ってきて欲しいです。
そして、その時には上位にいけるよう頑張りたいです。

書いたコード

クソコードですが...

CodeRunnerクラス(改善前のコード)
package coderunner;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

public class CodeRunner {

  private final static String token = "token=CDVMX93YPR10ESUA9I4JNE9EK2VD23JF";

  private final static String attackURL = "https://game.coderunner.jp/attack?";

  private final static String infoGetURL = "https://game.coderunner.jp/info?";

  public static void main(String[] args) throws MalformedURLException, IOException, InterruptedException {
    for (int i = 0; i <= 99; i++) {
      HttpsURLConnection conn;
      URL url = new URL(attackURL + token + "&skill=" + i);
      conn = (HttpsURLConnection) url.openConnection();
      BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
      String str;
      while ((str = reader.readLine()) != null) {
        System.out.println(str);
      }
      System.out.print(",");
      System.out.println(getUserInfo());
      System.out.println("__-------------------------------__");
      Thread.sleep(1500);
    }
  }

  private static String beforeUserInfo;
  public static boolean changedRoom(String userInfo) throws IOException {
    if (beforeUserInfo == null)
      return false;
    if (beforeUserInfo != null && !getUserInfo().equals(beforeUserInfo)) {
      return true;
    }
    beforeUserInfo = getUserInfo();
    return false;
  }

  public static String getUserInfo() throws MalformedURLException, IOException {
    HttpsURLConnection conn;
    URL url = new URL(infoGetURL + token + "&filter=members&style=text");
    conn = (HttpsURLConnection) url.openConnection();
    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String str;
    while ((str = reader.readLine()) != null) {
      return reader.readLine();
    }
    return null;
  }
}
CodeRunnerV2クラス
package coderunner;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import javax.net.ssl.HttpsURLConnection;

public class CodeRunnerV2 {

  private final static String token = "token=CDVMX93YPR10ESUA9I4JNE9EK2VD23JF";

  private final static String attackURL = "https://game.coderunner.jp/attack?";

  private final static String infoGetURL = "https://game.coderunner.jp/info?";

  private final static HashMap<Integer, DamageList> map = new HashMap<>();

  private static int[] currentRoomDamageList = new int[100];

  private static int beforeRoomNum = -1;

  public static void main(String[] args) {
    while (true) {
      try {
        int maxDamage = 0;
        int maxDamageSkill = 0;
        //スキルをひと通り回す
        for (int i = 0; i < 100; i++) {
          Thread.sleep(1250);

          //SkillIDで攻撃
          int damage = attack(i);

          //最大ダメージを保存
          if (maxDamage < damage) {
            maxDamage = damage;
            maxDamageSkill = i;
            System.out.println("最大ダメージを発見: " + "S-" + i + " D-" + damage);
          }

          //与えたダメージをリストに保存
          if (i < 100) {
            currentRoomDamageList[i] = damage;
          }

          DamageList currentType = null;
          boolean kotei = false;
          //i==15の時にmapの中にあるリストと一致する場合は一番高いダメージを与え続けてそれ以外は最も高いダメージを探しつづける
          if (i == 15) {
            Iterator<DamageList> itDamageList = map.values().iterator();
            while (itDamageList.hasNext()) {
              DamageList damageList = itDamageList.next();
              if (damageList.allMatch(currentRoomDamageList)) {
                currentType = damageList;
                kotei = true;
              }
            }
          }
          //同じ部屋IDがmapに存在すればそれに固定
          Iterator<DamageList> itDamageList = map.values().iterator();
          while (itDamageList.hasNext()) {
            DamageList damageList = itDamageList.next();
            if (damageList.id == getRoom()) {
              currentType = damageList;
              kotei = true;
            }
          }

          //固定モード
          if (kotei == true) {
            //部屋が同じなら固定
            System.out.println("攻撃を固定しました");
            int beforeDamage = -1;
            while (true) {
              int damage_ = attack(currentType.maxDamageId);
              if (damage_ < beforeDamage) {
                break;
              }
              beforeDamage = damage_;
              System.out.println(getRoom());
              Thread.sleep(1250);
            }
            System.out.println("固定を解除しました");
            Thread.sleep(1250);
          } else { //記録モード
            if ((i > 30 && maxDamage > 1000) || i == 98) {
              LinkedList<Integer> l = new LinkedList<>();
              for (int n : currentRoomDamageList) {
                l.add(n);
              }
              DamageList dl = new DamageList();
              dl.damageList = l;
              dl.id = getRoom();
              dl.maxDamageId = maxDamageSkill;
              dl.maxDamage = maxDamage;
              map.put(i, dl);
              currentRoomDamageList = new int[100];
              System.out.println("履歴を記録しました: " + "最大ダメージ: " + maxDamage + "  最大ダメージスキルID: " + maxDamageSkill + l.toString());
              break;
            }
          }

          //部屋変更を検出
          if (changedRoom(getRoom())) {
            int ZEROCount = 0;
            for (int nnn : currentRoomDamageList) {
              if (nnn == 0)
                ZEROCount++;
            }
            if (ZEROCount < 85) {
              LinkedList<Integer> l = new LinkedList<>();
              for (int n : currentRoomDamageList) {
                l.add(n);
              }
              DamageList dl = new DamageList();
              dl.damageList = l;
              dl.id = getRoom();
              dl.maxDamageId = maxDamageSkill;
              dl.maxDamage = maxDamage;
              map.put(i, dl);
              currentRoomDamageList = new int[100];
              System.out.println("履歴を記録しました: " + "最大ダメージ: " + maxDamage + "  最大ダメージスキルID: " + maxDamageSkill + l.toString());
            }
            System.out.println("部屋変更検出");
            break;
          }
          System.out.println(getRoom());

        }
      } catch (InterruptedException | IOException e) {
        System.out.println("Time out OR ERROR!");
        currentRoomDamageList = new int[100];
        e.printStackTrace();
      }
    }
  }

  public static boolean changedRoom(int nowRoom) throws IOException {
    if (beforeRoomNum == -1) {
      beforeRoomNum = nowRoom;
      return false;
    }
    if (beforeRoomNum != nowRoom) {
      beforeRoomNum = nowRoom;
      return true;
    }
    beforeRoomNum = nowRoom;
    return false;
  }

  public static String getMembers() throws MalformedURLException, IOException {
    HttpsURLConnection conn;
    URL url = new URL(infoGetURL + token + "&filter=members&style=text");
    conn = (HttpsURLConnection) url.openConnection();
    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String str;
    while ((str = reader.readLine()) != null) {
      return reader.readLine();
    }
    return null;
  }

  public static int getRoom() throws MalformedURLException, IOException {
    HttpsURLConnection conn;
    URL url = new URL(infoGetURL + token + "&style=text&filter=you");
    conn = (HttpsURLConnection) url.openConnection();
    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String str;
    int c = 0;
    while ((str = reader.readLine()) != null) {
      if (c == 4) {
        return Integer.parseInt(str);
      }
      c++;
    }
    return -1;
  }

  public static int attack(int skillId) throws IOException {
    HttpsURLConnection conn;
    URL url = new URL(attackURL + token + "&skill=" + skillId);
    conn = (HttpsURLConnection) url.openConnection();
    conn.setReadTimeout(12500);
    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String str;
    while ((str = reader.readLine()) != null) {
      int damage = Integer.parseInt(str);
      System.out.println("攻撃: " + "S-" + skillId + " D-" + damage);
      return damage;
    }
    return -1;
  }

}
DamageListクラス
package coderunner;

import java.util.LinkedList;

public class DamageList {

  public int id;
  
  public LinkedList<Integer> damageList;
  
  public int maxDamageId;
  
  public int maxDamage;
  
  public boolean allMatch(int[] damageList) {
    boolean f = true;
    for (int i = 0; i < 10; i++) {
      if (!(this.damageList.get(i) == damageList[i])) {
        f = false;
      }
    }
    return f;
  }
  
}
CSS Design created by satotaka99. Thankyou.