定期的にMineSweeperを実装したくなる病で・・・、JSF2.0(with JBoss)でやりました。
マス目のゲーム盤の表示でちょっと手間取ったので、自分用にメモ書きを残しておきます。
メインのFaceletsはこれ。
index.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"> <ui:composition template="templates/masterLayout.xhtml"> <ui:define name="windowTitle">#{msgs.windowTitle}</ui:define> <ui:define name="head"> <h:outputStylesheet library="css" name="styles.css" /> </ui:define> <ui:define name="content"> <h:form id="form1"> <h:panelGroup id="field"> <div id="clickModeIndicator"> <h:panelGroup id="clickMode"> <f:ajax event="click" listener="#{mineField.clickModeChange}" render="clickMode"> <h:outputLabel value="Click to [OPEN] MARK " rendered="#{mineField.clickMode == 'OPEN'}"> </h:outputLabel> <h:outputLabel value="Click to OPEN [MARK]" rendered="#{mineField.clickMode == 'MARK'}"> </h:outputLabel> </f:ajax> </h:panelGroup> </div> <div> <table border="0" cellspacing="0" cellpadding="0"> <ui:repeat value="#{mineField.rows}" var="row"> <tr> <ui:repeat value="#{row}" var="item"> <td><h:outputLabel value="#{item.toString()}"> <f:attribute name="location" value="#{item.locationCode}" /> <f:ajax event="click" listener="#{mineField.clickPanel}" execute="@form" render=":form1:field" /> </h:outputLabel></td> </ui:repeat> </tr> </ui:repeat> </table> </div> <div id="messages"> <h:outputText value="Watch out!" rendered="#{mineField.status == 'PLAY'}" /> <h:outputText value="Congraturations!" rendered="#{mineField.status == 'FINISHED'}" /> <h:outputText value="Game Over" rendered="#{mineField.status == 'FAILED'}" /> </div> </h:panelGroup> <br/> <div> <h:commandButton action="#{mineField.replay}" value="Replay" /> <h:commandButton action="setup" value="Settings..." /> </div> </h:form> </ui:define> </ui:composition> </html>
<table border="0" cellspacing="0" cellpadding="0"> <ui:repeat value="#{mineField.rows}" var="row"> <tr> <ui:repeat value="#{row}" var="item"> <td><h:outputLabel value="#{item.toString()}"> <f:attribute name="location" value="#{item.locationCode}" /> <f:ajax event="click" listener="#{mineField.clickPanel}" execute="@form" render=":form1:field" /> </h:outputLabel></td> </ui:repeat> </tr> </ui:repeat> </table>
外側のループで#{mineField.rows}を返しているBacking Beanのgetterがこれ。
MineField.java
public List<List<PanelWrapper>> getRows() { List<List<PanelWrapper>> rows = new ArrayList<List<PanelWrapper>>(); for (int y = 0; y < getSizeVertical(); y++) { List<PanelWrapper> row = new ArrayList<PanelWrapper>(); for (int x = 0; x < getSizeHorizontal(); x++) { PanelWrapper panelWrapper = new PanelWrapper(); panelWrapper.setPanel(getPanel(x, y)); panelWrapper.setLocationCode(x + "," + y); row.add(panelWrapper); } rows.add(row); } return rows; }
PanelWrapperは、1枚のパネルについて、パネルの絵柄(Panel)と座標情報(LocationCode)をまとめたオブジェクト。ゲーム盤全体のパネルに対応するPanelWrapperのリストのリストを作って返しています。
<td><h:outputLabel value="#{item.toString()}"> <f:attribute name="location" value="#{item.locationCode}" /> <f:ajax event="click" listener="#{mineField.clickPanel}" execute="@form" render=":form1:field" /> </h:outputLabel></td>
public void clickPanel(AjaxBehaviorEvent event) throws AbortProcessingException { UIComponent component = event.getComponent(); String location = (String) component.getAttributes().get("location"); Pattern p = Pattern.compile("[0-9]+,[0-9]+"); if (!p.matcher(location).matches()) { clickModeChange(event); return; } String[] coordinate = location.split(",", 0); int locationHorizontal = Integer.valueOf(coordinate[0]); int locationVertical = Integer.valueOf(coordinate[1]); (以下略)