Tốc độ tìm đường đi trong game này rất quan trọng vì càng lên level cao, việc di chuyển của con rắn có thể lên tới 60 ơ trong một giây (tương ứng FPS = 60) hay thậm chí có thể cao hơn. Nếu tốc độ quá chậm có thể khiến game bị “đứng” mỗi khi thuật toán này được sử dụng và tệ hơn là con rắn sẽ lao đầu vào tường như một chiếc xe mất phanh.
Nếu khi test bạn thấy tốc độ chưa được ưng ý, đặc biệt trên các máy yếu, hãy thử làm chậm tốc độ game lại và tăng thêm độ phức tạp của bản đồ. Một cách khác nữa là giảm kích thước bản đồ để giảm khơng gian tìm kiếm. Tuy nhiên bạn khơng cần q lo lắng về tốc độ tìm đường, theo thử nghiệm của ta thì với FPS = 1000 và độ dài rắn lên tới 100, game vẫn chạy ổn và con rắn không để mất một “viên kẹo” nào.
Để cài đặt thuật toán này, trước tiên ta tạo một lớp Node dùng để lưu giữ thông tin của một phần tử trong mảng hai chiều. Ta cần hai thuộc tính x,y để lưu lại chính vị trí dòng và cột của Node trong mảng. Như vậy ta có thể xác định được ngay vị trí của một đối tượng Node trong mảng mà không cần lặp qua mảng để tìm kiếm (do Node được lưu trong Queue).
function Node(x,y,value){ this.x = x; this.y = y; this.value = value; this.visited = false; }
Mặc dù dễ hiểu nhưng cách này sẽ khiến việc tìm được chưa đạt được tốc độ mà ta mong muốn do phải so sánh 2 thuộc tính value và visited để xác định một Node đã được “ghé thăm” chưa. Vì vậy, ta sẽ bỏ đi thuộc tính visited và tận dụng thuộc tính value. Ta có lớp Node mới:
var BLANK = 0; var WALL = 1; var SNAKE = 2; var VISITED = 3; function Node(x,y,value){ this.x = x; this.y = y; this.value = value; }
Vịng lặp chính của thuật tốn: // ...
// add the start node to queue open.enqueue(start);
// the main loop
while(!open.isEmpty()) {
node = open.dequeue(); if(node)
{
95 | P a g e { return getSolution(node); } genMove(node); } else break; } // ...
Phương thức sinh các nước đi tiếp theo tại vị trí đầu rắn:
// generate next states by adding neighbour nodes function genMove(node)
{
if (node.x < cols - 1)
addToOpen(node.x + 1, node.y, node); if (node.y < rows - 1)
addToOpen(node.x, node.y + 1, node); if (node.x > 0)
addToOpen(node.x - 1, node.y, node); if (node.y > 0)
addToOpen(node.x, node.y - 1, node); }
Phương thức thêm một nước đi vào tập Open, ta chỉ cần thêm các node rỗng (BLANK). Khi thêm vào, ta đặt lại trạng thái của node là VISITED để khơng thêm nó vào lần thứ 2:
function addToOpen(x,y, previous) {
var node = nodes[x][y];
if (node.value==BLANK) {
// mark this node as visited to avoid adding it multiple times node.value = VISITED;
// store the previous node
// so that we can backtrack to find the optimum path // (by using the getSolution() method)
node.previous = previous; open.enqueue(node);
} }
Phương thức dùng để lấy đường đi sau khi tìm được vị trí của node đích. Ta chỉ cần backtracking các node dựa vào thuộc tính previous của các node:
function getSolution(p) { var nodes = []; nodes.push(p); while (p.previous) { nodes.push(p.previous); p = p.previous; }
96 | P a g e
return nodes; }
Như vậy, khi đã có đường đi đến đích, ta chỉ cần cho rắn di chuyển từng ô dựa theo đường đi này cho đến hết độ dài.