2013-03-28 19 views
6

Tôi đang viết một chương trình Sokoban ở Haskell bằng thư viện Gloss và tôi đạt đến điểm tôi muốn, khi người chơi đánh bại một cấp, tải ở cấp độ mới từ tệp văn bản và có chương trình tiếp tục.Làm thế nào để tránh hoạt động trong đơn nguyên IO cho toàn bộ chương trình này?

Tôi đang gặp một chút khó khăn với điều này vì những hạn chế Gloss - chiếc play chức năng để thiết lập một trò chơi và có nó liên tục cập nhật trông như sau:

play :: forall world 
     . Display      --^Display mode. 
     -> Color      --^Background color. 
     -> Int       --^Number of simulation steps to take for each second of real time. 
     -> world      --^The initial world. 
     -> (world -> Picture)   --^A function to convert the world a picture. 
     -> (Event -> world -> world) --^A function to handle input events. 
     -> (Float -> world -> world) --^A function to step the world one iteration. 
             -- It is passed the period of time (in seconds) needing to be advanced. 
     -> IO() 

(sao chép trực tiếp từ http://hackage.haskell.org/packages/archive/gloss/1.7.4.1/doc/html/Graphics-Gloss-Interface-Pure-Game.html)

đây là world loại I đang sử dụng:

data Game = Game 
    { levelNumber :: Int, 
    currentLevel :: Level Square, 
    won   :: Bool } 

nơi Level s chứa các khối ở cấp độ hiện tại. Tôi đọc trong Game s sử dụng một cái gì đó như thế này (chưa thực sự làm một tổng quát được nêu ra, nhưng điều này về cơ bản là tất cả nó sẽ là một cuộc tranh luận với filename):

startGame = do 
    lvl <- readFile "levels/level001.lvl" 
    let lvl' = parseLevel lvl 
    return $ Game 1 lvl' False 

Vì vậy, khó khăn của tôi là phát sinh do của các chức năng cập nhật trong play. Tôi có thể dễ dàng chụp Game và tạo ra Picture (và Game, v.v.) mà không phải đọc bất kỳ dữ liệu nào từ hệ thống tệp nếu tôi chỉ hoạt động ở một cấp, nhưng vì tôi đang tải các cấp từ tệp trong giữa trò chơi, tôi không biết cách tránh tạo ra tất cả Game s IO Game s của mình. Có lẽ điều này là không thể trong hoàn cảnh này, và có lẽ đó là vì một lý do chính đáng? Tôi sẽ luôn hoạt động trên Game được lấy từ một tệp nhưng tôi không biết liệu nó có thể tránh được tại bất kỳ điểm cụ thể nào không và nếu có, tôi muốn tránh nó.

+3

Bạn có thể sử dụng IO lười ("BOOO! HISSSSS !!!") ví dụ: với gói (directory) 'tree-tree' để tải toàn bộ cây thư mục của các tệp trò chơi trước khi gọi' play', và truyền xung quanh kiểu cây kết quả trong 'Trò chơi' của bạn. Hoặc đặt tất cả các cấp của bạn trong một tệp và thực hiện tương tự với tiêu chuẩn 'readFile'. – jberryman

+3

Nếu không, hãy cắn và sử dụng ['Graphics.Gloss.Interface.IO.Game.playIO'] không đúng (http://hackage.haskell.org/packages/archive/gloss/latest/doc/html/Graphics- Gloss-Interface-IO-Game.html # v: playIO). Bạn vẫn có thể giữ hầu hết logic của mình trong các hàm thuần túy. – hammar

+0

Bạn có thể cho chúng tôi thấy trình phân tích cú pháp không? Không có khả năng trở lại ví dụ như các chuỗi bình thường? –

Trả lời

3

Tôi đã sử dụng Gloss's playIO từ Graphics.Gloss.Interface.IO.Game. Tôi cần thay đổi một vài chức năng của mình để hoạt động trên các kiểu dữ liệu thuần túy và xuất chúng được bọc trong đơn nguyên IO. Dưới đây là các loại tôi đã phải thay đổi:

worldToPicture :: World -> IO Picture 
eventHandler :: Event -> World -> IO Picture 
stepWorld  :: Float -> World -> IO World 

Đối với hầu hết các phần, điều này chỉ dẫn đến thêm một số return s chức năng hiện đang tồn tại của tôi, nhưng nó đã kết thúc thêm rất nhiều chức năng (như tiết kiệm một cách nhanh chóng , tải cấp độ mới, sử dụng các tập tin BMP cho đồ họa, vv). Tôi cũng có thể giữ hầu như tất cả mã hiện tại của mình miễn phí từ IO vì các chức năng mới vẫn lấy kiểu dữ liệu thuần túy làm tham số. Nó đã trở thành một refactor thực sự dễ dàng và giải quyết vấn đề của tôi một cách hoàn hảo.

Các vấn đề liên quan