12/1/11

Sử dụng XForms để tạo trò chơi Sudoku riêng của bạn, Phần 1: Tạo trò chơi

Tóm tắt:  Chẳng có gì bí mật khi nói Sudoku là một trong những xu hướng mới nóng nhất được lưu hành. Có thể dễ dàng chơi trò chơi số này trên máy tính hoặc trên giấy, và vì chúng ta có thể dễ dàng phân tích dữ liệu theo một biểu mẫu bằng cách sử dụng XPath, nên với chúng ta việc sử dụng XForms để tạo một biểu mẫu cho phép chúng ta chơi Sudoku là rất có lợi. Loạt hai bài viết này cho bạn thấy làm thế nào để tạo một máy khách trò chơi đòi hỏi các trò chơi mới từ máy chủ, phát hiện các di chuyển hợp pháp và bất hợp pháp và kết thúc trò chơi, và lưu trò chơi hiện tại cho lần chơi sau. Nó cũng cho bạn thấy cách tạo các trò chơi mới cho người chơi. Trong phần một, chúng ta tạo máy khách trò chơi cơ bản. Bài viết này giả định rằng bạn đã hiểu rõ những điều cơ bản của XForms. Để ôn luyện, hãy xem phần Tài nguyên để có các liên kết đến nội dung giúp bạn bắt đầu. Mã này đã được viết và thử nghiệm trên các phần mở rộng XForms của Mozilla Firefox, nhưng các khái niệm này áp dụng cho bất kỳ công cụ nào.

Tổng quan
Sudoku đã lặng lẽ xuất hiện trong đời sống tại Hoa Kỳ trong vài năm qua, và sau đó trở thành một hiện tượng, cũng giống như nó đã có ở Nhật Bản, nơi nó khởi đầu. Đó là một trò chơi đơn giản, giống với các trò chơi ô chữ ở chỗ nó sử dụng một mạng lưới ô vuông, nhưng khác vì nó sử dụng các số, và không đòi hỏi các gợi ý bên ngoài. Ý tưởng là bạn có một mạng lưới ô vuông có một vài số được cung cấp, như được cho thấy trong Hình 1.

Hình 1. Một trò chơi Sudoku mẫu
Một trò chơi Sudoku mẫu
Ý tưởng là điền vào bảng trò chơi sao cho mỗi hàng, cột, và ô vuông 3 x 3 (được phân định bằng các dòng trong hình này) có một trong các chữ số từ 1 đến 9 đúng một lần, như hiển thị trong Hình 2.

Hình 2. Trò chơi Sudoku đã giải xong
Trò chơi Sudoku đã giải xong
Có nhiều cách để thực hiện điều này, hầu hết nằm ngoài phạm vi của bài viết này, nhưng ý tưởng cơ bản là sử dụng quá trình loại trừ để quyết định nơi mà mỗi số đi tới. (Xem phần Tài nguyên để biết một số nguồn thông tin tốt). Như thể tất cả các quảng cáo sẽ mách bảo cho bạn, không có phép toán nào cần thiết cả.
Trong bài viết này, chúng ta sẽ xây dựng một mạng lưới ô vuông cơ bản hiển thị một trò chơi và cho phép bạn nhập các câu trả lời của mình bằng cách sử dụng các danh sách chọn. Khi sử dụng XPath, bạn có thể xác định trò chơi đã được giải hay chưa. Trong phần hai, bạn sẽ nâng cao các trò chơi với các khả năng tải và lưu trữ, và có thể chỉnh sửa giao diện một chút.
Dữ liệu
Để bắt đầu, bạn sẽ cần một số dữ liệu. Cách để làm điều này là tạo ra một "mạng lưới ô vuông" trong chính dữ liệu đó. Nói cách khác, một "hàng" dữ liệu -- các nội dung của phần tử r(ow) -- ánh xạ tới một hàng của bảng trò chơi. Mỗi số trú trong ô vuông riêng của mình, với chín số trong chúng tạo nên một hàng. Chín hàng tạo thành trò chơi. Cấu trúc kết quả trông giống như Hình 3.

Hình 3. Cấu trúc dữ liệu
Cấu trúc dữ liệu
Lưu ý rằng bạn có các hàng và các cột gần giống với những gì mà chúng sẽ trông thấy trên bảng. Trong trường hợp này, các mục nhập số không ứng với các ô rỗng mà người chơi sẽ phải điền vào. Do cách làm việc của XForms, nên khi người chơi điền vào một ô trên biểu mẫu, dữ liệu được thêm vào tài liệu XML này. Sau đó, bạn có thể kiểm tra cấu trúc của tài liệu bằng cách sử dụng cẩn thận các câu lệnh XPath được dựng lên để xác định trò chơi đã được giải hay chưa.
Hãy bắt đầu bằng cách tạo một trang cơ bản.
Tạo trang cơ bản
Trang cơ bản cần có một số phần tử. Chúng gồm có cấu trúc của trang thực tế, có cả vùng tên và v.v.., cũng như mô hình XForms (xem Liệt kê 1).

Liệt kê 1. Trang cơ bản
<?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>

Một số vùng tên mà bạn sẽ sử dụng sau này chỉ để làm cho mọi thứ đơn giản hơn một chút đã được bỏ qua. Ngoài ra lưu ý rằng dữ liệu đã được tạo ra trong cá thể riêng của nó, việc thay đổi cấu trúc XML để mọi người dễ đọc hơn một chút. (Tất nhiên, các tên là hoàn toàn tùy ý). Một hình ảnh nhỏ cũng đã được kèm theo để nhắc nhở người chơi về những gì họ đang cố gắng hoàn thành. Những gì bạn đã để lại là một trang đơn giản (xem Hình 4).

Hình 4. Trang rỗng
Trang rỗng
Bây giờ chúng ta hãy xem xét việc thêm một số phần điều khiển cho trang đó.
Tạo bảng cơ bản
Để tạo bảng trò chơi, bạn sẽ cần chín hàng trong các danh sách thả xuống, mỗi một hàng chứa các số một đến chín và một khoảng trống đại diện cho số không (không có gì). May mắn thay, điều này không khó để đạt được. Cách đơn giản nhất là tạo một cá thể thứ hai cung cấp một khuôn mẫu (xem Liệt kê 2).

Liệt kê 2. Sử dụng khuôn mẫu
...
    </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>

Bất kể dạng nhìn thấy của mình, khuôn mẫu này thực sự biểu diễn một hàng duy nhất, với mỗi "ô vuông" có một giá trị được chèn vào trong một cá thể trò chơi chính và một giá trị hiển thị riêng biệt. Với mỗi hàng trong trò chơi này, bạn tạo vòng lặp qua mỗi ô trong hàng. Đối với mỗi ô trong một hàng, bạn tạo một danh sách chọn bằng cách hiển thị từng mục nhập trong khuôn mẫu. Bằng cách thao tác các bảng định kiểu theo tầng ít hơn một chút (thiết lập các nội dung của div được hiển thị nội tuyến, chứ không phải là mỗi bảng theo dòng riêng của nó), bạn có thể nhận được bảng trò chơi cơ bản (xem Hình 5).

Hình 5. Bảng trò chơi cơ bản
Bảng trò chơi cơ bản
Bây giờ bạn cần thiết lập từng danh sách trong số các danh sách này để bắt đầu với giá trị được cung cấp, nếu có một giá trị.
Thiết lập các số ban đầu
Do cách mà các danh sách này đã được cấu trúc, nên việc thiết lập một giá trị ban đầu là khá đơn giản (xem Liệt kê 3).

Liệt kê 3. Thiết lập các giá trị ban đầu
...
        <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>
...

Biểu mẫu hiển thị một danh sách chọn cho mỗi phần tử box (ô vuông), vì vậy tất cả những gì bạn cần làm là có danh sách tham khảo phần tử box hiện tại. Bạn có thể thấy các kết quả trong Hình 6.

Hình 6. Thiết lập các giá trị ban đầu
Thiết lập các giá trị ban đầu
Tuy nhiên, lưu ý rằng không có gì ngăn cản không cho người chơi thay đổi dễ dàng các giá trị ban đầu nếu chúng bất tiện. Tất nhiên, điều này gây khó khăn cho toàn bộ mục đích của trò chơi này.
Làm cho các số ban đầu chỉ đọc
Để ngăn cản không cho người chơi thay đổi dễ dàng các giá trị ban đầu, bạn sẽ làm cho các giá trị đã được cung cấp trở thành "chỉ đọc." Bây giờ, dường như cách dễ nhất để làm điều đó sẽ là chỉ cần ra lệnh cho biểu mẫu không để cho người chơi thay đổi bất kỳ giá trị nào khác "0", nhưng hãy nhớ rằng một khi người chơi bắt đầu chơi trò chơi này, người đó sẽ thay đổi các giá trị không thành các giá trị khác, và để ngăn cản không cho họ thay đổi các giá trị mà chính họ đã chọn không phải là một ý tưởng tốt cho bạn.
Để giải quyết vấn đề này, chúng ta sẽ cần thêm một ít dữ liệu cho cá thể này (xem Liệt kê 4).

Liệt kê 4. Thêm thông tin cho cá thể
...
   <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>
...

Việc thêm các thuộc tính vào các giá trị ban đầu của bạn mang đến cho bạn cơ hội sử dụng một điều kiện liên kết để xác định rằng các giá trị này nên là chỉ đọc. Nói cách khác, người chơi sẽ không thể thay đổi giá trị của các danh sách chọn này.
Trong một thế giới lý tưởng, bạn sẽ có thể sử dụng "các lớp giả" để thiết lập một kiểu dáng cho các giá trị này sao cho người chơi có thể dễ dàng nhìn thấy các số nào mà chính họ đã chọn và các số nào đã được cung cấp từ đầu. Tôi đã thêm mã đó vào trong trang này, nhưng không may, nó vẫn chưa được Firefox hỗ trợ.
Nếu bạn tải lại trang này, bạn sẽ thấy rằng trong khi bạn có thể thay đổi các giá trị trống, bạn không thể thay đổi các giá trị ban đầu.
Ghi điểm trò chơi
Chắc chắn, bây giờ bạn đã có bảng rồi, bạn biết cách bạn đang làm như thế nào? Bạn có thể bắt đầu ghi điểm với chủ đề dễ dàng nhất, tìm kiếm các hàng đã được giải.
Các hàng
Để xác định xem một hàng đã được giải chưa, bạn chỉ cần xác định xem nó có chứa một cá thể của tất cả chín chữ số không. Vì chỉ có chín điểm, nên điều này cũng sẽ đảm bảo rằng không có các chữ số trùng lặp. Bạn có thể thực hiện việc này bằng một câu lệnh XPath đơn giản.
Để bắt đầu, nếu bạn muốn tìm bao nhiêu hàng đã có trong trò chơi, thì bạn có thể sử dụng câu lệnh XPath: count(/s:game/s:row).
Câu lệnh này sẽ cho bạn giá trị là 9. Tuy nhiên, bạn không muốn tất cả các hàng, bạn chỉ muốn tất cả các hàng đáp ứng điều kiện nhất định. Ví dụ, bạn có thể chỉ chọn các hàng chứa một ô có giá trị là 1: count(/s:game/s:row[s:box = '1']).
Với các hàng đó, bạn chỉ muốn những hàng cũng có một ô có một giá trị là 2: count(/s:game/s:row[s:box = '1'][s:box = '2']).
Và tiếp tục cho từng chữ số trong chín chữ số đó. Bạn có thể đặt tất cả chữ số lại với nhau để kiểm tra tất cả chín giá trị để bạn biết bạn đứng ở đâu (xem Liệt kê 5).

Liệt kê 5:
...
      <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>

Bằng cách thêm một phần tử cho một cá thể, bạn có thể dễ dàng nhìn thấy nơi bạn đứng, vì mỗi khi giá trị được cập nhật trong cá thể này, nó sẽ được cập nhật trên trang này. Bạn có thể thấy điều này trong Hình 7.

Hình 7. Tìm kiếm các hàng đúng
Tìm kiếm các hàng đúng
Hàng thứ hai có chính xác một cá thể của mỗi chữ số, vì vậy bạn có thể nhìn thấy giá trị là 1 với correctRows.
Các cột
Tạo một biểu thức XPath để kiểm tra các cột đúng có phức tạp hơn một chút. Thay vì tìm kiếm một hàng duy nhất đáp ứng nhiều điều kiện, ở đây cần tìm kiếm một cột duy nhất bao gồm một hàng có một chữ số. Ví dụ, bạn có thể đếm phần tử gốc chỉ khi biểu thức này có chứa một hàng có chữ số 1 trong cột đầu tiên: count(/s:game[s:row[s:box[1]='1']])
Nói cách khác, biểu thức sẽ đếm phần tử trò chơi khi và chỉ khi nó có một hàng đáp ứng điều kiện có phần tử box ở vị trí 1 có giá trị là "1." Không quan trọng nó là hàng nào, miễn là 1 là vị trí đầu tiên trong đó. Tương tự, bạn có thể đếm phần tử trò chơi chỉ khi nó cũng có chữ số 2 ở vị trí đầu tiên: count(/s:game[s:row[s:box[1]='1']][s:row[s:box[1]='2']])
Và cứ tiếp tục. Thật không may, câu lệnh này chỉ kiểm tra tính chính xác của cột 1, có nghĩa là bạn sẽ cần một một hàm count() mới cho mỗi cột, nhưng đó không phải quá tồi (xem Liệt kê 6).

Liệt kê 6. Tìm kiếm các cột đúng
...
  <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">
...

Bây giờ nếu bạn làm mới trang này, bạn sẽ thấy rằng giá trị "correct rows" (các hàng đúng) cập nhật khi bạn hoàn thành một cột, ví dụ như cột thứ ba trong Hình 8.

Hình 8. Sửa chữa một hàng
Sửa chữa một hàng
Tại thời điểm này, khi bạn đã giải được tất cả các cột và các hàng, bạn sẽ thấy một giá trị "correct rows" là 18 (chín dòng và chín cột). Nhưng bạn vẫn chưa xong đâu.
Thêm một bước nữa để ghi điểm
Đó vẫn chưa phải là quá tồi, nhưng bạn cần có thêm một bước nữa. Hãy nhớ rằng, ngoài các hàng và cột, người chơi chỉ có thể sử dụng các chữ số một lần trong từng ô trong số các ô vuông 3 x 3 được hiển thị trong Hình 1. Thật không may, không có câu lệnh XPath đơn giản nào sẽ cho phép bạn dễ dàng xác định xem tất cả các chữ số đã có mặt hay chưa, vì bất kỳ câu lệnh nào mà bạn xây dựng sẽ phải xác định các ô vuông cụ thể và các chữ số cụ thể. May mắn thay, có một tùy chọn.
Việc bạn có thể làm là sắp xếp từng ô vuông theo một hàng dữ liệu mà bạn tạo một cách rõ ràng cho mục đích này. Ví dụ, hãy xem xét phần tử XML được hiển thị trong Liệt kê 7.

Liệt kê 7. Phần tử box
<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>

Với chín phần tử box, nó tương ứng khá nhiều với một hàng. Hãy thử sắp xếp các ô vuông với các tọa độ sau đây (xem Liệt kê 8).

Liệt kê 8. Các tọa độ cho các ô vuông
<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>

Bạn có thể thấy dữ liệu phù hợp, và bạn có thể sử dụng một câu lệnh XPath đơn giản để xác định chính xác có bao nhiêu ô vuông (xem Liệt kê 9).

Liệt kê 9. Câu lệnh XPath đơn giản để xác định chính xác có bao nhiêu ô vuông
 
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'])

Lưu ý rằng câu lệnh này gần giống với câu lệnh được sử dụng để xác định các hàng ban đầu. Việc tiếp theo mà bạn sẽ cần làm là thêm tất cả các thông tin này vào trò chơi hiện có (xem Liệt kê 10).

Liệt kê 10. Thêm cá thể sắp xếp vào trò chơi
...
      <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">
...

Tất nhiên, việc chỉ thêm cá thể không thực sự làm bất cứ điều gì, bạn có thể chứng tỏ việc này cho chính mình bằng cách hoàn thành một ô vuông và lưu ý rằng giá trị "correct rows" không thay đổi. Để làm cho nó hoạt động, bạn sẽ phải hoàn thành việc sắp xếp.
Thiết lập các giá trị
Các cách khác nhau để thiết lập một phần tử bằng với giá trị của phần tử khác được xây dựng trong XForms, nhưng trong trường hợp này, bạn sẽ thực hiện điều khiển trực tiếp quá trình này. Bạn sẽ tạo một nút thiết lập một cách rõ ràng các giá trị riêng khi người chơi nhấn chuột (xem Liệt kê 11).

Liệt kê 11. Thiết lập các giá trị
...
    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>

Bây giờ khi người chơi nhấn chuột vào nút Check it! (Kiểm tra nó) , tất cả các giá trị này sẽ được thiết lập, chúng sẽ kích hoạt cập nhật tính toán "correct rows". Bạn có thể thấy điều này khi bạn tải lại trang và một lần nữa hoàn thành một ô vuông. Giá trị "correct rows" sẽ không thay đổi cho đến khi bạn nhấn nút này, như đã thấy trong Hình 9 (trước đó) và 10 (sau này).

Hình 9. Trước khi nhấn nút Check it
Trước khi nhấn nút Check it
Hình 10 cho thấy giá trị "correct rows" (các hàng đúng) sau khi nhấn nút.

Hình 10. Sau khi nhấn nút Check it
Sau khi nhấn nút Check it
Thế là, với việc bổ sung chín ô vuông đã xong, số lượng "correct rows" trước khi trò chơi hoàn thành phải là 27.
Thêm nút trình lên
Cuối cùng, bạn cần phải thêm nút trình lên. Bởi vì bạn muốn nút này chỉ xuất hiện một khi trò chơi đã sẵn sàng trình lên, bạn cần phải thiết lập sự liên quan của nó (xem Liệt kê 12).

Liệt kê 12. Thiết lập sự liên quan của nút trình lên
...
  <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>

Bắt đầu ở phía dưới cùng, nút submit (trình lên) đã được thêm vào và một phần tử mới được tham chiếu, phần tử submitButtonElement. Một câu lệnh liên kết cũng đã được thêm vào sao cho phần tử đó không xuất hiện trừ khi phần tử correctRows bằng 27. Để kiểm tra điều này, một tập dữ liệu "đúng" đã được tạm thời thêm vào. Khi bạn tải trang lần đầu tiên, bạn sẽ thấy có đủ tất cả các hàng và cột (xem Hình 11).

Hình 11. Tải dữ liệu đúng
Tải dữ liệu đúng
Tuy nhiên, một khi bạn nhấn nút Check it!, giá trị correctRows được cập nhật đến 27, và nút submit xuất hiện, bạn có thể thấy trong Hình 12.

Hình 12. Nút submit xuất hiện
Nút submit xuất hiện
Tại thời điểm này, bạn không có bất cứ nơi nào để trình dữ liệu lên, nhưng điều đó sẽ thay đổi trong phần 2.
Tóm tắt
Vì Sudoku dựa vào các mẫu dữ liệu rất cụ thể, nên bạn có thể sử dụng các biểu thức XPath để đánh giá quá trình người chơi đã làm trong một trò chơi cụ thể. Bạn cũng có thể sử dụng các mẫu này để dễ dàng tạo ra một bảng trò chơi cho phép người chơi chơi. Trong phần 1, bạn đã tạo ra biểu mẫu và cơ chế chơi; trong phần 2, bạn sẽ xem xét phần cuối dữ liệu, tải và lưu lại trò chơi và thực hiện các cải tiến khác.

Tải tại đây: http://www.mediafire.com/?4xb19blv1651mh6

Nguồn IBM
Bookmark and Share

0 comments:

Post a Comment

Next previous home

Cộng đồng yêu thiết kế Việt Nam Thiet ke website, danang