Bài viết sau đây là một phần của loạt bài. Để biết thêm các bài viết trong loạt bài này, hãy xem Nhân bản trò chơi 2048 trong Ruby. Để biết mã đầy đủ và cuối cùng, hãy xem ý chính.
Bây giờ chúng ta đã biết thuật toán sẽ hoạt động như thế nào, đã đến lúc nghĩ về dữ liệu mà thuật toán này sẽ hoạt động trên đó. Có hai tùy chọn chính ở đây: mảng phẳng thuộc loại nào đó hoặc mảng hai chiều. Mỗi cái đều có ưu điểm của nó, nhưng trước khi đưa ra quyết định, chúng ta phải tính đến một số điều.
câu đố KHÔ
Một kỹ thuật phổ biến để làm việc với các câu đố dựa trên lưới mà bạn cần tìm các mẫu như thế này là viết một phiên bản của thuật toán hoạt động trên câu đố từ trái sang phải, sau đó xoay toàn bộ câu đố bốn lần. Theo cách này, thuật toán chỉ cần được viết một lần và nó chỉ cần hoạt động từ trái sang phải. Điều này làm giảm đáng kể sự phức tạp và kích thước của phần khó khăn nhất của dự án này.
Vì chúng ta sẽ giải câu đố từ trái sang phải, nên có nghĩa là các hàng được biểu diễn bằng ma trận. Khi tạo một mảng hai chiều trong Ruby (hay chính xác hơn là bạn muốn nó được giải quyết như thế nào và ý nghĩa thực sự của dữ liệu), bạn cần quyết định xem bạn có muốn một ngăn xếp hàng hay không (trong đó mỗi hàng trong lưới được biểu thị bằng một mảng) hoặc một chồng cột (trong đó mỗi cột là một ma trận). Vì chúng ta đang làm việc với các hàng nên chúng ta sẽ chọn các hàng.
Mảng 2D này được xoay như thế nào, chúng ta sẽ xem sau khi chúng ta thực sự xây dựng mảng đã nói.
Xây dựng mảng hai chiều
Phương thức Array.new có thể nhận một đối số xác định kích thước của mảng mà bạn muốn. Ví dụ: Array.new(5) sẽ tạo một mảng gồm 5 đối tượng null. Đối số thứ hai cung cấp cho bạn một giá trị mặc định, vì vậy Array.new(5, 0) sẽ cung cấp cho bạn mảng [0,0,0,0,0] . Vậy làm thế nào để bạn tạo một mảng hai chiều?
Cách sai và cách tôi thấy mọi người thường thử là Array.new( 4, Array.new(4, 0) ) . Nói cách khác, một ma trận gồm 4 hàng, mỗi hàng là một ma trận gồm 4 số không. Và điều này dường như làm việc lúc đầu. Tuy nhiên, hãy chạy đoạn mã sau:
Nó có vẻ đơn giản. Tạo ma trận 4×4 gồm các số không, đặt phần tử trên cùng bên trái thành 1. Nhưng hãy in nó ra và chúng tôi nhận được…
Đặt toàn bộ cột đầu tiên thành 1, nó cho kết quả gì? Khi chúng ta tạo các mảng, lệnh gọi trong cùng Array.new được gọi đầu tiên, tạo thành một hàng. Sau đó, một tham chiếu đến hàng này được nhân đôi 4 lần để lấp đầy mảng ngoài cùng. Mỗi hàng sau đó tham chiếu cùng một mảng. Thay đổi một, thay đổi tất cả.
Thay vào đó, chúng ta cần sử dụng cách thứ ba để tạo mảng trong Ruby. Thay vì truyền một giá trị cho phương thức Array.new, chúng ta truyền một khối. Khối này được thực thi mỗi khi phương thức Array.new cần một giá trị mới. Vì vậy, nếu bạn nói Array.new(5) { get.chomp } , Ruby sẽ dừng lại và yêu cầu nhập dữ liệu 5 lần. Vì vậy, tất cả những gì chúng ta phải làm là tạo một mảng mới bên trong khối này. Vì vậy, chúng tôi kết thúc với Array.new(4) { Array.new(4,0) } . Bây giờ hãy thử trường hợp thử nghiệm đó một lần nữa.
Và nó làm điều đó như bạn mong đợi.
Vì vậy, mặc dù Ruby không hỗ trợ mảng hai chiều, chúng ta vẫn có thể làm những gì mình cần. Chỉ cần nhớ rằng mảng cấp cao nhất chứa các tham chiếu đến các mảng con và mỗi mảng con phải tham chiếu đến một mảng giá trị khác nhau.
Những gì mảng này đại diện là tùy thuộc vào bạn. Trong trường hợp của chúng tôi, ma trận này được trình bày dưới dạng hàng. Chỉ mục đầu tiên là hàng chúng tôi đang lập chỉ mục, từ trên xuống dưới. Để lập chỉ mục cho hàng trên cùng của câu đố, chúng tôi sử dụng a[0] , để lập chỉ mục cho hàng tiếp theo phía dưới, chúng tôi sử dụng a[1] . Để lập chỉ mục một ô cụ thể ở hàng thứ hai, chúng tôi sử dụng a[1][n] . Tuy nhiên, nếu chúng tôi đã quyết định về các cột… nó sẽ giống như vậy. Ruby không biết chúng tôi đang làm gì với dữ liệu này và vì nó không hỗ trợ mảng hai chiều về mặt kỹ thuật, những gì chúng tôi đang làm ở đây là một vụ hack. Chỉ truy cập nó theo quy ước và mọi thứ sẽ gắn bó với nhau.Quên những gì dữ liệu cơ bản phải làm và tất cả có thể sụp đổ rất nhanh.