wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
l# _: Z9 L2 @ W( }' ?) J/ {+ G借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- . m. Z7 T) K. D- Q r3 Z
- <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;">;; 定义新的游戏地图 a1 C% v/ i A
- (def-map "/game/5x5.el" ; 对外开放的URL/ h. `% i- g. |" ^3 ?/ G( |
- 'tutorial-room-0) ; 默认的入口$ a" O7 g) T" T
) S- B1 Q/ w. P2 {8 w- ;;; 游戏大厅
. Z# U4 a9 Y% F. T8 m - (def-room living-room4 m' ~4 n6 b3 t" N6 q+ l5 @
- ;; 进入该房间后的提示语% O7 Y+ J; a9 w$ q
- "1. 教程
. v' O# I+ x7 L D' H - 2. 入门(3x3)" }5 ]. R- F( L( Y- l
- 3. 初级(5x5)
% q' S5 c- \- r - 4. 中级(7x7)) ~# L3 M! c0 j1 H' P
- 5. 高级(9x9)
5 A3 I& t: J* ` - 0. 关于作者7 M- }0 m8 I, o1 W! C
- 请选择1-5开始新游戏:"- u; o& ^4 T( C2 A
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
# M: I3 G r( j - ("1" tutorial-room-0)
; ]0 S0 j3 x o% X+ Z - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配" k, C& l" O1 p
- ; 相应的返回也可以为函数,动态返回房间名7 T3 ] e8 o: V6 O1 I
- (t living-room)) ; 如果条件为t,为永真/ l! }9 v! h! v1 I8 L, H' M9 ~
# i2 R8 c# s. o2 g- ;;; 作者信息 c& H8 a! T7 K' P1 y& F) g2 j
- (def-room about-room5 V& U! h3 w/ {
- "作者:redraiment6 b! x' _# F7 q% j
- 微博:http://weibo.com/redraiment4 X0 K+ l4 L0 o8 `/ x
- 有任何建议,欢迎在微博或微信上联系redraiment。
4 x3 C4 @( U7 l0 I: h - 请输入任意数字返回游戏大厅。", Z* s( I* H( _. a
- (t living-room))1 G) }; T+ r- L) m2 i X
! f; ^7 c ]- g- A" w- ;;; 教程
* y9 t" t+ \9 v# d% |' p7 { - (defvar *wechat-5x5-tutorial-rooms* 0
. a; ~: @9 R7 u' x# e - "The number of tutorial rooms"); h+ C+ x4 h0 V" X
: A! [5 c" x$ z6 G; R- ;;; 简化教程的定义6 v9 _: n0 b, |4 n2 V/ v' m
- (defun string-last-line (content)* u/ c0 [# V% m
- "多行内容组成的字符串中的最后一行"
$ _( M8 Q! `1 g! m( w5 E$ Y5 Z& p: b - (with-temp-buffer) h8 S* C# |( `0 [6 y2 ]) P
- (insert content)/ {, W! h N3 V" c% L
- (buffer-substring (line-beginning-position)( N. r9 H' V% ], W% X- I
- (point-max))))
" n2 {9 f; s3 A, F' T/ k
( ~! U" v# l# ? [" r8 e- (defun def-tutorial-room (prompt)
& J9 q9 N! V, j! \3 N( A# X - "根据提示语自动生成教程房间。" {( ~6 c. Y& L% c" h
- ! i- n4 b; f$ l
- 1. 提取最后一行作为问题;" W* N+ h2 t5 D; k1 X6 H/ `( @+ U
- 2. 分析问题,获取期望用户输入的内容;7 ^' r9 p: y& ]/ A) M
- 3. 定义教程房间和重复提问房间。"
; d$ H0 R! M7 G* q! h2 R - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))0 M. t, w0 o& i) E) F
- (repeat-room (concat room-name "-repeat"))- }1 E: @3 }) y( [/ w6 q
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))$ ?+ M" C, m3 A. ~+ n4 w: e
- (question (string-last-line prompt))
& ]( A! J8 H) u6 p - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)2 `7 @- O8 _! R7 {& ~! G! d
- (match-string 1 question)))
& w! F8 X' n N - (doors (if except
, f4 h" F9 M( F - `((,except ,(intern next-room)): K# ~$ f" N* h% |
- ("q" living-room)! I2 ~) q! C) p. ]; I
- ("Q" living-room)
& |4 S/ e. S4 l - (t ,(intern repeat-room)))5 X, h* V; B8 I3 A. R% E
- '((t living-room)))))$ g O" _2 D0 {9 r
- (def-room-raw (intern room-name) prompt doors)) b; D# T1 o5 U Z2 ]
- (def-room-raw (intern repeat-room) question doors)))
! a& V _5 Z: |+ c3 W* U - - O$ R/ I6 x. _7 }" P
- (defun def-tutorial (&rest prompts)4 o' O( r1 v2 G6 u. O
- "批量生成教程房间。"
& K, w# n, E. k" U - (dolist (prompt prompts)+ w% Z3 p' h0 e4 |6 [
- (def-tutorial-room prompt)))
$ X/ j# X8 a1 p y6 N, f/ W/ d - 2 h4 s* D9 j! i! N4 r r/ u
- (def-tutorial+ L8 b' I) [" X" r
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。: Q/ K9 P5 ~2 B2 S5 O( u- O* a
- 1. 教程0 |2 L7 B" A0 Y9 w7 M* q: O0 E
- 2. 入门(3x3)! W- t* W( L4 E* N
- 3. 初级(5x5)
2 r# N2 {0 M- q - 4. 中级(7x7) l8 A8 Y0 c6 H( [# C
- 5. 高级(9x9)( v. E; v, Q6 q5 d6 i. s- ~
- 0. 关于作者. {9 M/ `6 e0 Q$ i
- 请选择1-5开始新游戏:. p) B: h8 O M# l) |# j) o
- 您现在正在游戏大厅里。) L+ y. @6 e5 X" h2 h ~! n2 w
- 请输入“2”进入入门级房间"9 H# s5 c) J+ e% l! ~+ [ X
- " ①②③9 S/ h! ? k0 \# t) n" [/ q( Y* v
- 1 ■
# ^, R" E0 T5 O- Y* _ - 2■■■
' R k" p. q+ q% ^) B- b w - 3 ■ / V \( p3 ?7 X8 k
- 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!6 O! d) H& O* L* _: e. N! Y' l
- 请输入“22”来关闭第2行第2列的窗户。" H; {4 G$ |8 }6 o6 z6 F
- " ①②③
/ c5 n* X: A% M, G) R u - 1 . L7 c4 y: d) `# i
- 2
7 u4 V$ t2 `# G - 3
+ [8 w" R( [" a/ I* p, J - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。! ], U. ^5 e; r
- 请输入“11”,试着开启左上角的窗户。"+ N! x1 ^; V/ g
- " ①②③5 N. [8 B( g E
- 1■■ ' R; D+ |* A( C( l- E1 r% F" H
- 2■ / k0 \; V0 x, ^7 g! A$ m1 g2 {) U
- 3 : ]% x8 B& D6 x* k- b
- 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。8 H: ]1 n- S+ ]$ Z) Q) x
- 请输入“13”开启右上角的窗户。"- e3 s- W/ B4 y* v) A$ `) y
- " ①②③( ]) w5 w K) A* n- g
- 1■ ■- [ u, ]8 u7 c' h" i7 c! j
- 2■ ■
% s1 f/ h% o& l6 f4 j/ m6 P - 3
5 X( s3 D; h* J) I+ t S7 n - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
+ ]" V/ m& J b5 X: M - 请输入“31”开启左下角的窗户。"6 @- {$ ]7 J) W
- " ①②③
4 q0 }3 n8 X2 x: W: h; z+ ?) [ - 1■ ■; P9 x* c0 A* k* h7 X! L$ n
- 2 ■5 y( B$ `& ]5 z
- 3■■ , U& U/ P n& O# I/ K3 x( Z
- 此时,总共有5扇窗户被开启了。& H% a7 O. ^# i6 I* F H
- 请输入“33”开启右下角的窗户。"
0 l% N4 v G# O8 d1 ~" s! T7 k; G - " ①②③
+ E' \/ v( x9 t& R2 d5 A. B1 { - 1■ ■, H u d8 r# S. Z0 O% {, W3 R
- 2 & H& U" P2 Y* d' H+ R% I: U
- 3■ ■- e% Y$ {. k1 {+ E) {5 U
- 现在,只有四个角落的窗户被打开。: Z/ h% I ?) A8 [: x5 A9 x& K
- 请输入“22”完成最后一击!"
) X0 L- g" @- i X7 X2 a - " ①②③% D( n7 w# {+ _% i" [4 u, U2 m
- 1■■■
% b* m' T% B! a - 2■■■/ |: T! Q' u6 d
- 3■■■
5 H4 x# P( l5 y- o - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
/ x) z& o' V! q: H - , U( q' d/ @" u2 v
- ;;; 棋盘0 p/ V8 ?* S0 K. K7 Q% [
- (defconst *wechat-5x5-white-chess* 12288# T/ N Z# B, n7 z2 Y# w c
- " "). L1 }3 Y3 b: X1 |
& F+ I3 l4 d5 r( I) @; y- (defconst *wechat-5x5-black-chess* 9632
3 E& b: I! I* R! Z) ? - "■")
' h5 J% r' t% Q! L2 I
$ T# t W4 M" x* X6 o- (defmacro with-board (&rest body). T1 v3 G1 E6 c) _' {2 p/ v) P7 l
- `(with-temp-buffer
- d5 }$ Z% Q( ^/ E. i% A - (unwind-protect2 C% T1 V1 `3 E2 _
- (progn
F' k! g5 _ e1 X9 Q( T! Z: o) d# Z - (if (session "board")1 w! H" M3 Z$ z$ o
- (insert (session "board")))8 T# N( _- O& z9 M9 R, `. i
- ,@body)
/ V/ ?6 {; X% G; v5 ? - (session "board" (buffer-string)))))
( u& o' E/ o b ` L x - : c5 _8 z6 s7 z7 A
- (defun board-init (size)2 t2 U( t) G% d, \" t& I
- (session "size" size)$ ?' `1 x' e+ \: |2 }. P& j
- (session "step" 0)
! Y$ \4 q4 f. F2 K: |, ` - (erase-buffer)
$ d# {* P. H2 j3 q+ G* F - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))
2 O' o6 [8 e& p - (dotimes (row size)
6 n# u5 e& e/ w - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
! X4 E) M' i1 B% D( Q( B3 ^
6 `8 U3 E2 V- S( U* q# _- (defun board-contains-p (y x)
+ l8 {/ ], u! T9 e: f+ _ - (let ((size (session "size"))) q7 c, E. K' k, x2 k3 y
- (and (<= 1 y) (<= y size)% ^: O7 s" c$ g' t7 E- _% \
- (<= 1 x) (<= x size))))6 z* ^. S+ i" s1 h0 S
- $ y6 j: N3 d8 m
- (defun board-toggle (y x)
* H& l$ o4 F3 B& C - (when (board-contains-p y x)
3 c* f! Y! f' i# ^6 k - (goto-line (1+ y)); x F( g5 K% d: W: M$ r4 }6 J
- (beginning-of-line)5 w" j# h# H/ n
- (forward-char x)
& l1 i1 j5 J; v! { - (insert (if (= *wechat-5x5-white-chess* (following-char))$ V2 w' ?9 w7 q4 }
- *wechat-5x5-black-chess*/ ?8 _9 Q4 u* ?* g; E$ W
- *wechat-5x5-white-chess*))
/ }3 X1 J' N* H( a - (delete-char 1)))9 R6 I4 z; z0 a" v; {
- , a4 T" o* s/ X: i! m P" \
- (defun board-put (y x)4 d, B" W* o2 {
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))# }6 j: _0 N W
- (board-toggle (+ y (first dir))
" C1 W6 J; m) C+ z+ [- ~' G - (+ x (second dir)))))' m( G' [$ ]6 B8 A8 N. Y/ R6 |
$ ~1 M" u. w* V/ t- (defun game-over-p (); m' v/ b' Q' \ ], w: P1 i5 W
- (beginning-of-buffer)
4 p0 r( a+ T- p - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
M0 a8 j7 I& x4 {/ R3 u' s1 I
% \+ P8 c, a+ ]0 j) r- (defun board-show ()
' _; h! j& o9 q. x3 b ^5 H$ ^ - (with-board
" Y6 T; M! R" \; X4 j4 r) t0 G: [ - (concat (buffer-string)- q2 z$ C0 M4 l
- (if (game-over-p)( E/ q" N! |: Y' j
- (format "共%d步,输入任意内容返回大厅" (session "step"))
& J5 p+ \1 w# ], n8 Z4 e - (format "第%d步" (1+ (session "step")))))))% C& R, Z* A" S' M. O0 X8 y
- 7 M. X# V! `' e# J1 ~/ s- _
- (defun board-position-parse (cmd), n% `/ j' P! y' ]
- (if (= (length cmd) 2)
( D2 [3 e8 F' a2 `" k; Z$ V& ?7 S - (list (string-to-int (substring cmd 0 1))
9 o3 J* X/ s3 }* ?2 G5 [ | - (string-to-int (substring cmd 1 2)))
4 \/ N" W' e% g - '(0 0)))
" b& z( ]- p5 n8 C& \& |! W& M - 6 W/ o" E- R; ^" p/ X3 K% s2 J
- ;;; 游戏房间
) O( I8 S6 p* J O - (defun game-room-init (cmd)7 \' `0 q: Z/ ^3 |; q' p4 C
- (let* ((middle (string-to-int cmd))
$ H) c4 g3 j9 S! D h; | - (size (1- (* 2 middle))))
" B" r/ Q4 U. Y' B - (with-board
# \1 y5 i$ r6 t1 a$ ^5 k$ a7 W4 |* z - (board-init size)
9 D' ?5 d' L4 H" ?6 d2 R5 k - (board-put middle middle)))# L; k; |! Z, F z* b5 ]" q8 G/ E
- 'game-room)! l# Q5 S% E2 ~; L3 U
- $ n J2 ]2 }; e$ W8 D% _
- (def-room game-room
7 R9 c$ d, ~+ q: h( a( F$ U6 T - #'board-show
* `3 D. g2 j6 {8 {& p - (t (lambda (cmd)+ L( \/ Q( O- R/ u! W
- (with-board1 z# T! K4 K2 J, U( A. ?" j' `
- (if (game-over-p)
7 `( i: U ]5 a, h" B - 'living-room
1 t* Y: H* S. {5 ]4 m( k. | - (destructuring-bind (y x) (board-position-parse cmd)
5 v0 J G6 Z$ b - (when (board-contains-p y x)
, T4 D+ D: x& }$ j* i& L c - (board-toggle y x)
0 B( Y8 R+ U {; ] | R; Z9 Y6 E - (session "step" (1+ (session "step"))))3 t; W0 w2 A% {$ h
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|