Viết chương trình finite-state machine với Akka
Scala
50
Akka
2
White

Ngoc Dao viết ngày 20/03/2016

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) 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 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 "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 kí tự để làm mã số
  • Để mở khóa user sẽ nhập mã số, mỗi lần chỉ được nhập 1 kí tự, các kí tự 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 5 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 5 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, String] 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à String
  • 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 until, việc chuyển trạng thái có thể ghi nhận độc lập ở chung một chỗ bằng notifying, 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, "") 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à chuỗi rỗng
  • Timeout có nghĩa sau thời gian đánh dấu bằng until, 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

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

Xem mã nguồn, bạ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". Bạn hãy thử sửa mã nguồn để thêm trạng thái này xem sao.

Đọc thêm

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Ngoc Dao

102 bài viết.
300 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
66 8
Làm thế nào để nâng cấp trang web mà không làm gián đoạn dịch vụ? Đây là câu hỏi phỏng vấn các công ty lớn thường hỏi khi bạn xin vào vị trí làm lậ...
Ngoc Dao viết hơn 2 năm trước
66 8
White
42 1
Bài viết này giải thích sự khác khác nhau giữa hai ngành khoa học máy tính (computer science) và kĩ thuật phần mềm (software engineering), hi vọng ...
Ngoc Dao viết hơn 2 năm trước
42 1
White
38 2
Nếu là team leader, giám đốc công ty hay tướng chỉ huy quân đội, vấn đề cơ bản bạn gặp phải là “hướng mọi người đi theo con đường bạn chỉ ra”. Thử...
Ngoc Dao viết hơn 2 năm trước
38 2
Bài viết liên quan
White
10 0
Kí tự Regex cơ bản Về cơ bản thì các sử lý matching của scala.util.matching.Regex sẽ được "phó thác" (delegate) cho java Regex. Bạn có thể tạo một ...
huydx viết hơn 3 năm trước
10 0
White
7 1
Trong scala kí tự _ được dùng với khá nhiều mục đích .. không liên quan đến nhau. Tạm note lại cái đã khi nào có time sẽ quay lại viết cẩn thận sa...
huydx viết hơn 3 năm trước
7 1
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
102 bài viết.
300 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!