wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。. @2 e5 b$ M8 O* d( Q( f
借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。
1 c* K8 N9 z8 ~) ?. a6 a [- <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;">;; 定义新的游戏地图
' |1 p) d6 ^( t - (def-map "/game/5x5.el" ; 对外开放的URL% X# T; ]1 j# R4 {4 T& f
- 'tutorial-room-0) ; 默认的入口0 y4 q7 u* p; G; m7 S* g
9 _& |+ r5 ?$ \: |* H- T- ;;; 游戏大厅0 C" G7 l0 U& n/ ?0 i* p3 g/ L
- (def-room living-room W& y* i$ F A, G" B
- ;; 进入该房间后的提示语0 G [( c: @9 z1 O
- "1. 教程1 F& E, s/ N/ m* }, y
- 2. 入门(3x3)
1 M, Y# B+ R( O1 E9 K - 3. 初级(5x5)
- J7 w& F0 D$ D" W ?* k8 \ - 4. 中级(7x7): o5 D5 D' T( o( f- H
- 5. 高级(9x9)" k% H2 V( N1 h5 O6 n
- 0. 关于作者
x: H4 K* Z6 w# y$ h- v5 B4 w - 请选择1-5开始新游戏:"- ]0 b7 z1 b0 P, Q! y% W2 O
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名/ \. t" C2 A6 _& g' L7 \
- ("1" tutorial-room-0)& V% j% \/ B# C% H
- ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配: s. y5 Q6 |. B3 P/ W) ?2 g
- ; 相应的返回也可以为函数,动态返回房间名
. C! h5 ?( }1 N - (t living-room)) ; 如果条件为t,为永真% V+ r' R6 U6 m' M
! K7 S0 r% L& S5 E6 a5 f) T- ;;; 作者信息
& \9 k4 T, j6 K5 z - (def-room about-room
( x* Y/ M: Y: D8 F) e: A - "作者:redraiment
5 u/ M: V- ]+ Y) ~0 f5 H( w - 微博:http://weibo.com/redraiment H9 s t* L+ _/ v i/ t
- 有任何建议,欢迎在微博或微信上联系redraiment。
1 V; J0 ~( a9 Y! Z% o - 请输入任意数字返回游戏大厅。"
& f+ ?0 Q7 O' o/ k D - (t living-room))
% J# B1 W/ g' e
. H. F& R" Y( F* d, F3 x: a- ;;; 教程: \/ T1 p) U1 Y' P( W( I
- (defvar *wechat-5x5-tutorial-rooms* 0/ O$ r/ q; c6 b* z! O, Z
- "The number of tutorial rooms")
# m2 T8 }3 a$ N2 V - 2 w) k& E" a( ~! C. k
- ;;; 简化教程的定义
' v& q/ _4 f$ W! { - (defun string-last-line (content)6 V' M u. K/ F' G% V
- "多行内容组成的字符串中的最后一行"8 u& U0 [/ @) K$ K4 o1 t
- (with-temp-buffer
5 g: `) P+ U2 D y8 u3 F - (insert content)
/ Y. V9 Z/ e( g- ~' a - (buffer-substring (line-beginning-position)
) S5 x) m8 e7 m# c - (point-max))))* y6 ?% F+ ]6 f2 b, W, I) b
1 x, p6 G, E& u% d5 S- (defun def-tutorial-room (prompt)- M' b# i, @ l3 Z
- "根据提示语自动生成教程房间。
! L V+ O3 q! s- v/ v
% B/ _8 U( M: S) G: P- 1. 提取最后一行作为问题;
( `. k" k# `8 N3 H" \1 Z$ `! x - 2. 分析问题,获取期望用户输入的内容;
3 a7 ?: _- Z' i6 h6 C/ v - 3. 定义教程房间和重复提问房间。"6 [6 B1 x( _. i+ ?
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
9 b* p* G0 ~6 a$ x0 R - (repeat-room (concat room-name "-repeat"))
" A! F( a( _; l' P - (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))
% c: v8 ^, h$ N+ _ - (question (string-last-line prompt))
% b) w9 [' v! z, m - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)6 j; ~/ Y. c: f1 {2 k
- (match-string 1 question)))- j3 z3 u3 s' Y3 v. ]# U$ ]
- (doors (if except
# Z, b* p1 R* G - `((,except ,(intern next-room))& E9 n) V4 Z [% ~1 }
- ("q" living-room)
1 V' _$ T. F! B# ]8 {9 A' r- ~; ^ - ("Q" living-room)4 a& _) v( X M
- (t ,(intern repeat-room)))
$ _- K( |& Y# t+ K8 G4 r - '((t living-room)))))
& x( f. O, l* | - (def-room-raw (intern room-name) prompt doors)
9 X& Q1 W) d6 p. u - (def-room-raw (intern repeat-room) question doors)))6 _9 T- S$ U/ s3 }0 K5 p
9 T; I% _* o- K- z0 Q s* p" O- C- (defun def-tutorial (&rest prompts)
1 C. Y" ]% I f1 i - "批量生成教程房间。"3 v& \/ L) Y% U, K: A
- (dolist (prompt prompts)
3 ~( U. B7 c3 r: a/ Y( X - (def-tutorial-room prompt)))
7 D. H$ ?% W; |' W - . }( x, P6 v2 [ x% E
- (def-tutorial
# q9 V( R& F7 m) u7 r. H8 E8 v3 Z/ b/ o - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。5 r5 ?7 W) b9 q! t
- 1. 教程
+ W' \/ ?6 I9 b; R - 2. 入门(3x3)# S3 w7 r; }+ X/ m1 Q1 Q6 R
- 3. 初级(5x5)/ \' g- w2 R A, @
- 4. 中级(7x7)
! h) t3 C& o$ A+ A9 ] - 5. 高级(9x9)
6 t6 W; V" X7 B" @! E+ q) N - 0. 关于作者! A R" |/ c d; @; y6 ]3 R
- 请选择1-5开始新游戏:
9 `' s8 q; g9 b. K, E3 @& k - 您现在正在游戏大厅里。
7 d( p2 D$ J) I, V) p' x: J4 c - 请输入“2”进入入门级房间"2 A8 ^! j7 U; R5 S, c/ D
- " ①②③9 o( c/ ?+ c0 M$ t; C6 J) d
- 1 ■ ) N/ c' W& g) ] @6 ]+ O2 o' n
- 2■■■! T" H( A# g! h
- 3 ■
) X& i: B' G) \ - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!8 b3 o/ v% i2 k. \
- 请输入“22”来关闭第2行第2列的窗户。"9 f8 n. @" j" Q$ F+ `
- " ①②③! s9 D2 Q; N6 Y
- 1 # a& ?: f4 z2 M3 g7 r7 l# Z
- 2 # w$ B0 N' l/ w
- 3
+ |6 M' X& p7 S6 D/ U7 } - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。: P2 C" T* @3 D. |3 ]8 d
- 请输入“11”,试着开启左上角的窗户。"
" Q0 Y3 W& [! O2 q! c - " ①②③" f5 m' H- X# ^/ R4 T% X
- 1■■ 3 x. u/ ^% f: L) [1 N
- 2■
5 h% ]) e& i0 Z4 \( _9 E - 3
* M9 u7 C- }0 ]' y - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。! v' x/ \" l$ K g8 l8 _& T
- 请输入“13”开启右上角的窗户。"9 ]0 B" N0 F. O; T5 Y
- " ①②③; l* T+ [+ \) O& a2 B
- 1■ ■ n; F: c# v2 F5 u" n$ X
- 2■ ■
2 `+ N& C! N0 g9 U. ^ - 3 , M# O# d& G) I! S/ T& M
- 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
* d, J9 H) r5 B7 k) A - 请输入“31”开启左下角的窗户。"3 L( ]. ]$ L* I* {
- " ①②③3 b4 s, f# R) a$ p& u" }" b( B1 [
- 1■ ■
7 Q' T! v7 H1 M2 d - 2 ■
0 G. |# X" \( o2 M# T! g1 C! Q - 3■■
8 u9 A) v$ w& L4 p: G8 s6 t - 此时,总共有5扇窗户被开启了。0 d5 G8 G! j& ^+ g) U5 q
- 请输入“33”开启右下角的窗户。"
0 H X8 B* @ F/ x - " ①②③8 O- v8 C# R7 D" O
- 1■ ■
# r+ q2 H" a: S% _5 H) i5 Z - 2
& a- Z0 i: [% h& f0 I* \8 ^( A" \$ A - 3■ ■
9 F4 G. Q, x/ @8 I" ^. f - 现在,只有四个角落的窗户被打开。
: ]5 T# T& ]- m1 P - 请输入“22”完成最后一击!"
S+ ?& W8 P9 A0 d0 A - " ①②③ b- ]& x( r' L/ p1 o
- 1■■■7 A# B' a( J7 y5 i+ `$ k
- 2■■■: N8 `" q0 Y& s: J" q, [" w
- 3■■■9 H" V/ r& c' M6 S
- 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
; y# w4 Q3 G; c. \4 u' F3 A$ D - ; o9 H3 g1 k2 \( `) r7 w ]5 e
- ;;; 棋盘5 ?: O5 u/ a' ~9 | j7 A+ }
- (defconst *wechat-5x5-white-chess* 12288
0 B; q6 `' \3 Y/ H - " ")' A& |3 B3 j1 s1 x
9 s# P6 n f% ^0 g% K/ ^# C7 W4 I- (defconst *wechat-5x5-black-chess* 96327 t$ ?* K/ ]0 k
- "■")
! @3 P* r$ Z6 {% A& v
- r! M4 C4 b" x4 k- (defmacro with-board (&rest body)% ?4 Z+ \3 c+ K4 q+ v# [( L8 p
- `(with-temp-buffer
) \1 U0 W- _8 M' G - (unwind-protect" H. K+ Y+ o* H% i% s4 v
- (progn4 [2 A, n3 y, p8 ~. p% R* t
- (if (session "board")
) R4 ~# S% K- z: B2 @$ P7 A, d - (insert (session "board")))
, d. Y7 J9 H3 s. [# t/ @ - ,@body)$ R4 ?' @. ~* u2 b% H% d- Q
- (session "board" (buffer-string)))))
6 j# H7 s5 N0 R: V M9 m7 w4 j) Z! `
( Z+ c6 L# j( x$ a- (defun board-init (size)
% ?& ~+ b1 b7 G" v - (session "size" size)
5 M9 W: L# J+ |; x9 G$ l' K y - (session "step" 0)
9 `9 D, Q6 z6 m. s* E - (erase-buffer)! f1 y. |/ b- n' @# A% R
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨")). o% \/ Y$ [# K- I
- (dotimes (row size)
& r* j# I) U# m0 \8 O1 w8 R - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))# ~( B- `. O& O4 n
# ~" e w5 n) b8 F4 j1 z- (defun board-contains-p (y x)& U! P) Y7 l% z% J, p+ P2 K
- (let ((size (session "size")))$ X) B3 _' ^+ @4 D
- (and (<= 1 y) (<= y size)
4 [* v7 s+ H1 y/ {5 b - (<= 1 x) (<= x size))))8 w J! W: _: r+ c6 p# z. A* }
1 v5 }4 r r/ g: Y- (defun board-toggle (y x)
# C9 }# d/ w% S5 M3 a - (when (board-contains-p y x). a9 r, t" r5 X, \6 S& \6 u
- (goto-line (1+ y))# _0 m5 V0 V: p* q
- (beginning-of-line)2 {# S U+ G) Y8 F7 b2 k: k$ C4 o
- (forward-char x)
) g2 ], d: P6 E" p& ^+ j - (insert (if (= *wechat-5x5-white-chess* (following-char))5 |0 `# w: N% \( ]0 Z
- *wechat-5x5-black-chess*! K1 ^9 Q7 y# W3 j y B( K
- *wechat-5x5-white-chess*))
; z" K; d `- g - (delete-char 1)))
2 W- E" V" l0 z* A/ x# [0 H; ~
* s9 f8 c3 i* o" r- (defun board-put (y x)
% m+ O0 p. i" j) D( K& s - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
1 \- T, J7 \) e0 y! I Q& @ - (board-toggle (+ y (first dir))
' j8 k6 W2 X$ V$ G% K - (+ x (second dir)))))
: ]; ~# i% p* ]5 t; m2 Y
D8 ~' v/ A9 D8 d! F- (defun game-over-p ()# ^- D. d' F- C) ?5 n8 q* ^
- (beginning-of-buffer)3 W8 T5 W: K2 h; w
- (not (search-forward (string *wechat-5x5-white-chess*) nil t)))2 l; f+ ^1 I( K+ d7 J
; L: U: V; K" g2 W& W6 T- (defun board-show (). W: @8 I; a e, x, Q: k# r5 F
- (with-board
6 r H1 V) `# q0 f y9 O2 |, ~ - (concat (buffer-string)
% d4 E( Z) k7 Y - (if (game-over-p)0 Q: J- F* p9 ]- ?: l1 }6 Y8 c
- (format "共%d步,输入任意内容返回大厅" (session "step"))
0 D5 C3 j& O) O: R# ^/ s' W1 t - (format "第%d步" (1+ (session "step")))))))! x# ?/ l# L! R; W
- : ~1 C ~# m! m
- (defun board-position-parse (cmd)
. x: [, t' l7 | - (if (= (length cmd) 2)
2 R4 \6 t7 S+ a( j h! I - (list (string-to-int (substring cmd 0 1)); W; V' R, N3 Q* b" |3 C* d
- (string-to-int (substring cmd 1 2)))& g5 s% s3 ~) Q: |$ B. u4 u0 {% j# O3 n
- '(0 0)))4 C$ q0 [3 a$ Q8 n
- 5 W+ p' [- ~8 l
- ;;; 游戏房间
" P% b3 x- x) c. j - (defun game-room-init (cmd)
0 J5 u4 \2 p. Z, J. o - (let* ((middle (string-to-int cmd)). P3 Y1 S* E5 ^7 F. D& X# W% I
- (size (1- (* 2 middle))))" Z, y0 t% ~1 i; O6 B
- (with-board( u, c& D4 S8 N/ U) L4 j
- (board-init size)8 P+ p' D7 Q) m5 i! B( U
- (board-put middle middle)))" }1 U4 W* E! R2 h' t/ `7 t. ~
- 'game-room)3 p. r. @6 X: z6 F! K5 X
- ! I( z8 c/ J/ F! l
- (def-room game-room
: Y% f! [& }- J6 n5 ? - #'board-show5 a1 f7 {& m- Y" f# B$ D
- (t (lambda (cmd)- R4 d& u$ m! e! c
- (with-board, S* q& I/ e$ \# x: h1 b
- (if (game-over-p)! V# w% f9 Y/ d1 j" P
- 'living-room7 D1 q+ h" c: n) f9 S% y
- (destructuring-bind (y x) (board-position-parse cmd)
! k1 d' q; p$ X8 q0 A - (when (board-contains-p y x)& B) n, x" E& @+ _4 R
- (board-toggle y x)9 Y# t6 o( M% v6 A
- (session "step" (1+ (session "step"))))
) ~" ]- {- o( e x% ] - 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|