首页 > 代码库 > org-mode游戏化的简单实现

org-mode游戏化的简单实现

12 Org Gamification

游戏化是一个很火的概念,Org-mode是一个实现GTD的极好工具,将两者结合起来想必非常有趣.


下面就是一个简单的对Org-mode游戏化的尝试,主要就是通过完成任务赚取积分,用然后用积分购买奖励物品.

1 积分操作

完成任务可以获取到积分,默认情况下[#A]级任务增加30积分,[#B]级任务增加20积分,[#C]级任务增加10积分.

但可以通过为每个entry设置REWARD属性的方式自定义完成该entry所获得的奖励积分数,需要为整数.

(defun org-gamification-point-to-score()
  "定位到积分行"
  (interactive)
  (goto-char (point-min))
  (when (not (search-forward-regexp "^#\\+SCORES: " nil t))
    (goto-char (point-max))
    (if (search-backward-regexp "^#\\+" nil t)
        (progn
          (end-of-line)
          (newline))
      (progn
      (goto-char (point-min))
      (newline)
      (previous-line)))
    (beginning-of-line)
    (insert "#+SCORES: "))
)

(defun org-gamification-get-score()
  "获取当前累计的积分数量"
  (save-excursion
    (org-gamification-point-to-score)
    (string-to-int (buffer-substring-no-properties (point) (line-end-position))))
)

(defun org-gamification-update-score(&optional newScore)  "更新当前积分"
  (save-excursion
    (org-gamification-point-to-score)
    (insert (number-to-string newScore))
    (insert " points")
    (backward-word)
    (kill-line)))

(defun org-gamification-add-score (score)
  "增加指定积分"
  (save-excursion
    (let (newScore)
      (setq newScore (+ score (org-gamification-get-score)))
      (org-gamification-update-score newScore))))

(defun org-gamification-remove-score-able-p (score)
  "判断是否能够扣减指定分数"
  (> (org-gamification-get-score) score))

(defun org-gamification-remove-score (score)
  "减少指定积分"
  (save-excursion
    (if (org-gamification-remove-score-able-p score)
        (org-gamification-update-score (- (org-gamification-get-score) score))
      (message "积分不足"))))

(defun org-gamification-get-entry-reward-score ()
  "获取完成entry该获得的积分"
  (save-excursion
    ;;(org-back-to-heading t)
    (if (org-entry-get nil "REWARD" t)
        (string-to-int (org-entry-get nil "REWARD" t))
      (+ 10 (/ (org-get-priority (thing-at-point ‘line)) 100)))))

2 奖励操作

可以使用积分购买奖励物品,带有`REWARD`标签的headline被认为是奖励物品

将奖励物品的标记为完成状态表示购买该奖励物品,会减少积分

使用命令`org-gamification-point-to-reward`跳转到奖励物品部分的headline处

使用命令`org-gamification-add-reward`来增加待购买的奖励物品

(defun org-gamification-point-to-reward ()
  "跳转到REWARD headline"
  (interactive)
  (let (reward-headline-pos)
    (setq reward-headline-pos (org-find-exact-headline-in-buffer "REWARDS" nil t))
    (when (null reward-headline-pos)
      (goto-char (point-max))
      (newline)
      (beginning-of-line)
      (insert "* REWARDS")
      (beginning-of-line)
      (setq reward-headline-pos (point))
      )
    (goto-char reward-headline-pos))
  )

(defun org-gamification-add-reward ()
  "增加奖励物品,需要用积分购买"
  (interactive)
  (save-excursion
    (let (reward-name reward-price)
      (org-gamification-point-to-reward)
      (end-of-line)
      (setq reward-name (read-string "请输入奖品名称: "))
      (org-insert-subheading nil)
      (insert reward-name)
      (setq reward-price (read-string "请输入奖品价格(整数): "))
      (org-set-property "PRICE" (int-to-string (string-to-int reward-price)))
      (org-set-tags-to ":REWARD:")
      ))
  )

(defun org-gamification-buy-reward-able-p()
  "判断是否能够购买奖励物品"
  (if (org-entry-get nil "PRICE" t)
      (org-gamification-remove-score-able-p (string-to-int (org-entry-get nil "PRICE" t)))
    (progn
      (message "该奖励没有设置PRICE")
      nil)))

(defun org-gamification-buy-reward ()
  "购买奖励物品,会减少积分"
  (when (org-gamification-buy-reward-able-p)
    (org-gamification-remove-score (string-to-int (org-entry-get nil "PRICE" t)))))

(defun org-gamification-sell-reward ()
  "售卖奖励物品,会增加积分"
  (if (org-entry-get nil "PRICE" t)
      (org-gamification-add-score (string-to-int (org-entry-get nil "PRICE" t)))
    (message "该奖励没有设置PRICE"))
  )

3 游戏环境初始化

使用命令`org-gamification-init`来初始化游戏,积分会清空为0

使用命令`org-gamification-start`来开启游戏

使用命令`org-gamification-end`来关闭游戏

(defun org-gamification-reward-p ()
  "判断该entry是否属于奖励"
  (save-excursion
      (org-back-to-heading)
      (find "REWARD" (org-get-tags) :test ‘string=)))

(defun org-gamification-entry-trigger (task-plist)
  "完成事项,增加积分"
  (let (from-state to-state )
    (setq from-state (plist-get task-plist :from))
    (setq to-state (plist-get task-plist :to))
    (save-excursion
      (when (and (member to-state org-done-keywords) ( or (member from-state org-not-done-keywords) (null from-state)))
        (if (org-gamification-reward-p)
            (org-gamification-buy-reward)
          (org-gamification-add-score (org-gamification-get-entry-reward-score))))
      (when (and (or (member to-state org-not-done-keywords) (null to-state)) (member from-state org-done-keywords))
        (if (org-gamification-reward-p)
            (org-gamification-sell-reward)
          (org-gamification-remove-score (org-gamification-get-entry-reward-score))))
      ))
  )

(defun org-gamification-entry-blocker (task-plist)
  "若动作会将积分变成负数,则不能进行该动作"
  (let (from-state to-state )
    (setq from-state (plist-get task-plist :from))
    (setq to-state (plist-get task-plist :to))
    (save-excursion
      (cond ((and (member to-state org-done-keywords) ( or (member from-state org-not-done-keywords) (null from-state)))
             (if (org-gamification-reward-p)
                 (org-gamification-buy-reward-able-p)
               t))
            ((and (or (member to-state org-not-done-keywords) (null to-state)) (member from-state org-done-keywords))
             (if (not (org-gamification-reward-p))
                 (org-gamification-remove-score-able-p (org-gamification-get-entry-reward-score))
               t))
            (t t))
      ))
)
(defun org-gamification-init()
  "org游戏化初始化函数     初始化积分为0     初始化游戏的hook     "
  (org-gamification-update-score 0)
  (org-gamification-start)
  )

(defun org-gamification-start ()
  "初始化游戏的hook"
  (interactive)
  (add-to-list ‘org-trigger-hook ‘org-gamification-entry-trigger)
  (add-to-list ‘org-blocker-hook ‘org-gamification-entry-blocker)
  )

(defun org-gamification-end ()
  "结束游戏"
  (interactive)
  (setq org-trigger-hook (remove ‘org-gamification-entry-trigger org-trigger-hook))
  (setq org-blocker-hook (remove ‘org-gamification-entry-blocker org-blocker-hook))
  )