Vinova tuyển lập trình viên Mobile & Web ở Hà Nội, lương $300-1000

Article: FSM với Akka 1398

JVM
ngocdaothanh.myopenid.com 175
Updated about 1 month ago

FSM (Finite State Machine) là design pattern được dùng nhiều khi viết game. Cốt lõi của FSM là:

State(S) x Event(E) -> Actions(A), State(S')

Có nghĩa khi ta đang ở trạng thái S mà có sự kiện E xảy ra, thì ta sẽ thực hiện hành động A rồi chuyển sang trạng thái S'.

Thư viện Akka của Scala từ sau phiên bản 0.10 (ra ngày 22/8/2010) sẽ có thêm tính năng FSM. Bài viết này giới thiệu cách sử dụng tính năng này. Để hiểu bạn cần có chút kinh nghiệm Scala.

Cách thiết kế chương trình FSM

Ta theo các bước sau:

  1. Liệt kê các state có thể có
  2. Tất cả state đều sử dụng chung một biến state data, cần thiết kế cấu trúc dữ liệu cho state data này
  3. Ứng với từng state, liệt kê các event có thể có
  4. Ứng với từng event, nêu ra action sẽ thực hiện và trạng thái tiếp theo; khi xử lí event và action, thường phải tham khảo state data

Nguyên lí thiết kế là vậy, nhưng thường ta không tự viết mã thủ công từ đầu đến cuối, mà sẽ dựa vào thư viện. Nó giúp ta một số việc:

  • Kiểm tra xem event có hợp lệ hay không. Ví dụ ứng với trạng thái S nào đó chỉ có thể xảy ra sự kiện E1 hoặc E2 nào đó mà thôi.
  • Tự động sinh ra event timeout. Ví dụ khi viết game cờ tướng, ta muốn khi user đang ở trạng thái phải đi nước nào đó, nếu quá 1 phút mà không đi thì sẽ bị xử thua. Dùng thư viện FSM thì có thể thiết kế để sau 1 phút nếu nó không thấy có event nào xảy ra, thì nó sẽ tự sinh ra event timeout. Ví dụ khác, khi viết game trồng trọt, ta muốn nếu sau 5 phút nếu không có sự kiện nào xảy ra đối với cái cây (ví dụ user xoá cây khỏi mảnh ruộng) thì thư viện sẽ tự động sinh ra event timeout, chương trình của ta sẽ bắt event này rồi thực hiện action là làm cho cây mọc cao to lên một chút.

Demo tính năng FSM của thư viện Akka

Akka là thư viện của Scala, được thiết kế để nhái lại thư viện OTP của Erlang. Akka muốn nhái vì OTP có nhiều tính năng cao cấp như gen_server, gen_fsm, supervisor v.v., kết hợp với tính năng hot code swapping của máy ảo BEAM của Erlang đã cho phép viết ra hệ thống có uptime lên đến 99.9999999%, nghĩa là chạy không bao giờ bị chết và có thể nâng cấp nóng không cần phải restart chương trình!

Đề bài

Ta sẽ dựa trên Akka để viết chương trình "code lock" thể hiện cái khóa số ở cửa ra vào (của phòng thí nghiệm, data center v.v.), một chương trình siêu kinh điển của FSM:

  • Khóa có 2 trạng thái: locked và opened
  • Khi khởi tạo, khóa ở trạng thái locked và được set một chuỗi số để làm mã số
  • Để mở khóa user sẽ nhập mã số, mỗi lần chỉ được nhập 1 con số, các con số sẽ được lưu vào buffer
  • Nếu lúc đang nhập dở dang, mà user ngưng không nhập nữa, thì sau 3 giây buffer sẽ tự động bị reset
  • Sau khi nhập đúng mã số, khóa sẽ chuyển sang trạng thái opened trong 3 giây, rồi lại tự động chuyển sang trạng thái locked

Bài làm

Xin xem mả nguồn ở GitHub:

  • Triết lí của Scala là kiểm tra kiểu chặt chẽ để tránh lỗi cú pháp nhảm nhí: FSM[LockState, Seq[Int]] cho biết trạng thái có kiểu là LockState và mỗi trạng thái sẽ được kèm theo dữ liệu có kiểu là Seq[Int] (chuỗi các con số integer)
  • Akka có DSL cho FSM cực kì hấp dẫn: trạng thái đánh dấu bằng when, sự kiện đánh dấu bằng Event(sự kiện, dữ liệu kèm theo trạng thái), chuyển đổi trạng thái đánh dấu bằng goto, nếu không muốn chuyển trạng thái thì dùng stay, chuyển đổi dữ liệu đánh dấu bằng using, timeout đánh dấu bằng forMax, việc chuyển trạng thái có thể ghi nhận độc lập ở chung một chỗ bằng onTransition, trạng thái bắt đầu đánh dấu bằng startWith; xem thêm mã nguồn của FSM và unit test
  • startWith(Locked, Nil) có nghĩa trạng thái bắt đầu sẽ là Locked (ổ khoá bị khoá), user chưa nhập mã số gì hết nên dữ liệu đi kèm là rỗng
  • Timeout có nghĩa sau thời gian đánh dấu bằng forMax, nếu không có sự kiện nào sinh ra (do user nhập mã số), thì thư viện sẽ tự động sinh ra sự kiện StateTimeout
  • Để dễ sử dụng, từ bên ngoài chỉ cần gọi các hàm tiện ích như start, stop, button. Bên ngoài không cần biết cụ thể message (event) nào được truyền. Đây là tinh thần của lập trình hướng đối tượng. Tuy nhiên không nên lạm dụng tạo wrapper.

Để chạy thử, xin xem README.

Xem mã nguồn, để ý thật ra để rõ ràng, ngoài 2 trạng thái trên, nên thêm trạng thái nữa là "đang nhập dở dang". Nghĩa là trạng thái Locked được tách thêm thành 2 trạng thái là chưa con số nào được nhập và đã có con số được nhập nhưng chưa nhập đủ tất cả các con số. Hãy thử sửa mã nguồn để thêm trạng thái này xem sao.

Đọc thêm

  • gen_fsm
  • SBT, công cụ để biên dịch mã nguồn ví dụ

Comments

You must login to be able to comment

Uploaded files

No file uploaded yet

You must login to be able to upload

Nhà tài trợ:

Mọi người đều tự do viết bài, sửa bài của người khác, và bình luận ở trang web này. Bạn muốn chủ động tạo bài mới để chia sẻ kinh nghiệm với mọi người? Xin click link ở dưới.

Create new content