// 2012-01-13T13:15+09:00
// Cell.toggleLightとかCell.setStatusまわり、依存関係が逆だったので修正
import java.io.*;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
// JavaDoc?なんですかそれは?(書式を学ぶのが面倒だなーと[おぃ])
enum Status{
BLANK,
LIGHT,
UNNUMBERED,
NUMBERED
}
// 位置情報をCellに持たせるか悩んだんだけど、やめた。それはCellの都合じゃなくてGameの都合のような気がしたから。
// game.findCellPositionなんてのやgame.getCellとかがくっ付くし、Positionクラスなんてのを作る羽目になったけど…
class Cell{
// そのセルの周囲に置けるライトの数だが、
// 実際に置けないのではなく、
// これは正解かどうかをチェックするルーチンで用いるつもりである。
// statusがStatus.NUMBEREDでないときは使われない。
private int maxlights;
// あまりマジックナンバーを使いたくなかったんで別に分けてる
private Status status;
// 他のセルが変更された時、ボタンの背景色を変える必要があるんだけど
// CellやGameはあくまでコア。JButtonのような、UIは関係ないので持たせたくなかった。
// 苦肉の策で、直接持たない代わりに、EventListenerインターフェースを実装したクラスに
// 持たせることにした。(俺は不勉強なんですが、何かのデザインパターンにあったりします?)
// こういう「取り出すだけ、設定するだけのsetterやgetterは無駄。publicなメンバ変数だけでいいじゃん」という意見の人もいる。
// 特に反対はしない。
public Status getStatus(){
return status;
}
public void setStatus(Status s){
status = s;
}
public int getMaxLights(){
return maxlights;
}
public void setMaxLights(int lights){
maxlights = lights;
if(maxlightschangedlistener == null){
return;
}
maxlightschangedlistener.maxLightsChanged(new MaxLightsChangedEvent(this,lights));
}
// さっき出したListenerの話がこの辺。
LightToggledListener lighttoggledlistener;
LightTogglingPropagatedListener lighttogglingpropagatedlistener;
MaxLightsChangedListener maxlightschangedlistener;
public void addLightToggledListener(LightToggledListener listener){
lighttoggledlistener = listener;
}
public void addLightTogglingPropagatedListener(LightTogglingPropagatedListener listener){
lighttogglingpropagatedlistener = listener;
}
public void addMaxLightsChangedListener(MaxLightsChangedListener listener){
maxlightschangedlistener = listener;
}
public void propagateLightToggling(Status s){
if(lighttogglingpropagatedlistener == null){
return;
}
lighttogglingpropagatedlistener.lightTogglingPropagated(new LightTogglingPropagatedEvent(this,s));
}
public void toggleLight(Status s){
if(lighttoggledlistener == null){
return;
}
lighttoggledlistener.lightToggled(new LightToggledEvent(this,s));
}
}
public void lightToggled(LightToggledEvent ev);
}
Status status;
public LightToggledEvent
(Object source,Status s
){ super(source);
status = s;
}
public Status getStatus(){
return status;
}
}
interface LightTogglingPropagatedListener
extends java.
util.
EventListener{ public void lightTogglingPropagated(LightTogglingPropagatedEvent ev);
}
class LightTogglingPropagatedEvent
extends EventObject{ Status status;
public LightTogglingPropagatedEvent
(Object source,Status s
){ super(source);
status = s;
}
public Status getStatus(){
return status;
}
}
interface MaxLightsChangedListener
extends java.
util.
EventListener{ public void maxLightsChanged(MaxLightsChangedEvent ev);
}
int maxlights;
public MaxLightsChangedEvent
(Object source,
int maxlights1
){ super(source);
maxlights = maxlights1;
}
public int getMaxLights(){
return maxlights;
}
}
// あまり好きじゃない。
private int row;
private int col;
row = row1;
col = col1;
}
public int getRow(){
return row;
}
public int getColumn(){
return col;
}
}
//これも正直苦肉の策
class CellInitializationData{
Status status;
int maxlights;
CellInitializationData(int row,int col,int lights){
if(lights < -1){
}
if(lights == -1){
status = Status.UNNUMBERED;
return;
}
status = Status.NUMBERED;
maxlights = lights;
}
public int getMaxLights(){
return maxlights;
}
public Status getStatus(){
return status;
}
return position;
}
}
// 初期配置データ読み込み用クラス。まぁGameクラスに統合しても良かったけどね。
class GameDataReader{
java.util.List<CellInitializationData> list = new ArrayList<CellInitializationData>();
while (true){
int row;
int col;
int lights;
row
= Integer.
parseInt(reader.
readLine()); col
= Integer.
parseInt(reader.
readLine()); lights
= Integer.
parseInt(reader.
readLine());
list.add(new CellInitializationData(row,col,lights));
if(reader.readLine() == null){
break;
}
}
return list;
}
}
// ゲーム本体
class Game
{
private Cell cells[][] = null;
// 初期配置のために第一引数を持たせる予定。でも、設計があまりよくならなそうなんだよなあ。どうしようかなあ。
public Game(int rows,int cols){
cells= new Cell[rows][cols];
for(int i = 0;i < rows;i++){
for(int j = 0;j < cols;j++){
cells[i][j] = new Cell();
}
}
}
public void Initialize(java.util.List<CellInitializationData> list){
for(int i = 0;i < cells.length;i++){
for(int j = 0;j < cells[i].length;j++){
Cell c = cells[i][j];
c.setStatus(Status.BLANK);
c.toggleLight(Status.BLANK);
}
}
for(CellInitializationData ci:list){
Cell c = cells[ci.getPosition().getRow()][ci.getPosition().getColumn()];
c.setStatus(ci.getStatus());
c.setMaxLights(ci.getMaxLights());
}
}
public boolean toggleLight(int row,int col){
if(cells[row][col].getStatus() == Status.NUMBERED){
return false;
}
if(cells[row][col].getStatus() == Status.UNNUMBERED){
return false;
}
java.util.List<Cell> list = getLightingArea(row,col);
if(list == null){
return false;
}
if(cells[row][col].getStatus() == Status.BLANK){
cells[row][col].setStatus(Status.LIGHT);
cells[row][col].toggleLight(Status.LIGHT);
for(Cell c:list){
c.propagateLightToggling(Status.LIGHT);
}
}else if(cells[row][col].getStatus() == Status.LIGHT){
cells[row][col].setStatus(Status.BLANK);
cells[row][col].toggleLight(Status.BLANK);
for(Cell c:list){
// その場所にライトが置ける => その場所はそのライトのみによって照らされていた場所
if(getLightingArea(p.getRow(),p.getColumn()) != null){
c.propagateLightToggling(Status.BLANK);
}
}
}
return true;
}
// 指定された位置にライトを置いたときにそのライトによって照らされる範囲を返す。
// 指定された位置が既に他のライトによって照らされているときはnullを返す。(要素数0のリストのほうがいいだろうか?)
private java.util.List<Cell> getLightingArea(int row,int col){
java.util.List<Cell> list = new ArrayList<Cell>();
for(int i = row-1;i >= 0;i--){
if(cells[i][col].getStatus() == Status.LIGHT){
return null;
}
if(cells[i][col].getStatus() != Status.BLANK){
break;
}
list.add(cells[i][col]);
}
for(int i = row+1;i < cells.length ;i++){
if(cells[i][col].getStatus() == Status.LIGHT){
return null;
}
if(cells[i][col].getStatus() != Status.BLANK){
break;
}
list.add(cells[i][col]);
}
for(int i = col-1;i >= 0;i--){
if(cells[row][i].getStatus() == Status.LIGHT){
return null;
}
if(cells[row][i].getStatus() != Status.BLANK){
break;
}
list.add(cells[row][i]);
}
for(int i = col+1;i < cells[0].length;i++){
if(cells[row][i].getStatus() == Status.LIGHT){
return null;
}
if(cells[row][i].getStatus() != Status.BLANK){
break;
}
list.add(cells[row][i]);
}
//list.add(cells[row][col]);
return list;
}
public Position findCellPosition
(Cell c
){ for(int i = 0;i < cells.length ;i++){
for(int j = 0;j < cells[i].length ;j++){
if(cells[i][j] == c){
return retval;
}
}
}
}
public Cell getCell(int row,int col){
return cells[row][col];
}
}
//ここまでCore
//ここからUI
// 名前は悩んでます。
Game game;
CellButton[][] buttons;
game = new Game(10,10);
setTitle("美術館パズル");
setSize(800,600);
setDefaultCloseOperation
(JFrame.
EXIT_ON_CLOSE); setResizable(false);
add(panel);
buttons = new CellButton[10][10];
for(int i=0; i<10; i++) {
for(int j=0; j<10; j++) {
buttons[i][j] = new CellButton(game.getCell(i,j));
buttons[i][j].addActionListener(this);
panel.add(buttons[i][j]);
}
}
}
//コアとUIを繋いでいる。MVCモデルとかあまり学んでないけどCにあたるのかなあ?
CellButton button = (CellButton)ae.getSource();
Position p
= game.
findCellPosition(button.
getCell()); game.toggleLight(p.getRow(),p.getColumn());
}
}
Cell c;
public CellButton(Cell c1){
c = c1;
c.addLightToggledListener(new ButtonCellLightToggledListener(this));
c.addLightTogglingPropagatedListener(new ButtonCellLightTogglingPropagatedListener(this));
c.addMaxLightsChangedListener(new ButtonCellMaxLightsChangedListener(this));
}
public Cell getCell(){
return c;
}
}
//コアとUIを繋いでいる。MVCモデルとかあまり学んでないけどCにあたるのかなあ?
class ButtonCellLightTogglingPropagatedListener implements LightTogglingPropagatedListener{
public ButtonCellLightTogglingPropagatedListener
(JButton b1
){ b = b1;
}
// 引数は本当はもっとまともなものにしたい。
public void lightTogglingPropagated(LightTogglingPropagatedEvent ev){
if(ev.getStatus() == Status.BLANK){
b.
setBackground(java.
awt.
Color.
GREEN); }else if(ev.getStatus() == Status.LIGHT){
b.
setBackground(java.
awt.
Color.
RED); }
}
}
class ButtonCellLightToggledListener implements LightToggledListener{
public ButtonCellLightToggledListener
(JButton b1
){ b = b1;
}
// 引数は本当はもっとまともなものにしたい。
public void lightToggled(LightToggledEvent ev){
if(ev.getStatus() == Status.BLANK){
b.
setBackground(java.
awt.
Color.
GREEN); }else if(ev.getStatus() == Status.LIGHT){
b.
setBackground(java.
awt.
Color.
BLUE); }
}
}
class ButtonCellMaxLightsChangedListener implements MaxLightsChangedListener{
public ButtonCellMaxLightsChangedListener
(JButton b1
){ b = b1;
}
// 引数は本当はもっとまともなものにしたい。
public void maxLightsChanged(MaxLightsChangedEvent ev){
b.
setBackground(java.
awt.
Color.
YELLOW); if(((Cell)ev.getSource()).getStatus() == Status.UNNUMBERED){
return;
}
b.
setText(Integer.
toString(ev.
getMaxLights())); }
}
// UIここまで
// あとは単なる起爆地点。
class Main{
{
Form1 f = new Form1();
f.setVisible(true);
}
}