wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
5 Q" h( e$ |7 z( E7 _& q借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- 5 Y+ N, ~7 E% p) W4 F* C6 Z* j
- <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;">;; 定义新的游戏地图
6 W- N- I* V! C- j0 k - (def-map "/game/5x5.el" ; 对外开放的URL* k' H. [- u. L
- 'tutorial-room-0) ; 默认的入口5 \' H1 a9 C5 Q- s
5 i {* J0 I$ S6 g- ;;; 游戏大厅
# g: W, U9 x; d) A - (def-room living-room, I8 Y1 ]. c0 z* N, Q
- ;; 进入该房间后的提示语
. y( J- J- t. L9 C2 [ - "1. 教程/ ]: A$ x. J/ L; o3 J
- 2. 入门(3x3)
" c6 V) O+ _2 E3 |$ _ - 3. 初级(5x5)
5 i6 ]9 H- B5 Z7 m, C! [ - 4. 中级(7x7)
! ^3 y! {& t5 c: F Y2 @ - 5. 高级(9x9); e- O" U7 V/ t7 O H) x% k
- 0. 关于作者/ a8 Q9 G' I. ]2 \2 h$ \
- 请选择1-5开始新游戏:"
- K1 f N8 o( R+ \" M* h k0 ~% b - ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名. m4 A* U, ^, y* S5 x
- ("1" tutorial-room-0). j5 |7 b+ y# a" c D/ K1 R
- ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配: J' @# E/ A t1 ^' p
- ; 相应的返回也可以为函数,动态返回房间名
! V+ B7 ^% O7 `3 _4 h2 ?7 z - (t living-room)) ; 如果条件为t,为永真
. g$ W6 Z( S3 c) I
$ I/ W% t6 v7 h- ;;; 作者信息
; @' c9 c+ Y8 B1 h" W& F - (def-room about-room4 R4 K* v+ }4 O F6 L
- "作者:redraiment" J+ ]5 E4 t4 d& `5 W
- 微博:http://weibo.com/redraiment
4 N/ Z4 K" S" v; K - 有任何建议,欢迎在微博或微信上联系redraiment。
/ P& |1 |9 g A6 _3 T3 h$ r9 _ b3 F - 请输入任意数字返回游戏大厅。"* ~. g4 f ^. ^9 B
- (t living-room))
# I9 I$ c. O* o c V- w
i8 G- o& X3 s- ;;; 教程
# R1 ^' K3 [3 E2 } - (defvar *wechat-5x5-tutorial-rooms* 0& g$ H) f* ^' i; P& a3 c3 z
- "The number of tutorial rooms")
1 A) m" J# Y5 r6 P6 X! _! S
1 t- I2 d) x- ?' ], N" c- ;;; 简化教程的定义
! {" O$ F o* g" U - (defun string-last-line (content)
; Q' _$ p2 M! N, [* a v1 ^ - "多行内容组成的字符串中的最后一行"
- n4 h$ ^4 Z. x; d' L# i - (with-temp-buffer" X. g, A9 t- p+ J1 N" v% K
- (insert content)
4 [; x, W" W: V - (buffer-substring (line-beginning-position); ]1 z2 A& c3 G/ P; b
- (point-max))))2 j M/ Q+ Q5 K, O3 D
+ M% K' A7 d% x- (defun def-tutorial-room (prompt)! N0 A8 h: ?) H
- "根据提示语自动生成教程房间。: e2 s- o/ ?, ?3 G
! D* [2 T) y' B/ M. Z- 1. 提取最后一行作为问题;* }! }' n, B, d8 z* Z
- 2. 分析问题,获取期望用户输入的内容;5 U [& f! z; d
- 3. 定义教程房间和重复提问房间。"! W4 l6 F9 L/ v
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*))); R6 B7 p1 H+ y( k+ g
- (repeat-room (concat room-name "-repeat"))6 f. Y' B% D; E! [/ V1 E5 u' C* J0 ~
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))( B. f1 Y3 @) I0 ~0 x6 X
- (question (string-last-line prompt))" {% N* v' O* w0 a
- (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question), }2 F- F$ m) N X( i6 B5 }# B, D
- (match-string 1 question)))2 O$ t" Z8 ~3 l: A; M
- (doors (if except$ }7 B: Y, _: n e! \: t
- `((,except ,(intern next-room))
! I+ F. W8 k5 T( S7 k( U0 } - ("q" living-room)
' L$ u) @6 e, G; F1 C - ("Q" living-room)
* G5 [2 e0 i6 E/ Z1 H- | - (t ,(intern repeat-room)))' M0 K/ |; R6 V5 b, v. Q
- '((t living-room)))))+ K& E1 Y4 }7 B) {. @0 ?( o
- (def-room-raw (intern room-name) prompt doors) z8 [4 r0 {; u) j4 ?% S
- (def-room-raw (intern repeat-room) question doors)))& D2 Y3 v$ _% B2 O2 Z
- c( s, ?& |1 _3 b A
- (defun def-tutorial (&rest prompts)
2 ]8 O# T! j/ E - "批量生成教程房间。"4 M- F4 @/ { w6 c, R: `# j) U
- (dolist (prompt prompts)+ d6 T# g* d. o, ?, f
- (def-tutorial-room prompt)))
* A0 L+ e/ i5 V, G, ^: k" v
5 w2 @# Z$ [1 J9 ~3 t- (def-tutorial
( z- l# b! w/ p7 g - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
[( Z6 z3 z7 _6 g* x* q - 1. 教程
! ?: Q% Z. }7 C/ o6 T% H7 U - 2. 入门(3x3)% m6 Q+ {1 v- t: y; D
- 3. 初级(5x5)' t' v% U; t @6 G+ m
- 4. 中级(7x7)$ l- M0 S5 V( S( d4 E8 c0 u
- 5. 高级(9x9)
% W% ^: z8 x& E7 `( u - 0. 关于作者
- K$ v4 y% {, ]/ H- _$ u - 请选择1-5开始新游戏:
3 N5 p: n! i0 Z# @& {* I - 您现在正在游戏大厅里。
# [$ O1 S- p2 D I( a5 F. \" O - 请输入“2”进入入门级房间": m. ~2 Q h% g4 B6 @
- " ①②③
" \1 Y: w; f' o/ _6 O* _+ h4 y I/ W - 1 ■ & x' a* V1 r/ U W
- 2■■■
! \% S- L N) E - 3 ■
, d1 X( p x1 L9 z3 j4 G9 n - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
; b( i: U4 K1 w5 {; `/ y' J - 请输入“22”来关闭第2行第2列的窗户。"- J' [' S( r& \" p1 C/ V& y5 P" M
- " ①②③
; u3 I+ ]+ f* s - 1
; n* P7 G/ I& _; l - 2
9 B& T' X Z: y6 ]( T0 Q& `6 X3 { - 3 2 X6 n( }4 e; d7 g' V+ Y
- 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。
) @" Q4 y. O: Q7 t - 请输入“11”,试着开启左上角的窗户。"2 {5 H1 q, k# ~8 @* q* o
- " ①②③
0 U; p' R4 J9 m; i - 1■■ 4 {$ x# s' h+ t5 G+ k* O! H
- 2■ , ^* b5 P' ]( _" I. f
- 3
/ I/ Z+ ]7 D+ S, H3 s% S! ~ - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。
% x! W0 J) o6 I7 _. M* K9 G - 请输入“13”开启右上角的窗户。"
1 O2 b( T7 R' \$ N2 c. j - " ①②③, W" t9 B/ i: ^: r$ `
- 1■ ■: l; h4 R0 d( D3 m/ k
- 2■ ■
' H: k6 u5 s( k8 r( E* x, u - 3
" Z6 T- B& C3 k - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
) y" s" J# U+ W: \ ` - 请输入“31”开启左下角的窗户。"$ l& V2 k2 |: r, c* h7 f
- " ①②③ s* k# y7 @: q
- 1■ ■
+ ?2 M+ n1 Q/ E) V3 F) j. h0 H' D - 2 ■% R! B' c! ^4 |) {% W. R+ S
- 3■■
4 t% E1 G1 Y; y# B! | - 此时,总共有5扇窗户被开启了。$ j ]- Z6 a4 b6 L4 X9 C/ I( X
- 请输入“33”开启右下角的窗户。"; ?" ?/ ~/ S' @6 v$ q9 f
- " ①②③9 f9 [) [1 G/ Q4 u0 u
- 1■ ■' u4 ^& l/ @) l
- 2 8 r1 m. l5 t- l T0 G4 D
- 3■ ■: M4 e o# `8 O% \$ R" Z% p
- 现在,只有四个角落的窗户被打开。
9 K ^ w5 y5 ^% c* Z - 请输入“22”完成最后一击!"2 k/ T% K( ?1 a
- " ①②③
- |8 y. Q% |3 V; J i) p - 1■■■
( o9 G$ ?$ N G. `+ X1 L - 2■■■
8 L' W: s% m5 | - 3■■■2 Q: e+ a. W* i! {- Q' G
- 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
# [ J& w/ ~" d - . P( b1 p4 x1 G# S7 M
- ;;; 棋盘2 r w. l% z/ Y4 C, G
- (defconst *wechat-5x5-white-chess* 12288" [* T8 t0 ]4 R" U F# e
- " ")
2 b. X. Z& `" @% f
' {% ~; W8 k) J( x' p" i% O1 I- (defconst *wechat-5x5-black-chess* 9632
7 }9 N7 k! B2 y4 I. u: F" h g - "■")
+ W8 T4 S6 G+ W# J4 {1 `- e4 Q
! h+ Q& p# ~2 x) p- (defmacro with-board (&rest body)
' L0 a& ~; t; q+ s1 C% D - `(with-temp-buffer
1 p- c9 p- S4 Z- G" Z) Y - (unwind-protect
: }1 J5 f" X7 ? - (progn
3 c' e( q Q( D- \; J6 ~9 [ - (if (session "board")
. U( A0 z% d5 P9 Y8 v' U - (insert (session "board")))9 U& Y( f- L {
- ,@body)
- o$ p4 R+ q& O# J* b0 B$ L - (session "board" (buffer-string))))), p. Q0 C+ R. U
. l, Y+ ~7 O3 ?. s. O. |& {- t- (defun board-init (size)
% D; \ D* w5 d, q; s. d8 _ - (session "size" size)
; ^+ [/ `4 f! ?0 X" Q! r7 E( m - (session "step" 0)8 F. n/ o# Q6 Z* x$ g2 q& m9 q
- (erase-buffer); j5 _) j) [6 \
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))( \1 c$ i$ r- C
- (dotimes (row size)! T& F, h1 `$ y0 C
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))# X' c/ N" z' V4 u9 f
- 6 z* ^$ x7 S5 k, u
- (defun board-contains-p (y x)
8 D3 h& c9 ~8 `7 q - (let ((size (session "size"))). f. C, k4 c( L: Y5 D8 A |
- (and (<= 1 y) (<= y size)2 X1 ?' k2 v- t+ c' ^( z
- (<= 1 x) (<= x size))))
6 }- J5 f8 e+ R' \* D [. g: W& d L
* _& @% D& Z- B- o( U- (defun board-toggle (y x)
& i& Q; g2 ?6 c' i% {( ] - (when (board-contains-p y x)
! w3 Z& ]6 z, {1 C& ]+ ? - (goto-line (1+ y))
7 C# k% c- V7 D/ m) ~ - (beginning-of-line)
5 `+ B( v7 J9 M5 {. b3 a: q' g* \ - (forward-char x)
5 C3 O' n5 R! i$ ~! R, I0 c$ ^ - (insert (if (= *wechat-5x5-white-chess* (following-char)), |% u" h1 \, L$ w0 p3 {% o
- *wechat-5x5-black-chess*; L; i# s0 S3 n, z0 Q) n
- *wechat-5x5-white-chess*)): {- }' r& H; y& N# q" I
- (delete-char 1)))6 G! l+ b7 G% {& S7 k
# C, D/ @5 x0 j- \6 t/ j2 E2 t- (defun board-put (y x)- P1 {( b% s0 c7 V0 z
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
- n' `3 U" i3 I# T+ y- P* M - (board-toggle (+ y (first dir))
( b! {8 R# y9 z+ \, w9 B3 f$ G - (+ x (second dir)))))
6 M) j h0 h+ v - ) v/ ~" N% @% f" M: R" A
- (defun game-over-p () q8 `4 H$ ^0 j* }0 c
- (beginning-of-buffer)
U; i: ^2 {- V - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
1 Z; _) G( B: u1 \6 p - 1 i* x' [' w# A- s* i; c
- (defun board-show () j8 e4 q- [. d
- (with-board
7 l8 \4 B1 R5 y6 P2 _2 v z - (concat (buffer-string)
2 a0 c9 V) e. |+ { - (if (game-over-p)
4 q8 P7 [8 l# j" k - (format "共%d步,输入任意内容返回大厅" (session "step"))& o$ m/ t5 l I- `8 W/ h
- (format "第%d步" (1+ (session "step")))))))
/ G) ^) M) Z/ K, b
4 L( O. w) K, o7 T& q$ _- (defun board-position-parse (cmd). E8 U( G- F; q$ A/ |2 @
- (if (= (length cmd) 2)$ O3 C7 [- \$ Z: R' y* i
- (list (string-to-int (substring cmd 0 1))* }" {3 O) R, d
- (string-to-int (substring cmd 1 2))): g+ x, @; }; `3 i0 |
- '(0 0))). y- M% [1 |" u$ L) B1 T6 U' E
- 3 Q' v u1 Z6 b6 k K3 ?
- ;;; 游戏房间5 V$ i0 w5 z- o( R3 l5 r( V
- (defun game-room-init (cmd)7 x7 A& R* j% ~2 _/ w {. \5 o g
- (let* ((middle (string-to-int cmd))5 R/ P2 E8 k$ d% L) t+ ?1 ^+ x
- (size (1- (* 2 middle))))% u( y' o ~/ }" V. H
- (with-board9 `; \( E% W( X, p+ V: g
- (board-init size). @1 p* b4 V5 F; A; {
- (board-put middle middle)))) q" S) D/ T+ y4 \7 y
- 'game-room)4 d! p! m( Q2 p) M* w: i, U" G' H
- 7 f* h% f B( i( r' t( w" |
- (def-room game-room' `9 W$ k0 X: {/ r) k: K& x
- #'board-show6 A: k: l5 g" a
- (t (lambda (cmd)! \6 _# W! M% t7 f- P, H {% ~3 k" o
- (with-board# F2 M- J. @8 _- H; v' ?5 F
- (if (game-over-p)1 t: w: Z$ G4 [7 ?
- 'living-room! V' m5 N- V4 D6 W% R* |1 ^
- (destructuring-bind (y x) (board-position-parse cmd)
6 F& R: ~% f/ s$ ?: M - (when (board-contains-p y x)* x0 s$ ^1 k0 A+ M& z# q
- (board-toggle y x)3 i) _/ s+ [; Y! [& k" W# _
- (session "step" (1+ (session "step"))))+ r2 o$ Y: n- Y
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|