IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  XML  >

XForms를 사용하여 Sudoku 게임 구현하기, Part 1: 게임 구현하기 (한글)

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

토론

샘플 코드

영어원문

영어원문


제안 및 의견
피드백

난이도 : 중급

Nicholas Chase, Freelance writer, Backstop Media

2007 년 5 월 29 일

Sudoku가 가장 주목을 받는 새로운 트랜드 중 하나라는 것은 누구나 알고 있습니다. 이 숫자 게임은 컴퓨터나 종이에서 할 수 있고, XPath를 사용하여 하나의 폼에서 데이터를 쉽게 분석할 수 있기 때문에 XForms를 사용하여 Sudoku를 실행할 수 있는 폼을 만드는 것도 가능합니다. 두 편의 기술자료로 구성된 시리즈에서는 서버에서 새로운 게임을 요청하는 게임 클라이언트를 만드는 방법을 설명하고, 게임의 흐름 탐지, 게임의 종료, 현재 게임을 저장하는 방법을 설명합니다. 또한 사용자를 위한 새로운 게임을 만드는 방법도 설명합니다. Part 1에서는 기본적인 게임 클라이언트를 만듭니다. 여러분은 XForms의 기초를 이해하고 있어야 합니다. 참고자료 섹션에는 시작하는 사람들에게 도움이 될 링크들이 제공됩니다. 코드는 Mozilla Firefox XForms 확장에서 작성 및 테스트 되었지만 그 개념은 어떤 구현에나 적용됩니다.

개요

Nick Chase의 developerWorks podcast

developerWorks podcast를 통해서 필자가 설명하는 Sudoku를 만나보십시오!

Sudoku는 지난 2년 전에 미국에서 유명해지기 시작했고, 이것의 기원지인 일본에서 그랬던 것처럼 하나의 현상이 되었다. 가로세로 퍼즐과 비슷한 간단한 게임이지만 숫자를 사용하고 외부에서 단서를 가져올 수 없다는 점에서 다르다. 원리는 그림 1에서 보듯, 그리드(grid) 판에 여러 숫자들이 제공된다.


그림 1. Sudoku 게임 샘플
Sudoku 게임 샘플

모든 행, 컬럼, 3 x 3 박스에 1에서 9까지의 숫자가 한번씩만 들어가도록 판을 채우는 것이다. (그림 2)


그림 2. 완성된 Sudoku 퍼즐
완성된 Sudoku 퍼즐

이를 수행하는 많은 방법들까지 이 글에서 설명할 수는 없지만, 기본적인 개념은 소거(elimination) 프로세스를 사용하여 배치 될 숫자를 정하는 것이다. (참고자료)

이 글에서는, 게임을 디스플레이 하고 셀렉트 리스트를 사용하여 정답을 입력할 수 있는 기본 그리드를 구현하고자 한다. XPath를 사용하여 퍼즐이 풀렸는지의 여부를 결정할 수 있다. Part 2에서는 게임에 로딩 및 저장 기능을 추가시키고, 인터페이스도 약간 바꿔볼 것이다.




위로


데이터

시작하려면 어느 정도의 데이터가 필요하다. 데이터 내에 "그리드"를 만드는 것이다. 다시 말해서, 데이터의 한 "행(row)" -- r(ow) 엘리먼트의 내용-은 게임 보드의 한 행으로 매핑된다. 각 숫자는 고유의 박스안에 있게 되고, 이 중 9개가 하나의 행을 구성한다. 9개의 행들이 이 게임을 구성한다. 결과 구조는 그림 3과 같다.


그림 3. 데이터 구조
데이터 구조

보드 상에서 나타나는 모양과 유사한 행과 컬럼이 생겼다. 이 경우, 제로(zero) 엔트리는 사용자가 채워야 하는 빈 박스에 해당한다. XForms 방식 상, 사용자가 폼 상의 박스를 채울 때 그 데이터는 이 XML 문서에 추가된다. 구조화 된 XPath 문을 사용하여 문서의 구조를 검사하여 퍼즐이 풀렸는지의 여부를 결정한다.

기본 페이지를 만드는 것부터 시작하자.




위로


기본 페이지 만들기

기본 페이지에는 여러 엘리먼트가 필요하다. 네임스페이스 같은 실제 페이지의 구조와 XForms 모델이 필요하다. (Listing 1)


Listing 1. 기본 페이지
                
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:xhtml="http://www.w3.org/1999/xhtml"
      xmlns:ev="http://www.w3.org/2001/xml-events"
      xmlns:xforms="http://www.w3.org/2002/xforms"
      xmlns:s="http://www.example.com/sudoku"
      xmlns:b="http://www.example.com/board">
  <head>
    <title>Sudoku</title>

<xforms:model>

  <xforms:instance id="content">
    <s:game>

      <s:row><s:box>6</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box>9</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box>1</s:box></s:row>
      <s:row><s:box>0</s:box><s:box>8</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box>7</s:box><s:box>2</s:box>
<s:box>5</s:box></s:row>
      <s:row><s:box>0</s:box><s:box>7</s:box>
<s:box>0</s:box><s:box>3</s:box><s:box>8</s:box>
<s:box>0</s:box><s:box>9</s:box><s:box>0</s:box>
<s:box>0</s:box></s:row>
      <s:row><s:box>4</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>6</s:box>
<s:box>1</s:box><s:box>8</s:box><s:box>0</s:box>
<s:box>0</s:box></s:row>
      <s:row><s:box>9</s:box><s:box>6</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>5</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>1</s:box>
<s:box>2</s:box></s:row>
      <s:row><s:box>0</s:box><s:box>0</s:box>
<s:box>8</s:box><s:box>7</s:box><s:box>2</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box>3</s:box></s:row>
      <s:row><s:box>0</s:box><s:box>0</s:box>
<s:box>6</s:box><s:box>0</s:box><s:box>3</s:box>
<s:box>2</s:box><s:box>0</s:box><s:box>7</s:box>
<s:box>0</s:box></s:row>
      <s:row><s:box>1</s:box><s:box>3</s:box>
<s:box>2</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>6</s:box>
<s:box>0</s:box></s:row>
      <s:row><s:box>7</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box>6</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box>4</s:box></s:row>

    </s:game>
  </xforms:instance>

  <xforms:submission id="submitgame" action="" method="post"/>

</xforms:model>

</head>
  <body>

    <img src="images/showlayout.gif" style="float:left;height: 64px; width: 64px;" />

    <h1 align="center">Sudoku</h1>

    <br clear="left" />

    <div>

    </div>

  </body>
</html>

여러분이 나중에 사용하게 될 여러 네임스페이드들이 남겨졌다. 데이터가 고유의 인스턴스에 생성되었고, XML 구조를 보다 가독성 있는 것으로 바꿨다. (물론 이름들은 완전히 임의적인 것이다.) 작은 그래픽 역시 추가되어 자신들이 무엇을 만들고자 하는 것인지를 사용자에게 상기시켜 준다. 결과적으로 간단한 페이지가 생겼다. (그림 4)


그림 4. 빈 페이지
빈 페이지

이제 이 페이지에 컨트롤을 추가하는 방법을 보도록 하자.




위로


기본 보드 만들기

게임 보드를 만들려면 아홉 개 행의 드롭다운(drop-down) 리스트가 필요하다. 각각 1부터 9까지의 숫자와 0을 나타내는 빈 공간이 포함된다. 어렵지 않다. 가장 쉬운 방법은 템플릿을 제공하는 인스턴스를 만드는 것이다. (Listing 2)


Listing 2. 템플릿 사용하기
                
...
    </s:game>
  </xforms:instance>

  <xforms:instance id="templates">
                 <b:template>
                <b:entry><b:sendvalue>0</b:sendvalue><b:display></b:display>
                </b:entry>
                <b:entry><b:sendvalue>1</b:sendvalue><b:display>1</b:display>
                </b:entry>
                <b:entry><b:sendvalue>2</b:sendvalue><b:display>2</b:display>
                </b:entry>
                <b:entry><b:sendvalue>3</b:sendvalue><b:display>3</b:display>
                </b:entry>
                <b:entry><b:sendvalue>4</b:sendvalue><b:display>4</b:display>
                </b:entry>
                <b:entry><b:sendvalue>5</b:sendvalue><b:display>5</b:display>
                </b:entry>
                <b:entry><b:sendvalue>6</b:sendvalue><b:display>6</b:display>
                </b:entry>
                <b:entry><b:sendvalue>7</b:sendvalue><b:display>7</b:display>
                </b:entry>
                <b:entry><b:sendvalue>8</b:sendvalue><b:display>8</b:display>
                </b:entry>
                <b:entry><b:sendvalue>9</b:sendvalue><b:display>9</b:display>
                </b:entry>
                </b:template>
                 </xforms:instance>

  <xforms:submission id="submitgame" action="" method="post"/>

</xforms:model>

<style type="text/css">
                div > * {display: inline;}
                </style>

</head>
  <body>

    <img src="images/showlayout.gif" style="float:left;height: 64px; width: 64px;" />

    <h1 align="center">Sudoku</h1>

    <br clear="left" />

    <div>
      <xforms:repeat id="gamerow" nodeset="instance('content')/s:row">
                   <xforms:repeat id="gamebox" nodeset="s:box">
                  <xforms:select1>
                   <xforms:itemset nodeset="instance('templates')/b:entry">
                        <xforms:label ref="b:display"/>
                        <xforms:value ref="b:sendvalue"/>
                     </xforms:itemset>
                   </xforms:select1>
                 </xforms:repeat>
                 </xforms:repeat>
    </div>

  </body>
</html>

보이는 모습에도 불구하고, 이 템플릿은 실제로 하나의 행을 나타내고, 각 "박스"에는 메인 게임 인스턴스로 삽입될 값과 개별 디스플레이 값이 들어있다. 이 게임의 각 행의 경우 행에 있는 각 박스를 순환해야 한다. 행에 있는 각 박스의 경우, 템플릿의 각 엔트리들을 디스플레이 함으로써 셀렉트 리스트를 만든다. 캐스케이드(cascading) 스타일 시트를 약간 조작함으로써(div의 콘텐트가 인라인으로 디스플레이 되도록 설정한다.), 기본 게임 보드를 만들 수 있다. (그림 5)


그림 5. 기본 게임 보드
기본 게임 보드

이제 여러분은 이러한 각각의 리스트들이 제공된 값으로 시작하도록 설정해야 한다.




위로


원래 숫자 설정하기

초기 값을 설정하는 것은 매우 간단하다. (Listing 3)


Listing 3. 초기 값 설정하기
                
...
        <xforms:repeat id="gamebox" nodeset="s:box">
        
          <xforms:select1 ref=".">
             <xforms:itemset nodeset="instance('templates')/b:entry">
                <xforms:label ref="b:display"/>
                <xforms:value ref="b:sendvalue"/>
             </xforms:itemset>
          </xforms:select1>

        </xforms:repeat>
...

이 폼은 각 박스 엘리먼트에 대한 셀렉트 리스트를 디스플레이 하기 때문에, 여러분이 해야 할 일은 리스트가 현재 박스 엘리먼트를 참조하도록 하는 것이다. 그림 6은 결과이다.


그림 6. 초기 값 설정하기
초기 값 설정하기

원치 않을 경우 원래 값을 변경할 수 있다. 물론 이 게임의 목적은 이기는 것이다.




위로


원래 숫자를 읽기 전용으로 만들기

사용자가 원래 값을 변경할 수 없도록 하기 위해서는 제공된 값을 "읽기 전용(read-only)"으로 해야 한다. 사용자가 "0"이 아닌 어떤 값도 변경할 수 없도록 폼에 지시하는 방법이 가장 쉬울 것 같지만, 사용자가 게임을 시작하면 사용자는 0의 값을 다른 값으로 바꿀 것이고 그들이 이미 선택했던 값을 변경하지 못하도록 하는 것은 좋은 생각이 아니다.

이 문제를 해결하려면, 약간의 데이터를 인스턴스에 추가해야 한다. (Listing 4)


Listing 4. 인스턴스에 정보 추가하기
                
...
   <s:game>

      <s:row><s:box ro="yes">6</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box ro="yes">9</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box ro="yes">1</s:box></s:row>
      <s:row><s:box>0</s:box><s:box ro="yes">8</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box ro="yes">7</s:box><s:box 
ro="yes">2</s:box>
<s:box ro="yes">5</s:box></s:row>
...
    </s:game>
  </xforms:instance>

  <xforms:bind nodeset="//s:row//s:box[@ro='yes']" readonly="true()" />

  <xforms:instance id="templates">
...
<style type="text/css">

   div > * {display: inline;}

   *:read-only { color: red }
 
</style>
...

애트리뷰트를 원래 값에 추가하면 이러한 값들이 읽기 전용이 되도록 지정하는 바인딩 조건을 사용할 기회가 생긴다. 다시 말해서, 사용자는 셀렉트 리스트의 값을 변경할 수 없다.

이상적으로는 "pseudo classes"를 사용하여 이러한 값에 대한 스타일을 설정하여 사용자들도 쉽게 어떤 숫자들을 선택했는지, 어떤 숫자가 원래 제공된 것인지를 알 수 있도록 하는 것이다. 필자는 코드를 페이지에 추가했지만, 안타깝게도 Firefox에서는 아직 지원되지 않는다.

페이지를 재 로딩하면, 빈(blank) 값을 변경할 수 있지만 원래 값은 변경할 수 없다는 것을 알게 된다.




위로


게임 점수 매기기

이제는 보드가 생겼으니 어떻게 해야 하는지 알아보자. 완성된 행을 찾아 점수를 매기는 것부터 시작해 보자.

행(row)

한 행이 해결 되었는지 여부를 결정하려면, 여기에 아홉 개의 모든 숫자들의 인스턴스가 포함되어 있는지 여부를 보면 된다. 아홉 개의 지점만 있기 때문에 확실히 중복은 없다. 간단한 XPath 문으로 이를 수행한다.

이 게임에 얼마나 많은 행들이 있는지 알고 싶다면 XPath 문을 사용한다: count(/s:game/s:row).

이것은 9 라는 값을 줄 것이다. 하지만, 이 모든 행을 다 원하는 것이 아니라, 조건을 만족시키는 모든 행만 원한다. 예를 들어, 여러분은 1의 값을 가진 박스를 포함하고 있는 행만 선택할 수 있다: count(/s:game/s:row[s:box = '1']).

이 행들 중에서, 2라는 값을 가진 박스를 갖고 있는 행만 원한다: count(/s:game/s:row[s:box = '1'][s:box = '2']).

9개의 숫자에 대해서도 이런 식으로 한다. 아홉 개의 모든 값을 검사하여 여러분이 지금 어느 위치에 있는지를 알 수 있다. (Listing 5)


Listing 5. Correct Rows 체크하기
                
...
      <s:row><s:box ro="yes">7</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box ro="yes">6</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box ro="yes">4</s:box></s:row>

      <s:correctRows>no</s:correctRows>

    </s:game>
  </xforms:instance>

  <xforms:bind nodeset="//s:row//s:box[@ro='yes']" readonly="true()" />

  <xforms:bind nodeset="//s:correctRows" calculate=
                  "count(/s:game/s:row[s:box = '1'][s:box = 
                '2'][s:box = '3']
                [s:box = '4'][s:box = '5'][s:box = '6'][s:box = '7'][s:box = '8']
                [s:box = '9'])" />

  <xforms:instance id="templates">
...
      </xforms:repeat>

    </div>

    Correct Rows: <xforms:output ref="//s:correctRows" /><br />

  </body>
</html>

한 엘리먼트를 인스턴스에 추가함으로써, 여러분이 어디에 있는지 쉽게 알 수 있다. 이 인스턴스에 값이 매번 업데이트 되기 때문에, 페이지에서 업데이트 될 것이다. (그림 7)


그림 7. Correct Rows
Correct Rows

두 번째 행은 각 숫자에서 정확히 하나의 인스턴스를 갖고 있기 때문에 correctRows에는 1의 값을 볼 수 있다.




위로


컬럼

XPath 식을 만들어서 맞는 컬럼을 체크하는 것은 조금 복잡하다. 여러 조건을 만족시키는 하나의 행을 보는 것이 아닌, 여기에서는 각 숫자를 갖고 있는 행을 포함하고 있는 컬럼을 보는 것이다. 예를 들어, 첫 번째 컬럼에 숫자 1을 포함하고 있는 행을 포함하고 있을 경우에만 루트 엘리먼트를 카운트 할 수 있다: count(/s:game[s:row[s:box[1]='1']])

다시 말해서, 1의 위치에 있는 박스 엘리먼트에 "1"의 값을 가진 조건을 만족시키는 행이 있을 때에만 게임 엘리먼트를 카운트 하는 것이다. 1이 첫 번째 위치에 있는 한 어떤 행인지는 상관 없다. 마찬가지로, 첫 번째 위치에 숫자 2를 갖고 있을 경우에만 게임 엘리먼트를 카운트 할 수 있다: count(/s:game[s:row[s:box[1]='1']][s:row[s:box[1]='2']])

이런 식으로 진행하면 된다. 안타깝게도, 이 문은 컬럼 1의 진위 여부만 검사하는데, 다시 말해서 각 컬럼에 새로운 count() 함수가 필요하다는 의미이다. 하지만 그렇게 나쁜 것만은 아니다. (Listing 6)


Listing 6. Correct columns 보기
                
...
  <xforms:bind nodeset="//s:correctRows" calculate=
     "count(/s:game/s:row[s:box = '1'][s:box = '2'][s:box = '3']
[s:box = '4'][s:box = '5'][s:box = '6'][s:box = '7'][s:box = '8']
[s:box = '9']) +
      count(/s:game[s:row[s:box[1]='1']][s:row[s:box[1]='2']]
                [s:row[s:box[1]='3']][s:row[s:box[1]='4']][s:row[s:box[1]='5']]
                s:row[s:box[1]='6']][s:row[s:box[1]='7']][s:row[s:box[1]='8']]
                [s:row[s:box[1]='9']]) +
                count(/s:game[s:row[s:box[2]='1']][s:row[s:box[2]='2']]
                [s:row[s:box[2]='3']][s:row[s:box[2]='4']][s:row[s:box[2]='5']]
                [s:row[s:box[2]='6']][s:row[s:box[2]='7']][s:row[s:box[2]='8']]
                [s:row[s:box[2]='9']]) +
                count(/s:game[s:row[s:box[3]='1']][s:row[s:box[3]='2']]
                [s:row[s:box[3]='3']][s:row[s:box[3]='4']][s:row[s:box[3]='5']]
                [s:row[s:box[3]='6']][s:row[s:box[3]='7']][s:row[s:box[3]='8']]
                [s:row[s:box[3]='9']]) +
                count(/s:game[s:row[s:box[4]='1']][s:row[s:box[4]='2']]
                [s:row[s:box[4]='3']][s:row[s:box[4]='4']][s:row[s:box[4]='5']]
                [s:row[s:box[4]='6']][s:row[s:box[4]='7']][s:row[s:box[4]='8']]
                [s:row[s:box[4]='9']]) +
                count(/s:game[s:row[s:box[5]='1']][s:row[s:box[5]='2']]
                [s:row[s:box[5]='3']][s:row[s:box[5]='4']][s:row[s:box[5]='5']]
                [s:row[s:box[5]='6']][s:row[s:box[5]='7']][s:row[s:box[5]='8']]
                [s:row[s:box[5]='9']]) +
                count(/s:game[s:row[s:box[6]='1']][s:row[s:box[6]='2']]
                [s:row[s:box[6]='3']][s:row[s:box[6]='4']][s:row[s:box[6]='5']]
                [s:row[s:box[6]='6']][s:row[s:box[6]='7']][s:row[s:box[6]='8']]
                [s:row[s:box[6]='9']]) +
                count(/s:game[s:row[s:box[7]='1']][s:row[s:box[7]='2']]
                [s:row[s:box[7]='3']][s:row[s:box[7]='4']][s:row[s:box[7]='5']]
                [s:row[s:box[7]='6']][s:row[s:box[7]='7']][s:row[s:box[7]='8']]
                [s:row[s:box[7]='9']]) +
                count(/s:game[s:row[s:box[8]='1']][s:row[s:box[8]='2']]
                [s:row[s:box[8]='3']][s:row[s:box[8]='4']][s:row[s:box[8]='5']]
                [s:row[s:box[8]='6']][s:row[s:box[8]='7']][s:row[s:box[8]='8']]
                [s:row[s:box[8]='9']]) +
                count(/s:game[s:row[s:box[9]='1']][s:row[s:box[9]='2']]
                [s:row[s:box[9]='3']][s:row[s:box[9]='4']][s:row[s:box[9]='5']]
                [s:row[s:box[9]='6']][s:row[s:box[9]='7']][s:row[s:box[9]='8']]
                [s:row[s:box[9]='9']])" />

  <xforms:instance id="templates">
...

페이지를 리프레쉬 하면 컬럼을 완성할 때 "correct rows" 값이 업데이트 되는 것을 볼 수 있다. 그림 8의 세 번째 컬럼이다.


그림 8. 행 정정하기
행 정정하기

여기에서, 모든 컬럼과 행을 풀었다면 18이라고 하는 "correct rows" 값을 볼 수 있을 것이다. (아홉 개의 행과 아홉 개의 컬럼) 하지만 여러분은 아직 완성하지 못했다.




위로


추가 단계

그렇게 나쁘지는 않았지만 한 단계 더 남아있다. 행과 컬럼 외에도, 사용자는 그림 1의 3 x 3 박스에 한 번씩의 숫자만 사용할 수 있다. 모든 숫자들이 존재하는지 여부를 쉽게 알 수 있도록 하는 간단한 XPath 식이 없다. 모든 문에서 특정 박스와 특정 숫자를 지정해야 한다. 다행히도 옵션이 있다.

여러분이 할 수 있는 일은 각 스퀘어를 이 목적으로 만든 데이터의 한 행에 매핑할 수 있다. 예를 들어, Listing 7의 XML 엘리먼트를 생각해 보자.


Listing 7. 박스 엘리먼트
                
<s:square><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
          <s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
          
<s:box>0</s:box><s:box>0</s:box><s:box>0</s:box></s:square>

아홉 개의 박스 엘리먼트에서 하나의 행과 매우 잘 상응한다. 다음과 같이 박스 매핑을 해보라. (Listing 8)


Listing 8. 박스 조절
                
<s:square><s:box>[1, 1]</s:box><s:box>
[1, 2]</s:box><s:box>[1, 3]</s:box>
          <s:box>[2, 1]</s:box><s:box>
[2, 2]</s:box><s:box>[2, 3]</s:box>
          <s:box>[3, 1]</s:box><s:box>
[3, 2]</s:box><s:box>[3, 3]</s:box></s:square>

데이터가 잘 맞고, 간단한 XPath 문을 사용하여 얼마나 많은 스퀘어가 정확한지를 알 수 있다. (Listing 9)


Listing 9. 얼마나 많은 스퀘어가 정확한지를 결정하는 XPath 문
                 
count(/s:game/s:square[s:box = '1'][s:box = '2']
      [s:box = '3'][s:box = '4'][s:box = '5'][s:box = '6']
      [s:box = '7'][s:box = '8'][s:box = '9'])

이는 원래 행을 결정하는데 사용된 문과 거의 동일하다. 다음에 해야 할 일은 이 모든 정보를 기존 게임에 추가하는 것이다. (Listing 10)


Listing 10. 매핑 인스턴스를 게임에 추가하기
                
...
      <s:row><s:box ro="yes">7</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box ro="yes">6</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box ro="yes">4</s:box></s:row>

      
    <s:square><s:box>0</s:box><s:box>0</s:box><s:box>0
                </s:box><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
                <s:box>0</s:box>
                <s:box>0</s:box><s:box>0</s:box></s:square>
                <s:square><s:box>0</s:box><s:box>0</s:box><s:box>0
                </s:box><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
                <s:box>0</s:box>
                <s:box>0</s:box><s:box>0</s:box></s:square>
                <s:square><s:box>0</s:box><s:box>0</s:box><s:box>0
                </s:box><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
                <s:box>0</s:box>
                <s:box>0</s:box><s:box>0</s:box></s:square>
                <s:square><s:box>0</s:box><s:box>0</s:box><s:box>0
                </s:box><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
                <s:box>0</s:box>
                <s:box>0</s:box><s:box>0</s:box></s:square>
                <s:square><s:box>0</s:box><s:box>0</s:box><s:box>0
                </s:box><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
                <s:box>0</s:box>
                <s:box>0</s:box><s:box>0</s:box></s:square>
                <s:square><s:box>0</s:box><s:box>0</s:box><s:box>0
                </s:box><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
                <s:box>0</s:box>
                <s:box>0</s:box><s:box>0</s:box></s:square>
                <s:square><s:box>0</s:box><s:box>0</s:box><s:box>0
                </s:box><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
                <s:box>0</s:box>
                <s:box>0</s:box><s:box>0</s:box></s:square>
                <s:square><s:box>0</s:box><s:box>0</s:box><s:box>0
                </s:box><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
                <s:box>0</s:box>
                <s:box>0</s:box><s:box>0</s:box></s:square>
                <s:square><s:box>0</s:box><s:box>0</s:box><s:box>0
                </s:box><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
                <s:box>0</s:box>
                <s:box>0</s:box><s:box>0</s:box></s:square>

      <s:correctRows>no</s:correctRows>

    </s:game>
  </xforms:instance>

  <xforms:bind nodeset="//s:row//s:box[@ro='yes']" readonly="true()" />

  <xforms:bind nodeset="//s:correctRows" calculate=
     "count(/s:game/s:row[s:box = '1'][s:box = '2'][s:box = '3']
[s:box = '4'][s:box = '5'][s:box = '6'][s:box = '7'][s:box = '8']
[s:box = '9']) +
      count(/s:game[s:row[s:box[1]='1']][s:row[s:box[1]='2']]
[s:row[s:box[1]='3']][s:row[s:box[1]='4']][s:row[s:box[1]='5']]
[s:row[s:box[1]='6']][s:row[s:box[1]='7']][s:row[s:box[1]='8']]
[s:row[s:box[1]='9']]) +
...
[s:row[s:box[9]='9']]) + 
      count(/s:game/s:square[s:box = '1'][s:box = '2']
                [s:box = '3'][s:box = '4'][s:box = '5'][s:box = '6']
                [s:box = '7'][s:box = '8'][s:box = '9'])" />

  <xforms:instance id="templates">
...

물론, 인스턴스를 추가하는 것만으로 다 되는 것은 아니다. 스퀘어를 완료하고 "correct rows" 값이 변하지 않았다는 것을 확인해야 한다. 이렇게 하기 위해서는 매핑을 완료해야 한다.




위로


값 설정하기

하나의 엘리먼트가 또 다른 엘리먼트의 값과 같도록 설정하는 다양한 방법들은 XForms에 구현되어 있지만, 이 경우, 여러분이 프로세스를 직접 컨트롤 해야 한다. 사용자가 클릭할 때 개별 값을 설정하는 버튼을 만들 것이다. (Listing 11)


Listing 11. 값 설정하기
                
...
    Correct Rows: <xforms:output ref="//s:correctRows" /><br />

    <xforms:trigger style="display:block">
                       <xforms:label>Check it!</xforms:label>
                 <xforms:action ev:event="DOMActivate">
                          <xforms:setvalue ref="/s:game/s:square[1]/s:box[1]" 
                                          value="/s:game/s:row[1]/s:box[1]" />
                 <xforms:setvalue ref="/s:game/s:square[1]/s:box[2]" 
                                  value="/s:game/s:row[1]/s:box[2]" />
                <xforms:setvalue ref="/s:game/s:square[1]/s:box[3]" 
                                 value="/s:game/s:row[1]/s:box[3]" />
                      <xforms:setvalue ref="/s:game/s:square[1]/s:box[4]" 
                                              value="/s:game/s:row[2]/s:box[1]" />
                        <xforms:setvalue ref="/s:game/s:square[1]/s:box[5]" 
                                               value="/s:game/s:row[2]/s:box[2]" />
                         <xforms:setvalue ref="/s:game/s:square[1]/s:box[6]" 
                                                value="/s:game/s:row[2]/s:box[3]" />
                         <xforms:setvalue ref="/s:game/s:square[1]/s:box[7]" 
                                                value="/s:game/s:row[3]/s:box[1]" />
                         <xforms:setvalue ref="/s:game/s:square[1]/s:box[8]" 
                                                value="/s:game/s:row[3]/s:box[2]" />
                         <xforms:setvalue ref="/s:game/s:square[1]/s:box[9]" 
                                         value="/s:game/s:row[3]/s:box[3]" />

                      <xforms:setvalue ref="/s:game/s:square[2]/s:box[1]" 
                                             value="/s:game/s:row[1]/s:box[4]" />
                      <xforms:setvalue ref="/s:game/s:square[2]/s:box[2]" 
                                             value="/s:game/s:row[1]/s:box[5]" />
                      <xforms:setvalue ref="/s:game/s:square[2]/s:box[3]" 
                                             value="/s:game/s:row[1]/s:box[6]" />
                      <xforms:setvalue ref="/s:game/s:square[2]/s:box[4]" 
                                            value="/s:game/s:row[2]/s:box[4]" />
                    <xforms:setvalue ref="/s:game/s:square[2]/s:box[5]" 
                                             value="/s:game/s:row[2]/s:box[5]" />
                         <xforms:setvalue ref="/s:game/s:square[2]/s:box[6]" 
                                               value="/s:game/s:row[2]/s:box[6]" />
                        <xforms:setvalue ref="/s:game/s:square[2]/s:box[7]" 
                                              value="/s:game/s:row[3]/s:box[4]" />
                        <xforms:setvalue ref="/s:game/s:square[2]/s:box[8]" 
                                                 value="/s:game/s:row[3]/s:box[5]" />
                          <xforms:setvalue ref="/s:game/s:square[2]/s:box[9]" 
                                                value="/s:game/s:row[3]/s:box[6]" />
                         <xforms:setvalue ref="/s:game/s:square[3]/s:box[1]" 
                                                 value="/s:game/s:row[1]/s:box[7]" />
                        <xforms:setvalue ref="/s:game/s:square[3]/s:box[2]" 
                                                 value="/s:game/s:row[1]/s:box[8]" />
                         <xforms:setvalue ref="/s:game/s:square[3]/s:box[3]" 
                                              value="/s:game/s:row[1]/s:box[9]" />
                       <xforms:setvalue ref="/s:game/s:square[3]/s:box[4]" 
                                                value="/s:game/s:row[2]/s:box[7]" />
                          <xforms:setvalue ref="/s:game/s:square[3]/s:box[5]" 
                                                value="/s:game/s:row[2]/s:box[8]" />
                        <xforms:setvalue ref="/s:game/s:square[3]/s:box[6]" 
                                                value="/s:game/s:row[2]/s:box[9]" />
                        <xforms:setvalue ref="/s:game/s:square[3]/s:box[7]" 
                                                 value="/s:game/s:row[3]/s:box[7]" />
                         <xforms:setvalue ref="/s:game/s:square[3]/s:box[8]" 
                                                 value="/s:game/s:row[3]/s:box[8]" />
                         <xforms:setvalue ref="/s:game/s:square[3]/s:box[9]" 
                                             value="/s:game/s:row[3]/s:box[9]" />
                         <xforms:setvalue ref="/s:game/s:square[4]/s:box[1]" 
                                                value="/s:game/s:row[4]/s:box[4]" />
                          <xforms:setvalue ref="/s:game/s:square[4]/s:box[2]" 
                                                value="/s:game/s:row[4]/s:box[5]" />
                          <xforms:setvalue ref="/s:game/s:square[4]/s:box[3]" 
                                                 value="/s:game/s:row[4]/s:box[6]" />
                         <xforms:setvalue ref="/s:game/s:square[4]/s:box[4]" 
                                               value="/s:game/s:row[5]/s:box[4]" />
                         <xforms:setvalue ref="/s:game/s:square[4]/s:box[5]" 
                                                value="/s:game/s:row[5]/s:box[5]" />
                         <xforms:setvalue ref="/s:game/s:square[4]/s:box[6]" 
                                                value="/s:game/s:row[5]/s:box[6]" />
                         <xforms:setvalue ref="/s:game/s:square[4]/s:box[7]" 
                                                value="/s:game/s:row[6]/s:box[4]" />
                         <xforms:setvalue ref="/s:game/s:square[4]/s:box[8]" 
                                                value="/s:game/s:row[6]/s:box[5]" />
                         <xforms:setvalue ref="/s:game/s:square[4]/s:box[9]" 
                                                value="/s:game/s:row[6]/s:box[6]" />
                         <xforms:setvalue ref="/s:game/s:square[5]/s:box[1]" 
                                                value="/s:game/s:row[4]/s:box[1]" />
                         <xforms:setvalue ref="/s:game/s:square[5]/s:box[2]" 
                                                value="/s:game/s:row[4]/s:box[2]" />
                         <xforms:setvalue ref="/s:game/s:square[5]/s:box[3]" 
                                                value="/s:game/s:row[4]/s:box[3]" />
                        <xforms:setvalue ref="/s:game/s:square[5]/s:box[4]" 
                                               value="/s:game/s:row[5]/s:box[1]" />
                       <xforms:setvalue ref="/s:game/s:square[5]/s:box[5]" 
                                                value="/s:game/s:row[5]/s:box[2]" />
                        <xforms:setvalue ref="/s:game/s:square[5]/s:box[6]" 
                                                 value="/s:game/s:row[5]/s:box[3]" />
                         <xforms:setvalue ref="/s:game/s:square[5]/s:box[7]" 
                                                value="/s:game/s:row[6]/s:box[1]" />
                         <xforms:setvalue ref="/s:game/s:square[5]/s:box[8]" 
                                                value="/s:game/s:row[6]/s:box[2]" />
                         <xforms:setvalue ref="/s:game/s:square[5]/s:box[9]" 
                                                value="/s:game/s:row[6]/s:box[3]" />
                        <xforms:setvalue ref="/s:game/s:square[6]/s:box[1]" 
                                               value="/s:game/s:row[4]/s:box[7]" />
                        <xforms:setvalue ref="/s:game/s:square[6]/s:box[2]" 
                                               value="/s:game/s:row[4]/s:box[8]" />
                        <xforms:setvalue ref="/s:game/s:square[6]/s:box[3]" 
                                                 value="/s:game/s:row[4]/s:box[9]" />
                         <xforms:setvalue ref="/s:game/s:square[6]/s:box[4]" 
                                                value="/s:game/s:row[5]/s:box[7]" />
                          <xforms:setvalue ref="/s:game/s:square[6]/s:box[5]" 
                                               value="/s:game/s:row[5]/s:box[8]" />
                        <xforms:setvalue ref="/s:game/s:square[6]/s:box[6]" 
                                                 value="/s:game/s:row[5]/s:box[9]" />
                         <xforms:setvalue ref="/s:game/s:square[6]/s:box[7]" 
                                                value="/s:game/s:row[6]/s:box[7]" />
                          <xforms:setvalue ref="/s:game/s:square[6]/s:box[8]" 
                                                 value="/s:game/s:row[6]/s:box[8]" />
                         <xforms:setvalue ref="/s:game/s:square[6]/s:box[9]" 
                                                value="/s:game/s:row[6]/s:box[9]" />
                         <xforms:setvalue ref="/s:game/s:square[7]/s:box[1]" 
                                                 value="/s:game/s:row[7]/s:box[1]" />
                         <xforms:setvalue ref="/s:game/s:square[7]/s:box[2]" 
                                                value="/s:game/s:row[7]/s:box[2]" />
                        <xforms:setvalue ref="/s:game/s:square[7]/s:box[3]" 
                                              value="/s:game/s:row[7]/s:box[3]" />
                        <xforms:setvalue ref="/s:game/s:square[7]/s:box[4]" 
                                              value="/s:game/s:row[8]/s:box[1]" />
                        <xforms:setvalue ref="/s:game/s:square[7]/s:box[5]" 
                                               value="/s:game/s:row[8]/s:box[2]" />
                        <xforms:setvalue ref="/s:game/s:square[7]/s:box[6]" 
                                              value="/s:game/s:row[8]/s:box[3]" />
                       <xforms:setvalue ref="/s:game/s:square[7]/s:box[7]" 
                                              value="/s:game/s:row[9]/s:box[1]" />
                        <xforms:setvalue ref="/s:game/s:square[7]/s:box[8]" 
                                             value="/s:game/s:row[9]/s:box[2]" />
                      <xforms:setvalue ref="/s:game/s:square[7]/s:box[9]" 
                                             value="/s:game/s:row[9]/s:box[3]" />
                       <xforms:setvalue ref="/s:game/s:square[8]/s:box[1]" 
                                              value="/s:game/s:row[7]/s:box[4]" />
                       <xforms:setvalue ref="/s:game/s:square[8]/s:box[2]" 
                                              value="/s:game/s:row[7]/s:box[5]" />
                       <xforms:setvalue ref="/s:game/s:square[8]/s:box[3]" 
                                              value="/s:game/s:row[7]/s:box[6]" />
                        <xforms:setvalue ref="/s:game/s:square[8]/s:box[4]" 
                                               value="/s:game/s:row[8]/s:box[4]" />
                         <xforms:setvalue ref="/s:game/s:square[8]/s:box[5]" 
                                               value="/s:game/s:row[8]/s:box[5]" />
                        <xforms:setvalue ref="/s:game/s:square[8]/s:box[6]" 
                                               value="/s:game/s:row[8]/s:box[6]" />
                        <xforms:setvalue ref="/s:game/s:square[8]/s:box[7]" 
                                               value="/s:game/s:row[9]/s:box[4]" />
                        <xforms:setvalue ref="/s:game/s:square[8]/s:box[8]" 
                                              value="/s:game/s:row[9]/s:box[5]" />
                        <xforms:setvalue ref="/s:game/s:square[8]/s:box[9]" 
                                               value="/s:game/s:row[9]/s:box[6]" />
                         <xforms:setvalue ref="/s:game/s:square[9]/s:box[1]" 
                                                value="/s:game/s:row[7]/s:box[7]" />
                         <xforms:setvalue ref="/s:game/s:square[9]/s:box[2]" 
                                               value="/s:game/s:row[7]/s:box[8]" />
                       <xforms:setvalue ref="/s:game/s:square[9]/s:box[3]" 
                                                value="/s:game/s:row[7]/s:box[9]" />
                         <xforms:setvalue ref="/s:game/s:square[9]/s:box[4]" 
                                                value="/s:game/s:row[8]/s:box[7]" />
                         <xforms:setvalue ref="/s:game/s:square[9]/s:box[5]" 
                                             value="/s:game/s:row[8]/s:box[8]" />
                         <xforms:setvalue ref="/s:game/s:square[9]/s:box[6]" 
                                              value="/s:game/s:row[8]/s:box[9]" />
                        <xforms:setvalue ref="/s:game/s:square[9]/s:box[7]" 
                                                value="/s:game/s:row[9]/s:box[7]" />
                        <xforms:setvalue ref="/s:game/s:square[9]/s:box[8]" 
                                               value="/s:game/s:row[9]/s:box[8]" />
                        <xforms:setvalue ref="/s:game/s:square[9]/s:box[9]" 
                                               value="/s:game/s:row[9]/s:box[9]" />
                
          </xforms:action>
                     </xforms:trigger>

  </body>
</html>

사용자가 Check it! 버튼을 클릭할 때, 이 모든 값들이 설정될 것이고, 이는 "correct rows" 계산이 업데이트 되도록 할 것이다. 페이지를 재 로드하고 스퀘어를 한 번 더 완성할 때 이를 볼 수 있다. "correct rows" 값은 여러분이 버튼을 클릭할 때까지 바뀌지 않는다. 그림 9(전)과 그림 10(후).


그림 9. 버튼을 클릭하기 전
버튼을 클릭하기 전

그림 10은 버튼을 클릭한 후 "correct rows" 값을 보여준다.


그림 10. 버튼을 클릭한 후
버튼을 클릭한 후

지금까지, 아홉 개의 스퀘어가 추가되었고, 게임이 완성되기 전에 "correct rows"의 수는 27이 되어야 한다.




위로


제출 버튼 추가하기

마지막으로, 제출 버튼을 추가해야 한다. 게임이 제출할 준비가 될 때에만 나타나도록 해야 하므로, 다음과 같이 설정한다. (Listing 12)


Listing 12. 제출 버튼 설정하기
                
...
  <xforms:instance id="content">
    <s:game>

      <!-- Test set of correct data -->
                <s:row><s:box>1</s:box><s:box>4</s:box><s:box>7</s:box>
                <s:box>2</s:box><s:box>5</s:box><s:box>8</s:box><s:box>3
                </s:box>
                <s:box>6</s:box><s:box>9</s:box></s:row>
                <s:row><s:box>2</s:box><s:box>5</s:box><s:box>8</s:box>
                <s:box>3</s:box><s:box>6</s:box><s:box>9</s:box><s:box>1
                </s:box>
                <s:box>4</s:box><s:box>7</s:box></s:row>
                <s:row><s:box>3</s:box><s:box>6</s:box><s:box>9</s:box>
                <s:box>1</s:box><s:box>4</s:box><s:box>7</s:box><s:box>2
                </s:box>
                <s:box>5</s:box><s:box>8</s:box></s:row>
                <s:row><s:box>4</s:box><s:box>7</s:box><s:box>1</s:box>
                <s:box>5</s:box><s:box>8</s:box><s:box>2</s:box><s:box>6
                </s:box>
                <s:box>9</s:box><s:box>3</s:box></s:row>
                <s:row><s:box>5</s:box><s:box>8</s:box><s:box>2</s:box>
                <s:box>6</s:box><s:box>9</s:box><s:box>3</s:box><s:box>4
                </s:box>
                <s:box>7</s:box><s:box>1</s:box></s:row>
                <s:row><s:box>6</s:box><s:box>9</s:box><s:box>3</s:box>
                <s:box>4</s:box><s:box>7</s:box><s:box>1</s:box><s:box>5
                </s:box>
                <s:box>8</s:box><s:box>2</s:box></s:row>
                <s:row><s:box>7</s:box><s:box>1</s:box><s:box>4</s:box>
                <s:box>8</s:box><s:box>2</s:box><s:box>5</s:box><s:box>9
                </s:box>
                <s:box>3</s:box><s:box>6</s:box></s:row>
                <s:row><s:box>8</s:box><s:box>2</s:box><s:box>5</s:box>
                <s:box>9</s:box><s:box>3</s:box><s:box>6</s:box><s:box>7
                </s:box>
                <s:box>1</s:box><s:box>4</s:box></s:row>
                <s:row><s:box>9</s:box><s:box>3</s:box><s:box>6</s:box>
                <s:box>7</s:box><s:box>1</s:box><s:box>4</s:box><s:box>8
                </s:box>
                <s:box>2</s:box><s:box>5</s:box></s:row>


<!--      <s:row><s:box ro="yes">6</s:box><s:box>0</s:box>
...
<s:box ro="yes">4</s:box></s:row> -->

      
<s:square><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
...
<s:box>0</s:box><s:box>0</s:box></s:square>

      <s:submitButtonElement>Submit</s:submitButtonElement>
      <s:correctRows>no</s:correctRows>

    </s:game>
  </xforms:instance>

  <xforms:bind nodeset="//s:row//s:box[@ro='yes']" readonly="true()" />

  <xforms:bind nodeset="//s:submitButtonElement"  
                                             relevant="/s:game/s:correctRows = 27" />

  <xforms:bind nodeset="//s:correctRows" calculate=
     "count(/s:game/s:row[s:box = '1'][s:box = '2'][s:box = '3']
[s:box = '4'][s:box = '5'][s:box = '6'][s:box = '7'][s:box = '8']
[s:box = '9']) +
...
          </xforms:action>
      </xforms:trigger>

      <xforms:submit ref="/s:game/s:submitButtonElement" submission="submitgame">
                  <xforms:label>Submit</xforms:label>	
                 </xforms:submit>

  </body>
</html>

밑에서부터 보면, 제출 버튼이 추가되었고, 새로운 엘리먼트인 submitButtonElement 엘리먼트가 참조되었다. 바인딩 문 역시 추가되어 correctRows 엘리먼트가 27이 아닌 이상 엘리먼트가 나타나지 않도록 했다. 이를 테스트 하기 위해, "정확한" 데이터 세트가 임시적으로 추가되었다. 페이지를 처음 로딩할 때 이 모든 행과 컬럼들이 완성되었음을 볼 수 있다. (그림 11)


그림 11. 정답 데이터 로딩하기
정답 데이터 로딩하기

하지만, Check it! 버튼을 클릭하면, correctRows 값이 27로 업데이트 되고, 제출 버튼이 나타난다. (그림 12)


그림 12. 제출 버튼 등장
제출 버튼 등장

아직까지는 데이터를 제출할 곳이 없다. part 2를 기대하기 바란다.

요약

Sudoku는 매우 특수한 데이터 패턴들을 기반으로 하기 때문에, XPath 식을 사용하여 특정 게임에 사용자가 만들었던 절차를 계산할 수 있다. 또한 이러한 패턴들을 사용하여 사용자가 실행할 수 있는 게임 보드를 쉽게 만들 수 있다. Part 1에서는, 폼과 실행 구조를 만들었다. Part 2에서는 데이터에 대해서 설명하고, 게임 로딩과 저장, 기타 향상에 대해설명하겠다.





위로


다운로드 하십시오

설명이름크기다운로드 방식
Part 1 sample codesudoku1_source.zip3KBHTTP
다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기

토론


필자소개

Nicholas Chase는 Lucent Technologies, Sun Microsystems, Oracle, Tampa Bay Buccaneers에서 웹 사이트 개발을 해왔다. 고등학교 물리 교사, 방사능 폐기 장치 관리자, 온라인 공상 과학 매거진 편집장, 멀티미디어 엔지니어, Oracle 인스트럭터, 인터랙티브 커뮤니케이션 기업의 CTO 등 다양한 역할을 수행하고 있다. XML Primer Plus (Sam's)를 포함한 다양한 책들을 저술했다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



 


 


 


이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us





위로


developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의