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
Ý 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
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
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
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â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
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
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
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
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
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
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
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
Tải tại đây: http://www.mediafire.com/?4xb19blv1651mh6
Nguồn IBM
0 comments:
Post a Comment