wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。' J7 J6 ^5 I: I. H: L9 N: W
借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- " ~, S) u# P, b& j X( I! u
- <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 j& }% |! s; e* }0 ^# L - (def-map "/game/5x5.el" ; 对外开放的URL
) G) P* Z) e0 Y! G2 O: c# l - 'tutorial-room-0) ; 默认的入口$ i2 U1 V. w9 r* h* @2 M
- 3 s9 L0 z3 n3 `6 t( Z2 y. J9 r; u7 `
- ;;; 游戏大厅
) B& Z' {1 p; O6 u$ f( N& c- [ - (def-room living-room) M) c6 n$ N! u9 N' D" f6 O7 @7 T
- ;; 进入该房间后的提示语, Q3 t% z9 L) J* p4 X2 I, c
- "1. 教程
5 Y) h. C6 y9 I - 2. 入门(3x3)+ b2 j4 _( F$ c1 K! }
- 3. 初级(5x5)
2 G0 Y& H- g* V- p6 x - 4. 中级(7x7)7 D/ p5 a1 }1 B v
- 5. 高级(9x9)
+ |6 ~/ p' I5 j, X - 0. 关于作者
; D9 c) ?9 D1 ~1 s* V - 请选择1-5开始新游戏:". X8 V8 ^+ D% @) z, A1 p' q% `
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名% T9 c; m& w. \# w$ Z# T
- ("1" tutorial-room-0)
4 |) | L4 A6 Y; S8 G E! K - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配
4 |7 G4 n% {1 H- { - ; 相应的返回也可以为函数,动态返回房间名
, O, B; e! Q( [% l$ q: N - (t living-room)) ; 如果条件为t,为永真1 m# Y$ }3 `$ t5 W
- ( Q- B* p# ?+ s' A' c' k7 A
- ;;; 作者信息
9 C: |' m, Z5 K R9 n - (def-room about-room& g5 v9 W, E7 l- ~
- "作者:redraiment+ x' ^" w6 M1 a2 G; }4 @
- 微博:http://weibo.com/redraiment. Z' }3 o7 V' ]. r, \' t
- 有任何建议,欢迎在微博或微信上联系redraiment。; z3 D8 r. \/ ~+ ]9 r# j
- 请输入任意数字返回游戏大厅。"
- g8 J( F3 ^, c, g$ B - (t living-room))
( u- [7 f5 g' {" ~
( q- ^, d* H% o# H- ;;; 教程
7 X2 H* e% r: W& e - (defvar *wechat-5x5-tutorial-rooms* 08 N5 T8 I+ ]! ~* J! _
- "The number of tutorial rooms")9 ]1 k- J$ B& j5 O3 r& r$ v; d/ I
1 u2 n P0 k' U" |+ l5 O. w; \0 ^3 R- ;;; 简化教程的定义4 I; F! I" B( k. Z6 b s3 p
- (defun string-last-line (content)
) B* k e Z. v. O- ~ - "多行内容组成的字符串中的最后一行"
2 a! y. ]) a) j. o - (with-temp-buffer
% _& L: m6 [1 u" N, D - (insert content); M8 ~' k2 Z# U h
- (buffer-substring (line-beginning-position)
( K5 I% L- j" Z, ^8 { - (point-max))))4 n; N& Z( \) n, O, g
- Q7 X$ ?( D$ }( m! R( Q8 r1 y
- (defun def-tutorial-room (prompt)
; a% g4 w- B! s$ i* j$ ]7 ]( E3 y - "根据提示语自动生成教程房间。; H( G7 h; O( |3 B; w; w
% r, A' y) e" ^/ a* Q' `9 o- 1. 提取最后一行作为问题;
- b" s6 m$ h% T4 h! t) c - 2. 分析问题,获取期望用户输入的内容;
0 a: t4 ^- `2 P7 c( N - 3. 定义教程房间和重复提问房间。" j" y+ h; m. N Q
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
# j9 m" t( `/ d. o& M3 L r5 ] - (repeat-room (concat room-name "-repeat"))& ]. b9 Z. i: i
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))
, i7 ] r' b! L( Z* N - (question (string-last-line prompt))
; I4 l) e0 I9 @) G: U2 z" s2 t: W - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)2 d+ W$ V% s, Z. P% L3 p
- (match-string 1 question)))# R+ _4 }! q3 W9 d1 e5 i1 }! b
- (doors (if except
! m5 x6 J4 \! e6 m# R j - `((,except ,(intern next-room))1 A& t c5 B/ o. R$ j. i
- ("q" living-room)0 I/ m0 T6 O7 X- o
- ("Q" living-room)
$ g9 s, _! [ t% h! Z" p% r; x - (t ,(intern repeat-room))); H- w* j7 g) d2 C: \
- '((t living-room)))))
7 H: a+ W# G( w! N" X* e2 y - (def-room-raw (intern room-name) prompt doors)+ U: ? B O: ^. [0 Q
- (def-room-raw (intern repeat-room) question doors)))
) S/ R$ k7 t# N; d4 b - 5 x$ Y; k. q. m) n1 V$ ~7 r0 `
- (defun def-tutorial (&rest prompts)0 m6 i# t% `! d0 a
- "批量生成教程房间。"* m; h: H2 G- O/ i0 C
- (dolist (prompt prompts)
! Z2 a" [, e) f; z - (def-tutorial-room prompt)))
9 M2 C: b4 y5 ?, X. ? - ; E* C+ [9 N: w
- (def-tutorial6 r* l& N* c9 i [0 t o
- "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
( u% Y2 M, d! J& c4 L - 1. 教程
' g; v% L2 c6 ` - 2. 入门(3x3)4 C) V" @1 S! \( T$ V0 M
- 3. 初级(5x5)2 g8 G7 S) F! z* {$ U' E( j( I, r) H
- 4. 中级(7x7); j* d+ {! {) F9 H. {4 K! p
- 5. 高级(9x9)7 r% J0 P! F1 Q8 E
- 0. 关于作者
" {6 j" ], k: M% o. N- a4 b - 请选择1-5开始新游戏:$ y- F* r8 D3 n$ x+ ~! S
- 您现在正在游戏大厅里。
# p7 B3 K3 [5 v# p - 请输入“2”进入入门级房间"- b8 x2 G9 C w" O& l9 ~* V
- " ①②③
0 I8 V0 H/ m/ m+ O" A7 } - 1 ■ 7 K+ y3 O! K: H8 D
- 2■■■( N$ M$ y- k. N5 e& f! `( x( F) \
- 3 ■
5 I! ^0 p! U2 d3 F) m; i - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
; g0 e. S- o8 f. { - 请输入“22”来关闭第2行第2列的窗户。"
' C% E r: l/ q0 C - " ①②③
8 W- V! X2 n$ z) Z - 1 ( L% U$ S) I( F5 k5 r' }
- 2 ; e+ w' R5 V; c4 i+ X
- 3
1 G' o0 s6 \0 |( x( p5 I1 B - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。
2 V1 [2 c8 }. p, D( d" h - 请输入“11”,试着开启左上角的窗户。"; L# {7 y9 ]7 Z# f# P4 ~& a- Q
- " ①②③. {2 Q! k7 a" u. J$ s, Y
- 1■■ 4 K! L7 k }6 i! J" i+ X
- 2■
6 l. I+ w# A' I- ^3 q& S - 3
2 ~1 l! H, Z7 W6 J - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。* A6 e) ~2 x$ h1 Z3 b: m. {
- 请输入“13”开启右上角的窗户。"0 H, A- h# _ x2 r! Z- b) \/ G( A
- " ①②③: k- S+ a1 d5 `1 D# K
- 1■ ■1 v2 a! @0 n, Y4 |. \
- 2■ ■ V0 H c. Q) |5 p* U: ^
- 3
* X3 A& Q$ S4 U1 ~. P4 g% | - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。( f$ f( k! O+ Z
- 请输入“31”开启左下角的窗户。"
& b' r# q2 U8 u - " ①②③1 G& m {; |' i0 z" L" I
- 1■ ■2 [- I' d9 k- ]$ n
- 2 ■
# V! g0 Z: |1 a2 d - 3■■ 5 Z3 U, T; c3 I! I# o0 s
- 此时,总共有5扇窗户被开启了。
+ j; z4 f9 P: A) E - 请输入“33”开启右下角的窗户。"% @5 D- A! I0 G. ^8 H3 ^
- " ①②③
- z$ O8 }5 y( z! t - 1■ ■
& m. e& p+ e* q2 x4 z - 2
I( j" I' q* _* {" L - 3■ ■2 }4 e. ~2 i- q& j* r
- 现在,只有四个角落的窗户被打开。) B! J, s- i+ t o6 X4 `7 t2 v
- 请输入“22”完成最后一击!", r8 N5 ]# S. q- X$ V! e
- " ①②③
& c a, m- K; v I: D) f - 1■■■& M6 G [: R: w% w1 P2 u! A
- 2■■■( W/ E0 F7 A) X; ?7 f6 y& |6 x) [
- 3■■■' q% R5 r- A7 }6 e; F6 v# X: c
- 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
+ z& \, U* w% w7 N2 w - , t( b5 D2 |- m1 H- u
- ;;; 棋盘
: z4 ~9 m K# p+ L - (defconst *wechat-5x5-white-chess* 12288
9 c1 Q. E. l+ q2 p* T' c4 R5 c - " ")$ Z/ m5 t0 g0 F8 Q& y( z3 N9 R
. g- q/ Q6 |# L0 J k- (defconst *wechat-5x5-black-chess* 9632" b1 P9 u S: s B
- "■")
2 P3 Y( t) M/ q3 d: q5 l$ ~' b
! t" N/ \3 ~4 R- (defmacro with-board (&rest body)
4 Y# C: ^' n2 u& Z9 o; I1 e7 `# V - `(with-temp-buffer" \. T- D& e3 F+ z3 X+ z. k. j
- (unwind-protect4 p# W+ ^7 M5 m- N# Y4 ^
- (progn
, Q- k& U4 I$ Z - (if (session "board")$ R/ `( C) r# K% a& Q, J6 u! b
- (insert (session "board")))0 p5 U% U% T, c3 @& T
- ,@body)
0 c+ d5 i. T1 L - (session "board" (buffer-string)))))0 J4 D- I/ m/ _& V6 ^5 J
- % d9 s" g0 x3 P+ V
- (defun board-init (size)5 E; k# `7 d. O/ P3 |7 W* C
- (session "size" size)
. w3 Y4 L# }' d+ N! n' { - (session "step" 0)
. P S% }* V. O - (erase-buffer) Z" K" I7 Y) D V- R7 c6 j. M
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))
2 ` H4 l u) g U2 f) e- L - (dotimes (row size)
& }+ a% Y3 p5 N) @7 o - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
* Z# T" Y+ G* \8 w - * a" g3 H' l, Y2 w3 u L4 c
- (defun board-contains-p (y x)
5 y" g0 N. p! b6 J& r - (let ((size (session "size"))); \" l, q+ c! R
- (and (<= 1 y) (<= y size), O' V! @# c( V& x
- (<= 1 x) (<= x size))))6 Z1 _+ s! C: X# a$ F
' }. Q$ w6 {' x2 S2 d- (defun board-toggle (y x)
* n6 P M- g C5 [ - (when (board-contains-p y x)! i% n- G$ e6 n! O) B v* |
- (goto-line (1+ y))
! M+ {4 z; Z3 ]( b0 R# P - (beginning-of-line)& B; L8 {2 w5 G
- (forward-char x)' G$ g& s+ Y) {. u3 e( A1 X
- (insert (if (= *wechat-5x5-white-chess* (following-char))
9 u8 }# \1 G1 u1 x, \5 s - *wechat-5x5-black-chess*
7 R$ k5 q* `* J3 S - *wechat-5x5-white-chess*))$ f6 h) I6 E/ Y$ k) k% M' E
- (delete-char 1)))
% A1 N( I% j/ b+ g/ e - % Z! P; G! }5 G- Y
- (defun board-put (y x)
; T _/ j o* Z6 e) u9 {3 l - (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
. E# j- M$ n6 m$ `0 r+ ]9 @ - (board-toggle (+ y (first dir))7 v$ a v I: }) S4 y7 P
- (+ x (second dir)))))- F, f" r4 O, N N; h8 u6 a7 O2 }* y& P- `' n
/ l0 z- }0 N2 z3 O$ Q {* n9 h- (defun game-over-p ()% O* z2 Q4 n& M
- (beginning-of-buffer)
; H# u P* W' F$ ?2 X: L( _ - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))- Y) E! u1 [7 a2 e9 C- }! s* e0 d
- 2 l# s# E8 B& H0 R0 M0 o# l
- (defun board-show ()
6 O( z0 j5 J* }- V - (with-board
" \9 e3 J# u/ \+ a: z% s - (concat (buffer-string)
0 a! a( R* G, D+ v - (if (game-over-p)7 v6 l- r! G m' m
- (format "共%d步,输入任意内容返回大厅" (session "step"))
4 O) a5 a3 X1 G* z5 u - (format "第%d步" (1+ (session "step")))))))' t4 ?( c, c8 Y; t7 c
- 7 s& C. X7 D0 D* |6 l9 }
- (defun board-position-parse (cmd)
& ?& U/ l3 ?% G7 u9 m2 E - (if (= (length cmd) 2)
' c0 @/ V3 I$ r' e - (list (string-to-int (substring cmd 0 1))1 E. m! F- U, U& |
- (string-to-int (substring cmd 1 2)))
) s! r) S4 N% @1 \6 I - '(0 0)))
5 e F/ R7 o; K/ [3 f
5 m) \6 j- a% s* ~- ;;; 游戏房间
& |1 M$ F/ M9 Y6 h" _3 U7 m7 G - (defun game-room-init (cmd)$ v% b# \8 Y' X/ i3 i q: w
- (let* ((middle (string-to-int cmd))
8 C0 l, _" V7 e7 ]- M. M# w& R( _6 M - (size (1- (* 2 middle))))( y, Q) `' F7 Q( a$ U
- (with-board$ L& W* a5 T- q! t: W/ r
- (board-init size)
) o$ z4 g( W Y; G" o - (board-put middle middle)))7 E i" l0 l E9 C
- 'game-room)# N+ C0 y" n$ q2 w
# Q. b- `% D! q* K- (def-room game-room4 V/ k- m, U a1 R8 |
- #'board-show% ?2 |! Q3 i# p4 W+ ?& }
- (t (lambda (cmd)
/ Y6 ]0 D- Z2 _' k- Z4 P5 D - (with-board
( K$ `* \2 F3 K- f, y - (if (game-over-p)
$ s" w' Z& }5 b/ C4 |7 V, @ - 'living-room
9 m- Y! e) E$ j - (destructuring-bind (y x) (board-position-parse cmd)5 F/ s: \, z( @
- (when (board-contains-p y x)& @: h, R* e# ]( X* e* `% L; q
- (board-toggle y x)7 J& B0 f O# q; Q3 k) `
- (session "step" (1+ (session "step"))))* l' P( P$ m; N C& _$ m
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|