昔は、プログラミング技術やアルゴリズムといえば、たくさんのパソコン雑誌が会ったのでそこから得ていましたが、パソコンという高価なものを購入する必要がありました1。
現代は、プログラミングのための障壁の高さはぐんと落ちて、多くの人が簡単にプログラミング出来るような環境ができましたが、こんどはインターネット上の多くの情報に混乱させられたり、はたまた、情報商材なるもので甘い言葉でプログラミング初心者を釣っている感もある昨今、私が時々つかっているのが・・
paizaラーニング。
頭の運動になると思って時々、スキルチェックのために使ったりしているのだけれども、最近、問題集なるものがあるのを発見したので、時々気分転換にやっています。
スキルチェック問題は、ランクに応じて解答時間に制限があるうえ、Bランク、Aランクの問題になると、結構まとまった時間がないとできないのもありおいそれと挑戦できない(途中でキャンセルすると、それが成績になってしまう!)ので、気軽にいつでも楽しめる問題集を楽しんでいます。
それに、スキルチェックの問題は、ブログ等で、その内容等を書くと規約違反になるようですが、問題集の方は特にそういった制限はないみたい。
というわけで、私も恥ずかしげもなく自分のコードをあげてみました。
いびつなリバーシ対戦
問題の内容は、こちらのページ(Java 版)にありますが、内容を見るのには無料でアカウントを作成しておく必要があります。
問題の概要は以下のとおりです。
1 から N のプレイヤー番号が与えられた N 人でいびつなオセロの対戦をします。
盤面・ゲームをする人数・合計のターン数・各行動についての情報が与えられます。
盤面に穴の空いているマスは '#' , 何も置かれていないマスは '.' になっています。プレイヤー達は、各行動ごとに次の操作をおこないます。
・ 盤面のマス(Y_i, X_i)に石を置く。既に相手の石が置かれている場合は相手の石を自分の石に置き換える。
・ 次に、縦横斜めに自分の石ではさんだ連続した穴の空いていないマスに自分の石を置きます。相手の石が置かれている場合は相手の石を自分の石に置き換えて、操作を終了する。操作を終えた後の盤面を出力してください。
ただし、番号 i のプレイヤーの石のあるマスを i として出力してください。なお、マスの座標系は左上端のマスの座標を ( y , x ) = ( 0 , 0 ) とし、
下方向が y 座標の正の向き、右方向が x 座標の正の向きとします。
この問題は、「Aランクレベルアップメニュー」の一連の問題の一つ、「いびつなリバーシ対戦」のファイナル問題になります。
本当は、その前に8ステップの項目ごとの問題を学習していった結果として解いていく問題なのですが、そちらの方は別途「チケット」が必要になるので、やってません。すっ飛ばしています(ちなみに、チケットは登録後標準で5チケットありますが、それ以降は購入する必要があるみたいです)。
なので、私の書いているコードは paiza 側が求めている意図とは異なる恐れがあります。
Java コード
以下がそのコードです。
何をしているのかは、コメントに書いています。
もう少し数学的に解ければなと思うのですが、学生時代に数学をおざなりにしてきた結果ですね。
もしも参考になれば幸いです。
import java.util.*;
public class Main {
private int H; // 行数(Y)
private int W; // 桁数(X)
private int N; // プレイヤー数
private int n; // 全ターン数
// ベースマップ
String[][] baseMap;
// 駒の配置マップ
String[][] playerMap;
// 各ターンのコマンド
String[] commands;
// 探索する8方向のベクトル
private final Object[] vecs = new Object[] {
new int[] {0, -1}, // 上
new int[] {1, -1}, // 右上
new int[] {1, 0}, // 右
new int[] {1, 1}, // 右下
new int[] {0, 1}, // 下
new int[] {-1, 1}, // 左下
new int[] {-1, 0}, // 左
new int[] {-1, -1} // 左上
};
public static void main(String[] args) throws Exception {
Main main = new Main();
main.init(); // 初期化
main.play(); // ゲームを実行
main.display(); // 盤を表示
}
/**
* ゲームを実行する
*/
public void play() {
// コマンドをループで実行
for (int i = 0; i < n; i++ ) {
String[] command = commands[i].split("\\s+");
// コマンドの内容を取得
int player = Integer.valueOf(command[0]); // プレイヤー
int row = Integer.valueOf(command[1]); // 行No.
int col = Integer.valueOf(command[2]); // 列No.
// プレイヤーのコマを配置
if (!put(player, row, col)) continue; // 配置できなかった場合はスキップ
// プレイヤーのコマの周囲8方向を探索
for (Object o : vecs) {
int[] vec = (int[]) o;
// 横と縦のサイズのうち短い方の値
int min = (H <= W) ? H : W;
// 探索限度カウンタ
int limit;
if (vec[0] != 0 && vec[1] != 0) {
// 斜め方向の探索の場合は、短辺サイズに
limit = min;
} else if (vec[0] == 0 && vec[1] != 0) {
// Y軸方向の探索
limit = H;
} else {
// X軸方向の探索
limit = W;
}
// プレイヤーコマから近い順のセルリスト
List<String> cells = new ArrayList<>();
for (int j = 0; j < limit; j++) {
int px = col + (vec[0] * j);
int py = row + (vec[1] * j);
// 探索位置が境界を超えたら探索をスキップ
if (px > (W - 1) || px < 0 || py > (H - 1) || py < 0) break;
// 探索位置のベースマップを取得
String base = baseMap[px][py];
// '#'(石)の場合は探索をスキップ
if (base.equals("#")) break;
// 探索位置のピース:現在位置のプレイヤーマップの値が NULL の場合は空文字列
// にする
String piece = playerMap[px][py] != null ? playerMap[px][py] : "";
// セルリストに探索位置のピースを追加
cells.add(piece);
}
// コマ配置可能なセル数
int reversable = 0;
for (int j = 0; j < cells.size(); j++) {
// 一番最初のセルは、自分自身なのでスキップ
if (j == 0) continue;
// セルリストを順にチェックし、プレイヤーと同じコマがあった場合は配置可能な
// セル数をセットした上で以降の処理をスキップ
if (cells.get(j).equals(String.valueOf(player))) {
reversable = j;
break;
}
}
// 配置可能なセル数に基づいて、プレイヤーのコマを配置
for (int j = 0; j < reversable; j++) {
if (j == 0) continue;
int px = col + (vec[0] * j);
int py = row + (vec[1] * j);
put(player, py, px);
}
}
}
}
/**
* プレイヤーの駒を配置する
*
* @param player ユーザー
* @param row 盤の行番号(Y軸)
* @param col 盤の列番号(X軸)
* @return 駒を配置できなかった場合に False
*/
public boolean put(int player, int row, int col ) {
if (isPlaceable(row, col)) {
playerMap[col][row] = String.valueOf(player);
return true;
}
return false;
}
/**
* プレイヤーの駒を配置できるかどうか
*
* @param row 盤の行番号(Y軸)
* @param col 盤の列番号(X軸)
* @return 駒を配置できる場合に TRUE
*/
public boolean isPlaceable(int row, int col) {
if (baseMap[col][row].equals("#")) return false;
return true;
}
/**
* 初期化処理
*/
public void init() {
Scanner sc = new Scanner(System.in);
String[] line = sc.nextLine().split("\\s+");
// 変数の初期化
H = Integer.valueOf(line[0]);
W = Integer.valueOf(line[1]);
N = Integer.valueOf(line[2]);
n = Integer.valueOf(line[3]);
// System.out.println("H: " + H + ", W: " + W );
// 配列の確保
baseMap = new String[W][H];
playerMap = new String[W][H];
commands = new String[n];
// ベースマップの作成
for (int i = 0; i < H; i++) {
char[] charArray = sc.nextLine().toCharArray();
for (int j = 0; j < W; j++) {
baseMap[j][i] = String.valueOf(charArray[j]);
}
}
// コマンドリスト作成
for (int i = 0; i < n; i++) {
commands[i] = sc.nextLine();
}
}
/**
* 盤の表示
*/
public void display() {
for (int i = 0; i < H; i++) {
StringBuffer sb = new StringBuffer();
for (int j = 0; j < W; j++) {
String base = baseMap[j][i];
String player = playerMap[j][i];
if (player == null || player.trim().equals("")) {
sb.append(base);
} else {
sb.append(player);
}
}
System.out.println(sb.toString());
}
}
}
-
1980年代、当時のパソコンはまだ高価なものでした。 ↩
0件のコメント