wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
8 c* ^2 s) q) U- g' E借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- 5 U3 C! K+ K. L7 e) I# ^
- <p> </p><pre style="color: rgb(0, 0, 0); text-transform: none; line-height: normal; text-indent: 0px; letter-spacing: normal; font-style: normal; font-variant: normal; font-weight: normal; word-spacing: 0px; orphans: 2; widows: 2; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;">;; 定义新的游戏地图5 v1 e9 B! a; \0 X' u
- (def-map "/game/5x5.el" ; 对外开放的URL
( }$ u# e; A* s8 ~" V, I4 Z - 'tutorial-room-0) ; 默认的入口
/ _' M" [( R5 }9 Z
9 q6 \* j' f3 p. m, J, X- ;;; 游戏大厅
- @1 m& j! r+ a: s6 l - (def-room living-room( G; [6 B' C3 ]
- ;; 进入该房间后的提示语
/ i! N X- `' v) T7 G% T% R* Z - "1. 教程; n1 v) s: r; ]( Q* u2 G7 U
- 2. 入门(3x3)% O: x- g2 I* W; ?. l9 O
- 3. 初级(5x5)
. h$ }2 S+ B5 ~; i0 _, Y9 t - 4. 中级(7x7): D: E1 x9 A! g+ D% C5 Q
- 5. 高级(9x9)0 \ i8 l& @* [) d: O
- 0. 关于作者
2 v( C: @6 u0 H - 请选择1-5开始新游戏:"9 z0 G `% e8 o% X
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名4 T; ^ O( C" v. q7 r3 U
- ("1" tutorial-room-0)
' k7 ~- v, ^# C - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配
- d2 X) @: b( E) b7 b4 d, C3 R$ ? - ; 相应的返回也可以为函数,动态返回房间名, V' V' g; Z8 p9 N
- (t living-room)) ; 如果条件为t,为永真7 P2 `% s/ ~$ m4 k+ f
- - [( h- q: O& K- d }' K
- ;;; 作者信息) e% I- b% U$ r9 R @
- (def-room about-room0 m. g; N4 ?' b" u" r$ T
- "作者:redraiment
9 ~7 A# s" j g, r; k - 微博:http://weibo.com/redraiment
; H* M, M% f% m" s+ E; N - 有任何建议,欢迎在微博或微信上联系redraiment。) U6 S2 f n- p- n! A
- 请输入任意数字返回游戏大厅。"9 d- k# C1 u J4 q \: S
- (t living-room))0 S( N) w5 G' `( w
- 8 w6 M3 O3 E$ S3 K
- ;;; 教程" p7 ^" J& W8 j' J2 _6 T
- (defvar *wechat-5x5-tutorial-rooms* 09 K$ x- t d( a+ `) m* e
- "The number of tutorial rooms")5 [+ l% ~! @- L |3 X$ r
- - e1 F+ H2 L4 C+ G
- ;;; 简化教程的定义
( Z& d: j* K( e7 t: x* h' z; l, _0 @ - (defun string-last-line (content)
' D" X; f, i& S) q/ Z- R* _ ~ - "多行内容组成的字符串中的最后一行"5 h. M3 s, k5 i8 o( H9 E
- (with-temp-buffer! @- W( K* l0 b. z
- (insert content)% O: D3 I% {( k/ J* L* z4 h
- (buffer-substring (line-beginning-position)
% X; I- Z9 D% ^; J% ^( T - (point-max))))2 c% U: Q& F4 d8 x& W5 G
0 b+ L' c4 e8 Q. q8 I. x- (defun def-tutorial-room (prompt)
2 g# i, m' R8 I3 I7 Y4 d; J - "根据提示语自动生成教程房间。
/ A* \1 o8 M$ _* j0 Q$ M8 G - 8 `# r3 V; ?, y @2 t* I5 @6 R
- 1. 提取最后一行作为问题;3 y, D' d& J8 z/ B: E/ t
- 2. 分析问题,获取期望用户输入的内容;
, \( T4 ?( z5 f9 j3 N - 3. 定义教程房间和重复提问房间。"
/ ^& A, ?" K/ |: O" F8 D - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*))): M* m5 \7 h+ k3 n& a! {
- (repeat-room (concat room-name "-repeat"))# Q8 M4 q* [) v9 f
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))
+ s) w2 d4 u; i# w, W |5 V/ _" Y - (question (string-last-line prompt))
6 ]3 t: j2 F% | - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)7 x' w/ ^( t* b( H/ v
- (match-string 1 question))). y P5 h2 N6 C' ]- j
- (doors (if except
: w' R; d5 o* K) W - `((,except ,(intern next-room))
% i" U" \) [ x9 Y, Q" f - ("q" living-room)4 Z9 ~8 T( w0 ? o; {, N3 |1 b: O
- ("Q" living-room)4 _0 M# N8 ]' u& V6 Z) v
- (t ,(intern repeat-room)))
6 b2 P4 Q$ z* `1 x$ [7 y6 a - '((t living-room)))))
- p8 F# m$ |' r+ P& l- u - (def-room-raw (intern room-name) prompt doors)
" b) ?0 N3 o( D1 n W( q v2 R2 u - (def-room-raw (intern repeat-room) question doors)))5 i, [/ W, ?% ^# E, |7 f) t. M" M
- C- \3 v' U0 r- (defun def-tutorial (&rest prompts)) D, R4 X2 z& o" m2 V" W
- "批量生成教程房间。"; y# u; I" \1 i
- (dolist (prompt prompts)4 R+ R4 w% N: |, W- Z4 T7 X
- (def-tutorial-room prompt)))" A! H( [ M, ]$ X
- ) a* H; c, J: d. i! s/ T7 X/ E
- (def-tutorial
! T0 ?- i2 {7 t5 e, p1 `9 d; T - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
. x Z! |3 p a/ ?3 n6 T - 1. 教程( Y) ?- x, g5 ~8 f
- 2. 入门(3x3)
$ I3 B7 y' z& q& ^2 l! R7 U - 3. 初级(5x5)' w# b4 H1 h9 }
- 4. 中级(7x7)
" @; M( X* U# @, W1 y! ?, b - 5. 高级(9x9)# J* w: h. s" l
- 0. 关于作者% i, w! I; t) S
- 请选择1-5开始新游戏:, Y0 w/ S2 |- A% y
- 您现在正在游戏大厅里。7 ^" E, X7 h! V, N
- 请输入“2”进入入门级房间"
& l% [6 D( k" R7 b6 X6 X - " ①②③
9 V* T7 W+ S' U7 z( A6 G% l - 1 ■ . R% k4 ?: @: l& @$ G
- 2■■■3 H' O& n: \ }( B+ I( H
- 3 ■ 1 r4 s3 o; [& X. _
- 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!) ]2 b- @0 S6 e4 r6 w
- 请输入“22”来关闭第2行第2列的窗户。"
. E* U' u @' ?5 J. Z$ i! { - " ①②③+ m8 k4 C1 ]$ x( ?- g
- 1 4 l6 _: k' i* p2 M+ H6 M/ T
- 2 , I {4 ~1 @; R) y( x I% B
- 3
5 O/ {* v+ Y8 [6 D - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。
N& G' h1 D5 g6 _1 | - 请输入“11”,试着开启左上角的窗户。"
8 }" v' Y- m! J - " ①②③
: K \, \) R' { - 1■■
' {. _' `+ c$ J, { - 2■ + y3 x8 [2 \! g
- 3
( a* I5 L+ m$ \& ~+ a! Q$ J) R* ~+ @ - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。+ p* {4 ]9 A* Z p" P" X6 w) b
- 请输入“13”开启右上角的窗户。"
9 d$ `4 a, ]- c: q V - " ①②③
7 w4 z/ _4 K3 x, u - 1■ ■8 R* f' j! v, p1 O. n0 ^: w# R
- 2■ ■2 V0 N8 U |+ s: ?" |5 @% m0 y) e
- 3 ! \! A) U% Y$ @( W. I7 q
- 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。( i/ f8 p/ v! ]9 I
- 请输入“31”开启左下角的窗户。"% G, b. u$ }$ ]. l0 |0 K
- " ①②③- S ~3 M( h% U" U' s: C
- 1■ ■
5 G8 S+ Z& e' H/ m3 g) H# R - 2 ■( p) o1 N6 y6 U6 @; P0 R1 }
- 3■■ ) J2 r4 X' ]4 y; ^7 A- [4 A
- 此时,总共有5扇窗户被开启了。, p) Z9 }7 C, S
- 请输入“33”开启右下角的窗户。"
+ o9 X) ?: S- H, { - " ①②③# {6 Z% F1 O# c- L& c% f% u8 a
- 1■ ■7 \' ~0 g0 A/ U; A! r
- 2
# z1 [' P8 w$ F9 H - 3■ ■7 [4 G8 S) o/ a# J
- 现在,只有四个角落的窗户被打开。
5 v1 J/ i" q5 B% N- F" e - 请输入“22”完成最后一击!"
6 v* h I1 M! E7 U# l, _ - " ①②③
1 o4 M$ y1 d1 v4 L8 o2 A( [# P" x4 Q - 1■■■) ~+ k: Z8 k, ^0 w2 f
- 2■■■
. D0 t8 R1 o R/ j5 x; X1 _& e - 3■■■
4 h$ j" Y' V6 M- M% D, t/ I1 a - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!"): Z' M& ^+ @; i; v( F6 R) J
- , r! g# Z4 T" X% N; q& A2 N
- ;;; 棋盘2 H) N5 L& T) `' [: H* h4 A
- (defconst *wechat-5x5-white-chess* 12288
! a& m8 d: a2 D' g0 L; }; W7 [ - " ")
* o s! N2 n& S
5 i* ^4 N" [! O7 Q! |; G- (defconst *wechat-5x5-black-chess* 9632
- D. S$ Z+ Z& R! W: e/ X/ @" U. T - "■")
u" L2 v9 D+ C3 x! U
" n# q* i) M: N- (defmacro with-board (&rest body)
9 ?$ u- G4 D9 E; j4 s( Q - `(with-temp-buffer
- T& K$ C6 J& l3 j# j - (unwind-protect2 ? S' @; y% ~: W ?) t
- (progn) k' E% v7 L0 d, k0 X
- (if (session "board")
2 d9 a( E0 F/ W; q - (insert (session "board")))
% H# H6 Z/ E, r0 T8 s4 f9 I - ,@body)
. C4 r5 M6 @# u, } - (session "board" (buffer-string)))))
% A$ f9 J; w8 T U - 5 ~. P8 h1 R6 V, A* W7 B7 }5 M
- (defun board-init (size)0 j* C/ p5 t$ E
- (session "size" size)
' J* d, u5 P; ?% X7 [ - (session "step" 0) |. C4 }8 f- A7 Y6 }& o
- (erase-buffer)- S* `/ g+ _) u; W6 G7 r
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))
0 _" q& X$ b: f/ j - (dotimes (row size)5 T4 l3 a: g$ U2 f
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))* J' x% V7 T9 f4 X& f
- 9 ~( O: M/ D( w4 x# c# N& M$ T
- (defun board-contains-p (y x)
: [6 l% ^. N2 ]3 I2 F3 M* W - (let ((size (session "size")))
% V0 u7 Z# a/ f6 [% H - (and (<= 1 y) (<= y size); N& h$ R C5 i
- (<= 1 x) (<= x size))))# P" L* Z7 }9 F; C& I8 j2 o
. G i' f8 d" S- (defun board-toggle (y x)
2 F3 G6 q) p- h+ n0 }5 | - (when (board-contains-p y x)
9 }) ]( i) b9 _ - (goto-line (1+ y))$ s. V+ l! @' s# A8 ]
- (beginning-of-line)
) g- B- @% \9 z: u - (forward-char x)
1 n# G' p4 P, h4 I7 o i) s - (insert (if (= *wechat-5x5-white-chess* (following-char))
8 g6 t; O9 M5 Z' r+ K4 t, E$ [) T - *wechat-5x5-black-chess*
; h4 Q1 R4 s5 ^8 L& J* C. C - *wechat-5x5-white-chess*))1 R/ s$ F# }. W/ W' L: \$ A
- (delete-char 1)))
& K; J5 U) ]/ A1 w, Y0 T) C8 A9 y
' C; ]* q/ w( B4 `" B! b- (defun board-put (y x)
% l! b! K% B0 N - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
- w- X' n1 r! ?: R6 E& l: m7 F - (board-toggle (+ y (first dir))
# e* ?+ i& [& G; A - (+ x (second dir)))))
# I- ^# E$ u' h7 K+ B4 \* E - # F% a6 x, s# a4 O' w$ }2 [) E. P
- (defun game-over-p ()
6 Y2 g' P* i3 E- ^ - (beginning-of-buffer)2 r I: n Y/ |
- (not (search-forward (string *wechat-5x5-white-chess*) nil t)))1 g# W* A* g3 X. E6 T: g% T+ `
- ) u, Q8 m! Z P
- (defun board-show ()
4 f% ~. f, \' | - (with-board" u7 i5 S y+ x/ O+ `! X
- (concat (buffer-string)* ?' {# [* m4 j* m7 m' U1 D8 t) H
- (if (game-over-p)
$ J: o* r; e9 @# @- S5 j8 H - (format "共%d步,输入任意内容返回大厅" (session "step"))
3 f T$ b7 p+ @0 S5 y x( Z& F - (format "第%d步" (1+ (session "step")))))))
! a7 i8 L4 d1 O! }8 @; ` - 1 }7 s) E) e3 S, }) x y
- (defun board-position-parse (cmd)# I6 ?; `, I7 h4 z
- (if (= (length cmd) 2)9 S- k2 d! B3 p0 Z$ \1 V) g7 q
- (list (string-to-int (substring cmd 0 1))
; K" D* V& T# l, l" _/ j - (string-to-int (substring cmd 1 2)))& _7 C6 ^5 l- n; T3 @: U
- '(0 0)))3 V& r$ w! _1 a+ T; c+ q
8 p5 w9 `. Q0 b0 F" T+ p- ;;; 游戏房间 U, O1 \6 i$ M0 j
- (defun game-room-init (cmd)
) [, d& f/ N1 ]/ Q5 M; E1 { - (let* ((middle (string-to-int cmd))6 e6 G0 \: D! i; m f3 Q
- (size (1- (* 2 middle))))9 f" o8 b; ~1 P) _( Q4 t
- (with-board# ~- r* N5 `! |; \0 |+ K, v: J
- (board-init size)
) m- C7 G% D' m7 I( z* q% I - (board-put middle middle)))0 }* e# }' O( ~) W" X$ X
- 'game-room)2 g# M! A1 g2 \
- 1 P$ t6 `3 X: T" b! e& E3 U
- (def-room game-room
7 ]3 G0 K) p7 l9 K - #'board-show* M. J- j B3 R/ V! I% B
- (t (lambda (cmd)9 s& Z& O8 Z1 e% b( ]9 G
- (with-board0 x1 d4 z+ N: v4 n! \" F; A% i
- (if (game-over-p)
' K4 a3 _" l: j8 E3 [0 Z - 'living-room+ ?4 b* i) Z- y9 a) A& d) g5 X
- (destructuring-bind (y x) (board-position-parse cmd)
0 g0 O2 M% F- Y( K' f - (when (board-contains-p y x)$ b' d! C5 `$ f, w5 }& h/ z! `( t6 S
- (board-toggle y x)
/ E1 _0 T) O$ ?# g. l- C3 \ - (session "step" (1+ (session "step"))))& [/ C$ w% |' m% _1 A
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|