平成19年 春期 基本情報技術者 午後 問12
問12 Java次の Java プログラムの説明及びプログラムを読んで,設問1,2に答えよ。
〔プログラムの説明〕 三目並べを行うプログラムである。 盤は 3 × 3 の升(ます)目をもち,2人のプレーヤは交互に自分の記号( o 又は x )を書く。 たて,横,斜めでの三つの升の並びを列と呼び,先に,どれかの列で三つの升すべてに, 自分の記号を書いた方を勝ちとする。 また,盤のすべての升に記号が書かれていて,どちらの勝ちでもないときは,引き分けとする。 先手は o ,後手は x を使う。 先手(o)が勝ちの例を図1に示す。
図 1 先手(o)が勝ちの例 列挙型 Mark は記号を表し,先手は Mark.CIRCLE,後手は Mark.CROSS を使うこととする。 また,升に何も書かれていない状態を Mark.BLANKで表す。 クラス TicTacToeBoard は盤を表し,(1) 〜 (4) のメソッドをもつ。 (1) Progress put(int x, int y, Mark mark)
Progress.CROSS_WON ― 後手の勝ち Progress.DRAWN ― 引き分け Progress.IN_PROGRESS ― 進行中
@ 指定位置に既に記号が書かれている。 A 指定された記号が書けるプレーヤの番ではない。 (2) boolean check(int x, int y, int dx, int dy, Mark mark) 検査する。位置 (x, y),(x + dx, y + dy),(x + 2 * dx, y + 2 * dy) の三つの升に書かれている記号が,mark と等しければ true を返す。 (3) Mark get(int x, int y) (4) void undo()
図2 実行結果の一部 〔参考:列挙(enum)について〕 プログラム中の Mark と Progress はそれぞれ列挙型であり,列挙型 Mark は 三つの列挙定数 CIRCLE,CROSS,BLANK を,列挙型 Progress は四つの 列挙定数 CIRCLE_WON,CROSS_WON,DRAWN,IN_PROGRESS をもつ。 列挙型はクラスの。 一種であり,列挙定数は列挙型のインスタンスである。 〔プログラム1〕 public enum Mark { // 記号の種類を表す列挙。各列挙定数では定数 symbol を定義する。 // 定数 symbol の値は各コンストラクタで与えられた値('o'など)である。 CIRCLE('o'), CROSS('x'), BLANK(' '); public final char symbol; Mark(char symbol) { this.symbol = symbol; } } 〔プログラム2〕 public class TicTacToeBoard { // ゲームの進行状況を表す列挙 public enum Progress {CIRCLE_WON, CROSS_WON, DRAWN, IN_PROGRESS} private Mark[][] board = new Mark[3][3]; // 盤 private Mark turn = Mark.CIRCLE; private Progress progress = Progress.IN_PROGRESS; private int count = 0; // 盤に書かれた記号の個数 private int lastx, lasty; // 最後に記号が書かれた位置を保持する。 public TicTacToeBoard() { // 盤を初期化する。 for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) board[i][j] = ; } public synchronized Progress put(int x, int y, Mark mark) { if () throw new IllegalStateException(); if (board[x][y] != Mark.BLANK || mark != turn) throw new IllegalArgumentException(); board[x][y] = mark; lastx = x; lasty = y; count++; // 勝ちか否かを検査する。 boolean game = // たてと横の列を検査する。 check(x, 0, 0, 1, mark) || check(0, y, 1, 0, mark) || // 斜めの列を検査する。 check(0, 0, 1, 1, mark) || check(0, 2, , mark); if (game) if (turn == Mark.CIRCLE) progress = Progress.CIRCLE_WON; else progress = Progress.CROSS_WON; else if (count == 9) progress = Progress.DRAWN; // 次に書かれる記号の種類を決定する。 if (turn == Mark.CIRCLE) turn = Mark.CROSS; else turn = Mark.CIRCLE; return progress; } private boolean check(int x, int y, int dx, int dy, Mark mark) { return (board[x][y] == mark && board[x + dx][y + dy] == mark && board[x + 2 * dx][y + 2 * dy] == mark); } public Mark get(int x, int y) { return board[x][y]; } public synchronized void undo() { if (progress == Progress.IN_PROGRESS && board[lastx][lasty] != Mark.BLANK) { turn = board[lastx][lasty]; board[lastx][lasty] = Mark.BLANK; count--; } else { throw new IllegalStateException(); } } } 〔プログラム3 〕 public class TicTester { public static void main(String[] args) { // 記号を書く位置(x, y)を定義した配列。null のときは undo を呼ぶ。 int[][] p = {{0, 0}, {1, 1}, {2, 2}, {2, 0}, {0, 2}, {1, 2}, {2, 1}, null, {0, 1}, {1, 0}}; TicTacToeBoard board = new TicTacToeBoard(); Mark marks[] = {Mark.CIRCLE, Mark.CROSS}; for (int i = 0; i < p.length; i++) { try { if (p[i] == null) { System.out.println("undo"); board.undo(); } else { Mark turn = marks[]; System.out.println("Turn : " + turn + " : " + board.put(p[i][0], p[i][1], turn)); } for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) System.out.print(board.get(x, y).symbol + " "); System.out.println(); } } catch (IllegalStateException ise) { System.out.println("Game is over."); } } } } 設問1 プログラム中の に入れる正しい答えを, 解答群の中から選べ。
a に関する解答群 ア Mark.BLANK イ Mark.CIRCLE ウ Mark.CROSS エ null b に関する解答群 ア count < 0 イ count >= 9 ウ progress != Progress.IN_PROGRESS エ progress == Progress.IN_PROGRESS c に関する解答群 ア -1, -1 イ -1, 1 ウ 1, -1 エ 1, 1 d に関する解答群 ア i イ i % 2 ウ i & 2 エ i / 2
設問2 クラス TicTacToeBoard のメソッド undo に関する記述として正しい答えを, 解答群の中から二つ選べ。
解答群 ア 2手目以降で続けて2回呼ぶと,二つ消せる。 イ 2手目以降で続けて2回呼ぶと,呼ばなかった状態に戻る。 ウ 2手目以降で続けて2回呼んでも,消せるのは一つだけである。 エ ゲーム中で先手後手とも,それぞれ1回しか消せない。 オ 消すことができなければ例外を投げる。 [←前の問題] [次の問題→] [問題一覧表] [分野別] [基本情報技術者試験TOP ] | ||||||||||