试图构建一个没有任何状态的井字游戏(纯fp风格)



我正在学习Clojure,并试图实现一个简单的tic-tac-toe(或morpion)。但我正在努力工作,以避免任何引用/原子/代理。。。

我知道我可以在控制台应用程序中轻松地做到这一点,因为它不会是事件驱动的,这样我就可以准确地知道何时传递新的板值。我是说

  • 我的板将是一个向量的向量([[:circle 0:cross][:any:circle:empty][:cross:none:none]]其中只有:circular和:cross值很重要)
  • 我会有一个简单的基于文本的方法,它使用一个板并返回一个字符串

但是,每当我想实现一个图形面板时,我都想知道如何才能做到这一点。例如:

  • 我正在创建一个javax.swing.JPanel的实例(请不要关心这里使用的其他方法):

    (defn make-board-panel
    "Builds the board JPanel, whose state is given by board argument,
    and turn-piece argument (must be either :circle or :cross, I mean the next
    value to set in the board)."
    [board turn-piece]
    {:pre ['morpion.core/is-board? board, 'morpion.core/is-a-player-piece? turn-piece]}
      (proxy [JPanel MouseListener] []
        (paintComponent [g]
            (proxy-super paintComponent g)
            (paint-board-lines g)
            (paint-board board g)
        )
        (mouseClicked [e]
            (if (and (abs-coord-in-cell? (.getX e)) (abs-coord-in-cell? (.getY e)))
                (let [cell-x (abs-coord-to-rel (.getX e))
                        cell-y (abs-coord-to-rel (.getY e))]
                    ;; Here I compute the new board value
                )  
                nil ;; Here I wish I could return the new board value to the caller of make-board-panel, but this seems impossible !
            ) 
        )
        (mouseEntered [e])
        (mouseExited [e])
        (mousePressed [e])
        (mouseReleased [e])
       )
    )
    
  • 但我似乎没有办法从Panel的mouseClicked事件中获取板的新值:除非我引入一个状态变量

那么有没有一个变通方法:

我完整项目的来源:

  • Morpion核心
  • Morpion图案

(由于Igrapenthin的评论,我试图改进,但我仍然失败了。)

(defn make-board-panel
 [board turn-piece output-fn]
 (proxy [JPanel MouseListener] []
   ;; ...
   (mouseClicked [e]
     (when (and (abs-coord-in-cell? (.getX e)) 
           (abs-coord-in-cell? (.getY e)))
       (let [cell-x (abs-coord-to-rel (.getX e))
             cell-y (abs-coord-to-rel (.getY e))]
          ;; Here I compute the new board value
          (output-fn new-board-value))))
    ;; ...
    ))

最新更新