wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
, c I8 I* f+ g借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- , R ]. F& E% E+ f/ T1 F* {" o
- <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;">;; 定义新的游戏地图
, W% L+ a+ N6 | - (def-map "/game/5x5.el" ; 对外开放的URL. U. Z3 ?+ z8 `5 K- l
- 'tutorial-room-0) ; 默认的入口1 H4 v P; S3 T3 \+ g/ D. W7 J j
- U* V* Y& l: N- ;;; 游戏大厅
: D, Z) a% {' ^9 a/ [$ U1 ? - (def-room living-room
# z, s0 E- y4 ]( Q - ;; 进入该房间后的提示语
9 }0 Q& y1 Z, N - "1. 教程2 f. @: t* l M' l
- 2. 入门(3x3); _; F$ h6 A9 ~: `
- 3. 初级(5x5) Q4 a7 l2 a+ s- Y; `, V: ]
- 4. 中级(7x7)- ~3 K3 V n; ~
- 5. 高级(9x9)+ y4 j3 D& E- a o0 Z; o6 t
- 0. 关于作者, W* I( y1 X% |7 e
- 请选择1-5开始新游戏:"
- r' J6 j$ d' E3 Z" R% ^ - ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
7 i! v/ J$ [8 u: M: q - ("1" tutorial-room-0)
1 {, q' S/ J% I7 { - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配1 m+ y8 I i0 i
- ; 相应的返回也可以为函数,动态返回房间名
: H+ { C7 ?4 k% j9 d1 n( }( N; m - (t living-room)) ; 如果条件为t,为永真8 g& O2 M1 i& C, v% }$ d$ U
- $ V( f9 I+ O; F4 o8 m% z- C+ k0 b& e
- ;;; 作者信息
3 h% F6 _' F) l" b( d) a9 n) z - (def-room about-room
3 p/ w1 E( l/ U - "作者:redraiment5 D" z, B) a! m$ s, |8 N+ T# g
- 微博:http://weibo.com/redraiment
( l- o" N9 n @3 X - 有任何建议,欢迎在微博或微信上联系redraiment。
8 a0 {# E' M+ ~! w( A" q - 请输入任意数字返回游戏大厅。"
0 b7 x- |# b2 p) K$ E - (t living-room))
+ v" ~$ C/ g6 t- t4 U: y& a: T
& S/ V1 \7 o: ]( @- l0 t- ;;; 教程9 Y/ h7 ~- b% p7 g4 W, F+ d7 J+ H
- (defvar *wechat-5x5-tutorial-rooms* 04 r7 h5 O5 j5 M2 @: A7 ]
- "The number of tutorial rooms")- i5 z7 _7 ^, ^* \4 h" U
; i- o6 |# @7 w! m1 C: b- ;;; 简化教程的定义
# t& }( J7 N5 x" j0 E - (defun string-last-line (content)
5 o( O# a! M, Q0 n' ?4 a - "多行内容组成的字符串中的最后一行"
4 k# q; i l% |* U - (with-temp-buffer! t9 c2 M4 ~; D5 K) ^
- (insert content)
8 m" w7 s3 ^, J" g& s" W) x - (buffer-substring (line-beginning-position)0 u, s) ^# u9 I1 a0 ~
- (point-max))))" q6 Y9 y) P' {% d- f
' Y. _: F9 b/ |. y1 j- (defun def-tutorial-room (prompt)
0 u {8 @# t2 r# s, C5 \ - "根据提示语自动生成教程房间。' U) t* H5 V; ]" G# _
- 8 k* C: F' C* I. m+ i
- 1. 提取最后一行作为问题;
: u4 \- q! I6 K! Y- l, r) u - 2. 分析问题,获取期望用户输入的内容;
* O; E, {- h2 u+ Z5 P6 Y2 s: z! d( V - 3. 定义教程房间和重复提问房间。"
3 E9 }* ?1 u7 s6 P - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
; }0 A. o; J0 H) M O - (repeat-room (concat room-name "-repeat"))/ g S' H) \8 g2 S7 D
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*)))). q0 S1 q2 U4 l9 X9 N
- (question (string-last-line prompt))
% z4 `- [. m' q$ _+ t5 i7 J - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)3 B5 n! C6 c- |; Q& ` j7 n' @
- (match-string 1 question)))
% o; W6 F# T1 Y' m - (doors (if except8 r* [+ v8 [/ }
- `((,except ,(intern next-room))
) @) F' g7 {) F: `. ^' g - ("q" living-room)
( o0 N4 D" k4 K! l% @+ d - ("Q" living-room)
0 b% r' d0 O* L# o3 A. j, W - (t ,(intern repeat-room)))
6 k( U4 D( o- `# H - '((t living-room)))))' Y4 V6 n8 s6 o2 e/ Z
- (def-room-raw (intern room-name) prompt doors)9 p' P& g, B E
- (def-room-raw (intern repeat-room) question doors)))
, S; J$ ?/ k9 i
7 R2 J6 V, l9 x% T4 j0 R- (defun def-tutorial (&rest prompts)$ a! ?1 H8 f7 I/ h
- "批量生成教程房间。"
. R5 e0 q+ x$ H# \4 f$ a$ Q - (dolist (prompt prompts); {. f' k. Z7 F& Q! {
- (def-tutorial-room prompt)))
/ [. U- n8 E" H+ W# G/ b - # x2 F5 {( M x. H* y0 A* D% n
- (def-tutorial; w! t! K$ q4 c+ ^$ n: B$ Y) @& e8 k
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
/ ]6 J, v9 d6 N& I, u% _: B - 1. 教程+ z; V# }0 V, w
- 2. 入门(3x3)
0 a, F0 p$ |! f, y9 m - 3. 初级(5x5)1 A& z7 E# M3 c( J
- 4. 中级(7x7)9 k9 [. q( y' e8 c: g7 K. U( |
- 5. 高级(9x9)
) _$ f3 @4 n% \2 ~( L+ ~ - 0. 关于作者
" ^$ a5 m: C6 D; c. } - 请选择1-5开始新游戏:0 @) p* v& z1 V, H
- 您现在正在游戏大厅里。8 ^, F8 _" p) C" ] {3 w7 }. T2 ~/ X
- 请输入“2”进入入门级房间"
+ J- k8 k1 D* f; t/ V9 V# ? E! Q8 ? - " ①②③7 P8 ]% j [+ P/ d z6 f( p; k
- 1 ■
0 Y3 S: R6 C: B! y( P" R - 2■■■ P, Q7 U0 y7 G: h3 {4 G
- 3 ■ 5 y( e" t, w5 v0 N) S8 ?7 i
- 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!: Y* u& }% a9 T6 c
- 请输入“22”来关闭第2行第2列的窗户。"# x# f9 f* }! m6 v
- " ①②③
5 `* r6 C2 }2 U1 Y) b, a - 1 F t8 s. C7 F6 Y1 m
- 2 0 D1 W. @. ` R' j/ o
- 3 * P4 O" Y9 x( @
- 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。/ { v2 m; M# N
- 请输入“11”,试着开启左上角的窗户。"
9 Z+ @# T3 r3 a1 K4 } - " ①②③
+ E8 U8 g5 p' I( J& X - 1■■ / a# s" Z7 h4 q
- 2■ & `% p( Z6 t& P2 T/ l
- 3 1 C" w$ i: ^! i
- 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。, l- x; K# B+ q$ L( @3 A$ t0 v" ]- R- s
- 请输入“13”开启右上角的窗户。"
0 u4 ]' K7 b) b, C - " ①②③
/ o& C( [& f1 A# w0 ^/ S - 1■ ■
% O+ I8 I' H% y, s. O) c' e - 2■ ■
% E; u# {3 `. b( R( p5 Y7 M. y - 3 ' F' _, I$ t' N
- 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。# B( N, P# {$ ^$ p/ {
- 请输入“31”开启左下角的窗户。"
4 X/ T1 m8 k X% o" a1 `+ E- j) D - " ①②③2 C' _, K3 v; Z& G/ O9 p. i2 C2 n, R
- 1■ ■
. G" a: o# L; ~ - 2 ■
$ l9 S" x0 d: ?% i$ O& R - 3■■
* }7 N! I. `- h - 此时,总共有5扇窗户被开启了。
6 j+ b: I+ C( N' w+ P5 t8 Z5 g8 g - 请输入“33”开启右下角的窗户。"
^2 r: F! r5 V" A' C - " ①②③ s; v. a0 O( F* D! `6 W5 L2 W$ z
- 1■ ■& y% [/ d; L+ a& a2 s
- 2
7 L: M& W5 ]! Q& L$ ~0 z( z - 3■ ■
; I$ W1 n1 ]' ~. k- j1 U - 现在,只有四个角落的窗户被打开。1 t0 d9 _: {% c& u/ \) g
- 请输入“22”完成最后一击!"
5 C( p0 o7 b; {0 H/ u% c9 ^3 m - " ①②③1 ^& e9 R4 s5 ?3 d4 `1 n0 r
- 1■■■
/ s Z; T. M3 A- G4 i6 ~; O9 N - 2■■■
7 m, [. j$ r8 l - 3■■■( P) v) s$ x: `7 f
- 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!"): J3 P4 W* n c% t' R
/ T. I+ y% p; N- ;;; 棋盘
; Q4 I- w$ B/ R; Q( J! j% _0 Y - (defconst *wechat-5x5-white-chess* 12288% H6 k$ B) s! t7 f+ Y" ]! [, |
- " ")) g" {% X$ r4 o+ |# {3 R0 M
- $ E4 H: x" k) y1 e/ P6 `" L
- (defconst *wechat-5x5-black-chess* 9632 o7 _, ^6 |0 M9 D W" j% s( t
- "■")+ v0 ]; B( D$ u0 T. h
- x4 ]. ~, g) i: { i! y+ \4 r- (defmacro with-board (&rest body)
: n4 \$ r; Y9 U- Q4 I* C; H - `(with-temp-buffer
) \" P! A' I4 p( Y - (unwind-protect+ L2 P* U- { {
- (progn% K7 a6 p: }' p' t; q. T
- (if (session "board"); H4 M7 q4 u2 p; {/ K' R' J
- (insert (session "board")))0 A: W. g- @& q' m
- ,@body)
2 B C$ S; b) G) d - (session "board" (buffer-string)))))3 E Y5 n0 z! o; w& P& |
7 |6 R/ Z+ Z' H# U0 I9 B- (defun board-init (size)2 {* R3 P0 M% m
- (session "size" size)
( u% e, R; P+ E; T# s* Y& ? - (session "step" 0)
: _# t9 j- [# ]$ t) H2 F: E5 W - (erase-buffer)& r: S7 L/ u; |7 V
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))
+ y! s, e) m! Y" @1 G/ b( y+ z; ^ - (dotimes (row size)
. g/ t. g5 R# U, }! T& p+ a$ G; J - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))! K: |. _3 ~( E5 `! }! O. i8 t1 N
" W& t( M5 R; p7 a, x- G- (defun board-contains-p (y x)
- ~- {/ m- M. R$ h( Y - (let ((size (session "size")))
% d' ?! ~# d0 I7 s - (and (<= 1 y) (<= y size)
* C5 A* D2 q" Y L! x - (<= 1 x) (<= x size))))
, V( Z. S" T. k' k: g) J
4 j8 I; \+ g9 a- (defun board-toggle (y x)
4 }5 ]6 X: b$ Z( n3 K - (when (board-contains-p y x)0 k# X0 }$ J: ^9 t# o
- (goto-line (1+ y))& O" d# F! M9 b7 V# W& N
- (beginning-of-line)9 [2 ]' o# L- m$ A9 S( m2 U# ]
- (forward-char x)
; P4 L6 j2 S# D0 K! m - (insert (if (= *wechat-5x5-white-chess* (following-char))
) A% Z' }. F' r - *wechat-5x5-black-chess*
" L$ G& i; c/ N+ J& X l9 y* { - *wechat-5x5-white-chess*))# M6 R& `; A9 i0 F7 a7 A
- (delete-char 1)))
q; B: v/ w; n5 _& _
8 e% w* Y' S- U- ]! k- (defun board-put (y x)
' m( Q/ {0 B) L" y- I$ G - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0))) R) r3 ~* |7 \9 ]! M9 i& A
- (board-toggle (+ y (first dir))
- H& |& N6 z& N/ B: h0 b - (+ x (second dir)))))0 E9 |- v1 ^9 L5 R6 T, J* l
- 8 g1 w5 G0 ]% s7 `! Q
- (defun game-over-p (). V4 Y9 [6 x& s7 H6 v$ y
- (beginning-of-buffer)
8 q6 k, C, L6 J6 {* ~8 R- \ - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))& @0 n0 D: V. }/ H9 S: \1 b
8 F# O- N/ `/ F% M9 x# k# W. ]- (defun board-show ()
9 |6 [5 }9 |, B7 a) j) n - (with-board, F0 c |; \, B# f0 I1 L
- (concat (buffer-string)9 E6 C: ~" j n6 K
- (if (game-over-p)& V" w5 s& r6 X5 C$ z
- (format "共%d步,输入任意内容返回大厅" (session "step"))) R, r( E0 h4 J$ M6 D
- (format "第%d步" (1+ (session "step"))))))); m/ X g( \$ `" J7 J$ a/ }# z
# O6 y( C: Q0 L6 ^0 d0 u& ]% ~- (defun board-position-parse (cmd)0 l1 x( S* `' I e
- (if (= (length cmd) 2). B" \/ q0 L9 T6 n8 h/ X# O
- (list (string-to-int (substring cmd 0 1))) {4 N/ s5 q p6 r6 ]; K" R
- (string-to-int (substring cmd 1 2)))2 Z5 Y* y9 x! [8 Z" C0 }
- '(0 0)))
$ l3 M$ q8 Q% X
) i- U8 n+ _% z+ Q; k) Y- ;;; 游戏房间
& R6 f% Y9 V/ W% f4 p: { - (defun game-room-init (cmd)
, s+ i) q: I" I$ ]9 u: } - (let* ((middle (string-to-int cmd))2 N& }1 ?+ [; |0 n4 u( E
- (size (1- (* 2 middle))))2 X" X. B0 w5 N/ V3 {; H! `
- (with-board& x; |/ @$ \& @ R# r9 k, Z7 N* y" \
- (board-init size)
0 ]5 _6 Z! Y4 c1 R, y3 D) |0 M - (board-put middle middle)))+ t7 y- D0 Y" H4 X5 s
- 'game-room) y! z# i6 r/ C5 N" ?6 j5 B: i
, c5 m. f# w4 O3 Q- (def-room game-room
( C, `, P' a0 E9 S - #'board-show
6 f: g. L4 U5 x: e4 i( r% j - (t (lambda (cmd)& L c: I9 V( n+ D' g1 x
- (with-board
" r: z3 j2 @* v! D - (if (game-over-p)
* n4 C* p4 c" ^. T9 _ - 'living-room e _4 F9 ^* m- N$ U2 \
- (destructuring-bind (y x) (board-position-parse cmd)+ M" k( E% P* z- G4 S: W- [ U5 I6 Y
- (when (board-contains-p y x)- r' T9 ^$ D" s: K
- (board-toggle y x)
0 b" ?- d$ P. f1 I. x h% b( m7 \: { - (session "step" (1+ (session "step"))))
& o* z3 A8 q8 k3 E. ]; C! y - 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|