wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
3 l; D* y1 K% m借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。
) `! B7 d$ w# p' 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;">;; 定义新的游戏地图
2 @ C8 S$ U. Y- a. M, `( [ - (def-map "/game/5x5.el" ; 对外开放的URL
9 @/ J7 S) D5 g' `' K( | H* B - 'tutorial-room-0) ; 默认的入口# T6 a5 Z! Q! K; Y. w& E$ }, y
! @3 W7 M' ^" b, T1 u& O/ c- ;;; 游戏大厅8 s( f; B4 q7 M' S" ^+ [% r
- (def-room living-room0 H0 ^- u* E Q, { W
- ;; 进入该房间后的提示语; Z0 s/ \# U% D* J7 y
- "1. 教程
" q* l7 _& I0 E, v4 j" o9 \ - 2. 入门(3x3)
" ^& V1 ]( `/ @# O- \ - 3. 初级(5x5)7 J3 {- I) B8 ~+ r" [$ Z
- 4. 中级(7x7)2 W! z- P: d+ P# M/ K' n
- 5. 高级(9x9)5 R, s+ e' s9 T5 t8 q3 p- M
- 0. 关于作者6 f2 V3 s. J2 W$ s# b" y% A
- 请选择1-5开始新游戏:"
8 E% ^7 Y) m' w - ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
. _/ h0 E" O. O! ~ - ("1" tutorial-room-0)
# I+ k0 ?; A" J9 b* @$ l, O - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配
* p/ ]0 h Y) X, v - ; 相应的返回也可以为函数,动态返回房间名
8 J/ y3 S/ q( y$ ` - (t living-room)) ; 如果条件为t,为永真* x7 u+ b% e: J" D1 z( `; K& ?
1 f1 H! Q7 I& F5 \3 D" R- ;;; 作者信息0 V! N# L6 R/ B; ^
- (def-room about-room$ } Q1 W0 ]2 Z6 H$ l& J# K
- "作者:redraiment
# y1 \& V |+ x- @" U$ h/ L - 微博:http://weibo.com/redraiment1 W& H5 B8 B( T! b) e3 ]
- 有任何建议,欢迎在微博或微信上联系redraiment。
, \6 F( z3 A& Y* S: `0 }, ` - 请输入任意数字返回游戏大厅。", p6 ^# b: l8 {
- (t living-room))
" F; i( f+ V. q& w+ I - * N l" Y7 _9 }& P! L4 B
- ;;; 教程
, X# @$ {4 U1 S% z) e - (defvar *wechat-5x5-tutorial-rooms* 0
, k1 {8 S8 q/ z4 N& x& H* T J - "The number of tutorial rooms")0 l9 M& ~) U" ?1 I% H
- 6 S4 R5 c" q) V9 J( l; {
- ;;; 简化教程的定义
; ?. S0 Z% O9 c' I, N - (defun string-last-line (content)& B5 x, V# C" i" A* x9 e) `
- "多行内容组成的字符串中的最后一行"# }9 @" B5 C7 X2 X: ]. u+ V% e
- (with-temp-buffer$ n# B5 o, s) {; H
- (insert content)6 H- g5 {8 _% J% f8 d7 S
- (buffer-substring (line-beginning-position)
d3 v+ ], M; x8 ^: y - (point-max)))) S/ g6 v$ ]1 G" A
- ; k7 A+ v# ] y6 M2 B f! ~1 f
- (defun def-tutorial-room (prompt)
4 v7 j- Q1 J8 e0 W - "根据提示语自动生成教程房间。
* I _6 _/ T* h2 t) f2 g, x. h
8 I1 U, y* u% V; X- 1. 提取最后一行作为问题;
4 d1 C- C, G4 x/ L: d A* A- e. Z - 2. 分析问题,获取期望用户输入的内容;
; p+ ^7 i i' w* m% b - 3. 定义教程房间和重复提问房间。" }; Z5 f. ~- }/ e1 O
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
3 y4 P5 X w9 U4 _, e1 r - (repeat-room (concat room-name "-repeat")), A8 W0 ~' w" n
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))) |% f1 N% w$ I) U ]; h
- (question (string-last-line prompt))# m0 l4 N6 F$ _; q( x
- (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)
( S3 E. h, Z3 {* }4 h7 L/ y5 \ - (match-string 1 question)))
+ |1 ~: @$ r; w- D - (doors (if except
$ n& d0 g7 m$ L2 A% c* z' N - `((,except ,(intern next-room))6 ^# t& [0 @1 \" ]) o+ Z) b( @
- ("q" living-room)
* d6 F4 |; } b1 U/ C- Q% R - ("Q" living-room)" s/ V. U( _9 Y3 a6 c
- (t ,(intern repeat-room)))
& i* j: u2 _- ] - '((t living-room)))))- j5 N% a- C: s0 Y/ d' a
- (def-room-raw (intern room-name) prompt doors)$ G5 y% D7 X- c" |
- (def-room-raw (intern repeat-room) question doors)))% ]5 d& H2 |' Z s0 b
) w! M3 V( k8 W/ ]( q; ]5 d- (defun def-tutorial (&rest prompts)+ X) X t+ F- N! E/ j, f) E
- "批量生成教程房间。". ]2 {0 h% f* D9 x" K- ~- }
- (dolist (prompt prompts)
7 S. y! {/ F* w' V2 Z* L - (def-tutorial-room prompt)))
7 `( ]. D% M9 E$ E9 X( G, `
3 F B2 J4 i1 n( i6 _- (def-tutorial$ x \& D$ N( X- r
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
) O: X& G4 M' I D, k - 1. 教程
/ o! g" C5 ^8 n, Q, l. O7 ?2 _9 L2 y - 2. 入门(3x3)- ~9 G0 @. i/ S0 H
- 3. 初级(5x5)* C4 Q) b4 s' z! D
- 4. 中级(7x7)
( t! U2 ~* S1 ? - 5. 高级(9x9)6 u; f4 ?, ~8 U: z4 d0 [* w1 g
- 0. 关于作者: O4 }' ]' ]- E. k |& i* P
- 请选择1-5开始新游戏:1 |9 T: v/ P2 {7 K* y: Q
- 您现在正在游戏大厅里。+ [8 I4 X) `1 A5 D' n2 ^
- 请输入“2”进入入门级房间"
/ n5 u' q I6 E2 Y+ I. r - " ①②③
( O- A; w/ p5 l3 ^: E5 w - 1 ■ * _+ d# k' ^- v. M0 d* y
- 2■■■
9 j L+ _, g% R$ q; L! `. Z- \ - 3 ■ 2 M7 J# ?. j7 n7 V! ~7 _
- 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
9 h" ?; i! a* m2 t2 y, d - 请输入“22”来关闭第2行第2列的窗户。"
1 C9 l; }0 H' ^' W4 K% @+ h7 Q - " ①②③
, B7 x+ U H# C( p5 t! J - 1 ) t5 b4 V) F6 V/ @% v# S
- 2 0 M Q$ a9 s1 U2 N/ [% B3 M
- 3
! @9 |$ r) z) O1 D7 ` - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。4 Y- u2 g6 l5 U/ n2 c3 s6 p
- 请输入“11”,试着开启左上角的窗户。"6 e" F0 T0 ?- X! w: L- A
- " ①②③
! }: e2 C# o1 c - 1■■
1 u T; b1 O7 m& n% `1 u - 2■ * \$ C5 `. ]2 b; m% y' P3 b9 T
- 3
5 [6 E* a& U% i3 z: o, O - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。
/ l" |* } @" a& [ - 请输入“13”开启右上角的窗户。"& n5 i& J9 _1 B9 t9 f2 ^) ?
- " ①②③7 ^/ Q( w% f d( z+ s, a) Z" W
- 1■ ■
3 P0 @! H" C w5 y& a3 m - 2■ ■
m" U" u7 M* h6 ?! l. q - 3
/ |4 U h8 s( D3 a. f. Z( m4 r - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。2 D+ m! {# c9 k4 y; B% j
- 请输入“31”开启左下角的窗户。"! C+ X# l) {2 l* z- F
- " ①②③/ i8 ^2 j) T7 f
- 1■ ■
+ G c4 j" P9 P% [! j) B: k7 H - 2 ■3 x! j) f& K( d* M }# l; L
- 3■■ 7 k6 E, F( c; h4 S% S
- 此时,总共有5扇窗户被开启了。# r0 N5 U$ F# G/ y% Y
- 请输入“33”开启右下角的窗户。"
2 e) I( Z: v9 O. ^. C - " ①②③
# ]: d& C6 A+ j9 U4 _ - 1■ ■' l" Z2 A4 W6 }* e
- 2 / ]- A+ b# j0 ~! t% e! r
- 3■ ■
$ F5 E2 D/ W8 d& M w - 现在,只有四个角落的窗户被打开。
6 z2 l8 R9 b& P5 D: R1 L4 ^ - 请输入“22”完成最后一击!"
4 p' m p+ B9 l" i - " ①②③
, A5 @5 m. k% \ - 1■■■
- a0 ~5 r6 W1 T% g9 W - 2■■■
! n: s" O" Y2 n. O - 3■■■% I0 \& H( ]! T" q E
- 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")3 V( ?* X9 c7 R' `6 i
- 3 ]0 _% G8 G' A) s( r; X3 q% I& b
- ;;; 棋盘1 I( C6 N7 A2 Q3 h) r: e" ]
- (defconst *wechat-5x5-white-chess* 12288
6 D0 u5 ?! h9 G% x - " ")
1 m- K9 y& x4 }6 S$ H$ ?4 M
( J; H; |0 E: v. P- (defconst *wechat-5x5-black-chess* 96324 q8 S+ t. B2 M6 {. N: m
- "■")6 M2 O6 d1 D: M- B7 h' Q" L
- ' ?' Z* t# j m$ T& O
- (defmacro with-board (&rest body)5 T4 l2 P8 Y# N" V) c
- `(with-temp-buffer
5 |3 X- r: _$ l - (unwind-protect
& \% n- I9 d j - (progn
- d- }* q/ d! G5 ~; B+ U" j - (if (session "board")- f7 G. f+ D' V
- (insert (session "board")))+ R3 x# p" Y0 c& J
- ,@body)
0 F2 ?8 k& L' L4 I: P1 B - (session "board" (buffer-string)))))
" q5 Y$ W) F! [6 p( g" p( _# H0 w3 M - # k# H2 \/ x- V+ G
- (defun board-init (size): ?) {/ u: R' K$ v0 O
- (session "size" size)7 n2 ]; V9 m$ H+ I# h
- (session "step" 0)
* e5 L+ V3 C9 k2 l5 u" V - (erase-buffer)% w1 \$ H) i( a# k! Z
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨")); P6 @, a# s3 M# i0 z2 ?6 O
- (dotimes (row size)- L3 W, E, |) Z0 E
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
7 X! |# y; j" ^; U. a7 f
( M9 b1 ~' f" }- (defun board-contains-p (y x)
. R# i! T9 ?: t+ }. x' L - (let ((size (session "size")))
* p8 r" u8 G& K. p; R" S - (and (<= 1 y) (<= y size)
. f* j; G/ ~9 _0 f& I0 J - (<= 1 x) (<= x size)))). R" C7 J6 V, p! O: G4 d' z
2 Q `+ E( i- e% L6 f- (defun board-toggle (y x)
! k, y' f y7 d6 n - (when (board-contains-p y x)
/ }7 G( _# ~3 A - (goto-line (1+ y)); I0 C- t) _. Z0 f3 S) @$ v
- (beginning-of-line)' \" r5 r3 C" }" Q" g
- (forward-char x)
9 w" ~8 d7 H- [& I' {" i$ ] - (insert (if (= *wechat-5x5-white-chess* (following-char))
7 @. x. p- c5 ]% t8 j7 T; ^ - *wechat-5x5-black-chess*1 G7 ~/ N% ^+ t2 s, k
- *wechat-5x5-white-chess*))9 R8 u- n; }- d9 h
- (delete-char 1)))" J" P! x$ P6 }' o
( [7 T9 O# h0 ]: s- (defun board-put (y x)
/ V3 v( T5 f' W, t) z6 W- ~ - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
' x, v1 Q5 r1 q( W. h8 I - (board-toggle (+ y (first dir))
8 T" ?" g$ y7 D - (+ x (second dir)))))
* W* S" w0 E' i6 G8 K# U F0 W
" ]6 d! K' I) q) M2 A1 T" H- (defun game-over-p ()
2 f7 y8 R' g* A, H. d n" { - (beginning-of-buffer)
, {5 G6 T$ C% i - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))2 s4 n) d. r3 h! B" @8 o( y
- ; f k, W- P. c$ B5 x9 _
- (defun board-show ()
2 E8 M0 |# D+ e# b - (with-board
' ]/ \& j1 K( z! \$ n% k - (concat (buffer-string)9 ~* {; y; K" t
- (if (game-over-p)
/ M" x. C. g* ^8 i9 F$ Z! s' i% r9 N - (format "共%d步,输入任意内容返回大厅" (session "step"))
/ V" t( Z; b, `3 { - (format "第%d步" (1+ (session "step")))))))* `) N' A0 \8 c9 `
+ P: o0 i5 {5 C0 Z- (defun board-position-parse (cmd)
- Z5 n9 c' X b% }; V* E" C - (if (= (length cmd) 2)
/ X9 Q: h x: h2 V - (list (string-to-int (substring cmd 0 1))7 C! I* V2 O6 h% o) _$ f# {) @
- (string-to-int (substring cmd 1 2)))& E h3 @! {5 x4 J+ t& e8 Y, }
- '(0 0)))
! R q* _& `) @, h6 b$ w
# j0 g/ ?# t& H( L- ;;; 游戏房间- [0 K) g8 ], ~) Z, u7 w/ C( y' y
- (defun game-room-init (cmd)
3 `; V, r, @/ u# I9 I, N# \) O3 @. S6 K - (let* ((middle (string-to-int cmd))
k9 R9 ~' L& K' } - (size (1- (* 2 middle))))) Y, \& }. _9 o/ B- v9 r' \( i4 R
- (with-board
1 v% C( O0 }, f/ Y, m+ p: S - (board-init size)+ I: F6 X7 U; C8 G P
- (board-put middle middle)))
) w+ y5 `3 d, M/ L: }% O( h - 'game-room)
" G$ A M' c* Q7 L0 [& r" n0 A3 F
+ W& [5 w1 ?9 N8 s7 E- (def-room game-room
5 G1 z J3 W8 c- M! m# t8 { - #'board-show) t; e' v, g$ D* u' Q# Z) I- A& N+ i
- (t (lambda (cmd)4 P, d5 s s0 e& H
- (with-board2 w* X8 p- c3 B% E& G6 `
- (if (game-over-p)8 Q) X& l' N. k. y* t6 r
- 'living-room5 N9 i% C( O# K9 ?" d
- (destructuring-bind (y x) (board-position-parse cmd) I% |# @/ B# z
- (when (board-contains-p y x)3 x0 `! J8 M/ n2 Y
- (board-toggle y x)
$ p/ C- C$ o! s2 J' h: H - (session "step" (1+ (session "step"))))
6 v1 L3 T+ H4 l) F9 O. j% d - 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|