wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
- }( e: B- ]7 ~, ]- ~) v0 N借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- / J" w$ p; t6 i# F3 R, c
- <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;">;; 定义新的游戏地图9 b8 h( `6 R, T: g) m1 V) C+ B
- (def-map "/game/5x5.el" ; 对外开放的URL/ i) p+ l( q( D: D. F
- 'tutorial-room-0) ; 默认的入口
& }8 ~% \, x$ {% a8 O* L - 5 D; ^: x% `3 B7 ]8 H) o3 k; A3 K
- ;;; 游戏大厅$ |$ w2 c* K+ L ]! u( Q0 S; o+ f
- (def-room living-room9 @; Q6 Z6 U' L
- ;; 进入该房间后的提示语 c! b$ f1 n1 ?: S; ]& M2 Y z
- "1. 教程
2 b/ r; [* p! @& p7 \, u - 2. 入门(3x3)) ^/ F3 U* k5 n* W- }
- 3. 初级(5x5)
( L' v0 Z9 K% F2 R; K/ m k - 4. 中级(7x7)9 m7 t7 X3 y9 n. q7 b: t
- 5. 高级(9x9)+ x* [$ M% S0 W# g+ z
- 0. 关于作者
0 d/ Q# \' A; ]! |9 f& T - 请选择1-5开始新游戏:" F% _9 E- N7 Q* S
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
' b! ?" q4 H2 ~0 a+ y. Y( r* e- f - ("1" tutorial-room-0)7 N0 t: ]: Y% J# H
- ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配, V+ X! j" j2 K8 s* w' Y
- ; 相应的返回也可以为函数,动态返回房间名
+ V! \3 d) ^) G8 M$ f+ M! H$ [4 I5 W - (t living-room)) ; 如果条件为t,为永真4 y) K8 A! O2 k2 r, ^
- / M( g6 s9 K5 b& ^* Z
- ;;; 作者信息
" [2 u1 p8 Z) q* {1 F - (def-room about-room, U$ t" h. Q) y) W# h! A
- "作者:redraiment
4 {6 V2 g* ?6 j. u5 ~! J. b3 @ - 微博:http://weibo.com/redraiment" ~, ]. b; c+ O/ T: N, z; J
- 有任何建议,欢迎在微博或微信上联系redraiment。6 ?+ J& M8 n! v/ H, ?" c
- 请输入任意数字返回游戏大厅。"
, b% ?: c4 |3 `, ]) w+ C; e, B5 W - (t living-room))6 A! v" g* X8 ^) v S# r
* X4 O: ~7 K5 p a8 U( D9 A: t! Y- ;;; 教程. {! ~. O1 V; }; j
- (defvar *wechat-5x5-tutorial-rooms* 0
) }' Z! {5 T- F1 H1 d$ y$ h - "The number of tutorial rooms")2 M+ ^; e" E4 w: K/ r
7 S) x1 g8 l( F4 b- ;;; 简化教程的定义; p0 I) H, V) l$ ^
- (defun string-last-line (content)
) q2 L$ {* s5 q; O% j2 @- b, [ - "多行内容组成的字符串中的最后一行"0 }9 z. E. ]% H; W8 d. A6 ^6 u2 r
- (with-temp-buffer" G- `1 s# P. h' l# x8 T% B( x, a
- (insert content)+ \1 T( N" f! \* F" L" B
- (buffer-substring (line-beginning-position)
2 q0 e3 \; h: }* H% V0 x - (point-max))))
1 P2 w( c0 z4 ~ K
% ?- Z0 a3 _, a- (defun def-tutorial-room (prompt)
* E+ M$ Y: T( Y6 y) a - "根据提示语自动生成教程房间。
0 G& D7 g F& A- o; k4 L0 M N
" _8 u- E6 ~4 S: b$ i2 C- ~- 1. 提取最后一行作为问题;1 J. [, v" ] J j
- 2. 分析问题,获取期望用户输入的内容;# p6 E/ F/ |1 T6 \' S8 |2 S+ [
- 3. 定义教程房间和重复提问房间。"
5 e3 Z, Y( X4 K8 A$ ^3 l( I - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
; q+ ]2 f& x4 v9 k$ q - (repeat-room (concat room-name "-repeat"))5 {( U" [4 k$ c) Q; h7 n
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))
3 X* R; P# c6 t( z; ~$ L4 }- [1 _ - (question (string-last-line prompt))
4 D& c- b6 R# ^" I - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)
( F" [- u, S/ f5 V* @8 O - (match-string 1 question)))! C# o5 G% Y6 D2 n
- (doors (if except3 P+ `+ ]( G0 l: }( Q
- `((,except ,(intern next-room))& E3 e( T3 k% \6 v* A; m, q4 T
- ("q" living-room)
; H5 g9 S& X$ T2 u& W; c - ("Q" living-room); f6 u9 W4 L2 }
- (t ,(intern repeat-room)))8 @- G1 d! z. o. L
- '((t living-room)))))
( {+ f' `4 ]! A6 a! h% w. l* W - (def-room-raw (intern room-name) prompt doors)! Q. ?3 e6 }- T7 q
- (def-room-raw (intern repeat-room) question doors)))
; i1 c) `2 d1 _ u7 f8 m" }" _; } - 1 _- p6 l3 b$ e
- (defun def-tutorial (&rest prompts)
7 N4 C, _" d/ s- B+ i- k/ I - "批量生成教程房间。"# T- n- {! j' y2 R! v
- (dolist (prompt prompts)& z/ }4 Z- ~( p; a2 M7 D
- (def-tutorial-room prompt))): z8 X% F V# F; c! N9 T
9 V2 Y# z# |' |4 H! r7 l6 c1 a- (def-tutorial
* _# b4 D" ^& [! P - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
5 @$ Y- W' f% M( @6 W - 1. 教程. [$ v% [/ o! }" S* F: ?
- 2. 入门(3x3)
) u' r6 { K$ A% N - 3. 初级(5x5)
' m) e) U; i. s6 x - 4. 中级(7x7)
7 g8 H0 Q% {, ^) F' N4 [3 C - 5. 高级(9x9)
8 F9 b* |+ t% Q8 J% O3 y5 R - 0. 关于作者3 U% \2 A. z$ s/ J& h
- 请选择1-5开始新游戏:+ Y7 o, R5 }- K' X6 U: m3 R7 q5 }
- 您现在正在游戏大厅里。
, E \- ~) F1 H' S; A - 请输入“2”进入入门级房间"
& q$ Q0 [" k {( z; Q8 O - " ①②③' ^% m, p. K3 ]
- 1 ■
2 Z0 L6 H7 j6 E7 X4 B5 | - 2■■■
" y4 l& `* G; }. V$ g - 3 ■ ) g' s0 D7 ?) z$ _1 z
- 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
; G' Z, l6 q1 y) k X - 请输入“22”来关闭第2行第2列的窗户。" t, c9 m& i* r( x& c* w0 K
- " ①②③
% H! O( Z+ m$ r; R2 D1 p - 1
% @6 T/ z5 }8 Z1 n: s. K - 2 2 m2 D9 B' u) Y) w( y! E( c
- 3
. d0 K8 p8 {6 `& z5 O% S2 q4 u' S - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。2 _3 U( l, @* p% }& @+ e" s H( g
- 请输入“11”,试着开启左上角的窗户。"
( d3 g$ {1 o" U& |* _ - " ①②③ f: a* E3 v" m: Z
- 1■■ 3 Q3 m5 J2 [1 ?
- 2■
, D8 D) I0 L! g+ i5 U e - 3
1 V h7 n' O7 Q8 P; W# Y" [ - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。
1 ?' s( i8 q0 y9 h6 b - 请输入“13”开启右上角的窗户。"
/ W% I" M- L! i1 W) B" Z6 ^ - " ①②③1 z+ ~$ T6 d2 ?5 c; O1 C/ W& b
- 1■ ■+ ^0 V2 z% i" s
- 2■ ■
! j; _5 }. w! z3 _: X* h0 x - 3 % f/ `8 h ], b3 I
- 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。( U$ B. I. q- D
- 请输入“31”开启左下角的窗户。"
9 E0 h3 D1 @: a9 H - " ①②③
1 B( c6 S# a& j2 }: g - 1■ ■
0 U& S; ]0 P2 [* M. u - 2 ■
7 [( c9 z& O+ j6 u; X' ~ - 3■■ " Z) h; n1 A% k
- 此时,总共有5扇窗户被开启了。( g1 W& f( O3 {0 s
- 请输入“33”开启右下角的窗户。"
+ J, |+ R& E# k/ z( c2 q - " ①②③
. [4 U" S1 K" h - 1■ ■7 k8 M. D9 ~' d4 G
- 2 1 o* ?! L2 ^ _+ r
- 3■ ■1 r! {$ V0 {# f' o& o: q
- 现在,只有四个角落的窗户被打开。! \4 ?! w+ S( \. ]4 u$ h! ]/ S
- 请输入“22”完成最后一击!" @7 C4 O% c, I+ v/ S
- " ①②③
( \0 o$ D1 @4 R5 ]% Y - 1■■■ t' v% _' k! y$ E8 e Z6 ?
- 2■■■' k) ~9 ~0 @5 A/ l
- 3■■■
# Z! N h+ s0 S0 I# ]5 _ - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
/ i; F/ K2 A; W& S# }
4 C2 X ` Q( Q3 X% a9 ~- o- \- ;;; 棋盘) i8 r/ x5 ~6 S' j0 @$ M
- (defconst *wechat-5x5-white-chess* 12288
( b4 G7 @. F, |/ `5 a2 t - " ")
6 [; ^- R: o7 f. O - ) w6 Y9 `: {8 B4 y2 i7 A0 Q) P
- (defconst *wechat-5x5-black-chess* 9632. _1 ~2 c9 ]5 Y$ v0 D
- "■")
& I; T( ^) w% Y. f7 L+ P% Q: @ - % Y6 u% ~' S/ \2 X- T( W/ N
- (defmacro with-board (&rest body)* |, k7 r S9 C" z% L S. Z
- `(with-temp-buffer9 m: {. J4 f8 {$ d
- (unwind-protect
L* z3 e' Z$ u7 s3 k! e" C0 t, _ - (progn
) A+ P7 n2 {) s( j. s/ ~2 p - (if (session "board")* g- h: c4 {4 J( U$ K) j
- (insert (session "board")))
( Y3 o& m" j+ K, D - ,@body)1 U3 D% y; p: a7 X3 s! L4 |
- (session "board" (buffer-string))))) g' u! B" b L" X0 C
! m* _& |# E3 v0 O- (defun board-init (size)
7 J$ J. S/ | V2 L* S4 F6 i - (session "size" size)& w; ^2 N0 s* ]# b
- (session "step" 0)/ s1 k" s3 K& ~. C0 F
- (erase-buffer)
( P: z# G0 {: G- E, [6 z2 q! W - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))5 M! Q/ C$ e$ [" B9 z; E$ v8 ?+ ?
- (dotimes (row size). M8 ^/ y. [2 m& w# Q F8 M
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
+ `- ^' I* r, j2 V - 1 U5 m: d6 c9 H
- (defun board-contains-p (y x)1 J, [" L$ n( z/ p
- (let ((size (session "size")))
' d; T8 f A1 O, C - (and (<= 1 y) (<= y size)8 n' L: y* _8 C. s3 a
- (<= 1 x) (<= x size)))). z0 F8 a6 I3 i( C* y
9 \- q% ~% }" S- (defun board-toggle (y x)
, e- S2 b+ {# M - (when (board-contains-p y x)8 | i( k$ h5 e4 M# r3 V, X2 F
- (goto-line (1+ y)), q5 N9 U- v; P7 A# \8 ?
- (beginning-of-line)# d* ^# }, a% u3 _/ Z) }7 o, Y( h
- (forward-char x)3 I4 z' { X: |/ g
- (insert (if (= *wechat-5x5-white-chess* (following-char))2 _% B' S& i0 R1 x8 [. ?) K
- *wechat-5x5-black-chess*
V. K4 m' v0 J2 f - *wechat-5x5-white-chess*))
- N. }9 _% ^: J$ e& z. m, G2 J - (delete-char 1)))
2 Z/ g$ u1 f# l; v- l
: c9 l. y. p( ^' I e- (defun board-put (y x)/ |7 M8 y& A$ |3 w/ @% Y% m' R/ r
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))$ ?: q2 e# P# U2 K+ c
- (board-toggle (+ y (first dir))! M% M8 y7 E& T+ U* w' f! `) p
- (+ x (second dir)))))
: l/ _7 g* Z! m% b4 X5 b - . U1 ]8 w8 f, I' b3 \
- (defun game-over-p ()5 M5 R% @$ N" v
- (beginning-of-buffer)7 } c( J* J5 I. P) {
- (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
3 y: l" y7 g) H _# ^ - % ^$ p' k6 Q! A$ b9 T' W! {3 D
- (defun board-show ()/ h0 K+ l+ u9 N* l9 T
- (with-board9 H! I( |. E) ?3 ?
- (concat (buffer-string)
1 f9 D$ h0 o4 d& h0 w9 F u - (if (game-over-p)
1 K; z$ U5 v; ^, b - (format "共%d步,输入任意内容返回大厅" (session "step"))
2 l, y q: w$ U - (format "第%d步" (1+ (session "step")))))))9 r2 h* G; Z8 n+ L( b
- * |, P3 Z6 G( `& `( g
- (defun board-position-parse (cmd)
5 }! H* Q% K' ^$ J' N - (if (= (length cmd) 2)
( w' u2 ?7 D& M - (list (string-to-int (substring cmd 0 1))* r8 o# M. b0 j9 j& q" g1 N6 x' G
- (string-to-int (substring cmd 1 2))). u7 \0 T9 y' i' F; L$ \
- '(0 0)))
8 i7 f$ h5 z: x; b2 T& N - ! I1 W9 |& T3 x2 U# b7 ?6 Q" x, _/ y
- ;;; 游戏房间
" v2 g: ^& V5 a( ?1 T7 N - (defun game-room-init (cmd)
# j# k0 D: j& w4 k l& r - (let* ((middle (string-to-int cmd))' ]6 E9 e( Y% c/ D* ^- t7 |
- (size (1- (* 2 middle))))
2 X$ f B0 a5 s! X. N; }# |2 E" S - (with-board8 `/ e7 j, ~) z9 O( q- \$ f- B
- (board-init size) B; ~4 }: j, T; s
- (board-put middle middle)))( X# {! k. K" [
- 'game-room); v8 x: L5 M1 V& J+ @
- % U- C" [6 D" b# g' Q, V
- (def-room game-room. R+ d" j# e& g$ r9 \. G
- #'board-show
0 y$ H. f4 @$ p e3 }9 v4 L. D - (t (lambda (cmd)
5 P# w/ S& j$ D. @" K# x0 ~ - (with-board: H8 ~9 S [1 j6 K; B
- (if (game-over-p)* s( x: G4 [9 X, s5 W% O& j
- 'living-room5 Y7 t7 V7 |$ p* M5 }. V1 Q
- (destructuring-bind (y x) (board-position-parse cmd). C- i3 Y: r. x! _4 C5 P9 D3 h
- (when (board-contains-p y x)3 p' ~% H& t. q P) ^7 L2 @% k
- (board-toggle y x)
4 o: h9 z8 R! X# M/ K - (session "step" (1+ (session "step"))))6 {, E+ K0 n* Q8 q7 E7 R/ u
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|