wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。; {) J2 L( u \* q, u/ i+ i
借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。
2 V! K2 t. \2 {- D- <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;">;; 定义新的游戏地图
C# }* E: A5 [$ t" U$ } - (def-map "/game/5x5.el" ; 对外开放的URL% U, ~" W3 I! r% R
- 'tutorial-room-0) ; 默认的入口. d0 J+ [+ P* h) g- J1 l
- 0 {4 |& a0 Y3 m+ D" P+ c
- ;;; 游戏大厅
- q6 J* h: }+ P& }; ~. \- X - (def-room living-room- Z4 F( A+ }$ C1 B& L
- ;; 进入该房间后的提示语# l8 w+ \, p1 F9 d; p3 |/ o% f+ a
- "1. 教程
. i' O* q" ]2 u! `2 E( V - 2. 入门(3x3)/ G# a4 X$ [5 b- U: o& y
- 3. 初级(5x5)
: {3 P6 L: t" ~. v1 R - 4. 中级(7x7)
# G. H# c2 W; L4 k( h# d - 5. 高级(9x9)
8 h$ q5 Z+ a4 Z4 I5 V/ k0 F - 0. 关于作者
0 x/ v$ C% _0 J( E. G% N' B - 请选择1-5开始新游戏:"
& J- |; A" |; d* V. r - ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
6 B' s7 r$ ?) m - ("1" tutorial-room-0)
- V. q) M) O; \% k - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配
. m; E2 F ]( f! I$ t - ; 相应的返回也可以为函数,动态返回房间名# g% e4 |: f/ z
- (t living-room)) ; 如果条件为t,为永真
; H0 s7 A; }5 Q' S+ N
, P: R! O( A: C1 \7 c$ g- ;;; 作者信息
2 W; l3 P$ y) E- m& H - (def-room about-room3 E' j- k' _$ R7 I& p n
- "作者:redraiment& E* [( E( ]% p
- 微博:http://weibo.com/redraiment
$ \4 `: s( G$ @& B+ N$ X1 t- Y. m2 y - 有任何建议,欢迎在微博或微信上联系redraiment。. G E! D( n- c" \
- 请输入任意数字返回游戏大厅。"5 Z, q) G; L6 ]! `: p
- (t living-room))5 l' ]8 i5 |0 p% k
- + u9 b/ f( i5 a( K3 G
- ;;; 教程( O' K: _) t: j
- (defvar *wechat-5x5-tutorial-rooms* 0, k$ f9 t8 g4 x) Y) v( v2 w1 K
- "The number of tutorial rooms"), W8 d+ X8 \9 h% v4 E/ I+ b+ w
- , g# ]' G- C4 q; c& N8 _: C& o' n
- ;;; 简化教程的定义
" n5 p, a5 r- R1 }4 N- n - (defun string-last-line (content)6 C7 J& H/ W; p+ U
- "多行内容组成的字符串中的最后一行"
+ Y0 h! @& Q+ F4 U1 T- S# } - (with-temp-buffer
6 Y+ D% \, ]6 b; j9 s* t& I - (insert content)( O y7 t0 q. Y/ o
- (buffer-substring (line-beginning-position)" l6 o% ^' P3 T& o- `) W) S
- (point-max))))% V& M: D7 N C4 e# \
' @: K G E# g- (defun def-tutorial-room (prompt)* M6 x% d4 k2 ]& f( \2 d
- "根据提示语自动生成教程房间。) T9 ?6 p' p/ j- Z5 E- `
- $ i7 r' T& B( C3 V2 i' P, T% z
- 1. 提取最后一行作为问题;* I7 c& M1 \9 @/ U3 b' |
- 2. 分析问题,获取期望用户输入的内容;/ E6 D! Y1 z' w9 i! v( n% ?' |/ k
- 3. 定义教程房间和重复提问房间。"9 A# H6 K6 M" z& F
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))* ~3 E: I* _& g! w# ^
- (repeat-room (concat room-name "-repeat"))& K) B w& x) W, Y
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))
( J E9 v3 n c! g! F$ k' |3 q j - (question (string-last-line prompt)). G" a/ h4 o4 K; Q8 ?$ o/ r, O$ l, |
- (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)5 z) p+ R- I7 j4 W4 ^ O
- (match-string 1 question)))
- i( R7 U+ r, Q& o* c - (doors (if except
. o1 D4 \0 F, n( J; u: U. w7 W - `((,except ,(intern next-room))3 T( R( ?7 t. v2 l
- ("q" living-room)8 o6 \5 G+ N. U
- ("Q" living-room)1 }5 |8 u5 S( B) g
- (t ,(intern repeat-room)))
% p8 Y3 c1 J1 }& } - '((t living-room)))))
0 T0 m) d3 [: j+ K1 Z& x( d - (def-room-raw (intern room-name) prompt doors)1 l4 r( l0 f; e4 g' X
- (def-room-raw (intern repeat-room) question doors)))
6 x9 p# u! K" p; K
* k, w! E u/ e/ ^1 p- (defun def-tutorial (&rest prompts)
# c2 b9 k6 M3 T - "批量生成教程房间。"2 b' \ g7 a, Y/ e8 E# m3 ^. {
- (dolist (prompt prompts)
$ w$ G4 O5 e3 C# |9 D. ?( } - (def-tutorial-room prompt)))* t% \) m& f& }6 {
5 R9 N( t! t8 Z/ ^5 @- (def-tutorial
/ r/ e! Q. |$ l Z# Y - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
& |$ Y5 g9 {$ s: T) ^5 V - 1. 教程% t& ?, z4 h9 ?: B; O
- 2. 入门(3x3)
) n" S3 d0 D5 v4 t. ?2 v) u - 3. 初级(5x5)% ~% t, Q8 o2 {3 C
- 4. 中级(7x7)2 `" |5 J( z" R# E6 g
- 5. 高级(9x9)
) Q( \. s0 A" O* V J - 0. 关于作者# ]$ Q+ A' }2 S& J, \+ m
- 请选择1-5开始新游戏:
: N" [" P) }& z8 _. W' u; f - 您现在正在游戏大厅里。
! u- ]% D1 P9 i* s7 h - 请输入“2”进入入门级房间"
: Z' _* c7 o7 m7 J) A& Q - " ①②③( q, a5 |7 ~+ G3 G% F
- 1 ■
* s5 t0 H, r) A+ i7 I - 2■■■
% Q% B- G* D& y" o - 3 ■
; F5 B7 p2 T' f f( K# _' X6 w' F - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
2 f4 ^+ b# @1 Z - 请输入“22”来关闭第2行第2列的窗户。"
' ?: h# t. z: s. v - " ①②③. B0 }; C, ?6 B: W1 Q
- 1
" L; c: C( N& z+ n: d0 M* @ d0 E- j - 2
" X2 T+ G6 I# D; o6 r - 3
% l* \; c/ E7 u; W - 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。2 y, z7 V; l, \6 j# l* G
- 请输入“11”,试着开启左上角的窗户。"
8 Q: W6 t# i" g% _ - " ①②③9 p U* _. I* F1 E
- 1■■ ( x0 |/ P% _6 d6 v
- 2■
, ` h9 s7 c; O+ m* S- n4 E: m+ o* o - 3 5 u) ~! [' i: D& p$ Z3 ~ u) U% j
- 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。+ i3 ?+ @* X- f4 d% @, \1 o1 O
- 请输入“13”开启右上角的窗户。"2 f1 C$ X/ A7 v6 @) h8 b
- " ①②③+ [7 O4 _# [9 J: N* h% `9 W' s- V" M
- 1■ ■
8 i. x4 U) P, q7 f2 o! g - 2■ ■
7 _5 @# j& F2 J, U. g+ E: C/ N6 _ - 3 ! J7 m0 ~1 P/ V: B
- 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
- V/ d1 [% A) y2 {: h4 W - 请输入“31”开启左下角的窗户。"
; y+ @0 W5 O9 O - " ①②③
* Y) @/ O9 M9 f9 I* d4 j' J1 n - 1■ ■
: e9 m5 D% V3 b1 N9 K! X - 2 ■
+ B! i7 Z6 [" A4 `+ d - 3■■ + K6 t6 ]; ?% N) r
- 此时,总共有5扇窗户被开启了。
. _: @. C, i. D2 K% Z - 请输入“33”开启右下角的窗户。"+ B/ a% h S4 r
- " ①②③+ `+ o) r1 ~* s$ n9 X- U; ~5 U
- 1■ ■4 i, C3 q B* R& }; t
- 2 : A& E( [2 p/ r5 P; r' r
- 3■ ■, p# q: j/ a H J% ?+ A
- 现在,只有四个角落的窗户被打开。
6 r; V, i4 A. N! o. f. D - 请输入“22”完成最后一击!"2 J$ V; f. o- W& B, z. L# Q" J
- " ①②③
0 ]8 E. Y1 \, u6 }) c - 1■■■
T4 ~% l u& e - 2■■■
7 Q3 E* c4 _0 O$ P- k - 3■■■
& J0 L3 \3 l, H* F6 K) r - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
5 _" t3 ^( M: o - ) j2 e+ Z. o8 F! {
- ;;; 棋盘* ^+ f/ I; e& M& Z0 b& b% Z2 t
- (defconst *wechat-5x5-white-chess* 122888 Y8 ^0 g' B9 a! e) F
- " ")
7 o' t m& R8 o1 r
4 m a* Z) v. m, [. f8 s- M- (defconst *wechat-5x5-black-chess* 9632
5 q7 S" i- s+ l3 w - "■")
9 ]9 y2 g& @* j# b% _. i1 t' T
r" V) f" W; ~) a" M G- (defmacro with-board (&rest body)' E1 p& b" Y! X( @2 `
- `(with-temp-buffer7 y. {6 O* L, B$ N' M. t
- (unwind-protect
6 d& j5 u; ?0 I$ {6 z - (progn
; v. B: i: ]3 k; r% z - (if (session "board")
: Z1 Z9 E, \) S$ A0 f - (insert (session "board"))), h! d" I/ ]% g& {" f% _
- ,@body)" Q4 B- D5 Q! q: A$ T7 N4 p
- (session "board" (buffer-string)))))
- {6 R% L, K( G7 T( I - ) s1 E7 T2 f1 `+ G; p5 T0 h% G
- (defun board-init (size)
0 `* n+ ^& N3 ~7 R1 P: O( e, A - (session "size" size)/ `& C+ r% D+ O- f4 k$ {
- (session "step" 0)/ K( `/ z7 }+ `) I5 ^3 K3 R
- (erase-buffer): B* n {" [& @& g$ b3 v4 t
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))+ O, X0 u% f! a1 ]7 {
- (dotimes (row size)
# } V- A8 e I8 B0 b) x# C - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))- f8 S& y* G _' d
! R! X- g% q. R- (defun board-contains-p (y x)8 V/ r' m) B" `6 L
- (let ((size (session "size")))7 R; f! g9 J: ^* z
- (and (<= 1 y) (<= y size)
, e( r3 {/ f2 ~3 g - (<= 1 x) (<= x size)))) @4 X3 b" P2 H3 k
- , `9 y% {" p) F: a
- (defun board-toggle (y x)* N: Y: B% o- k3 C4 j) w: @
- (when (board-contains-p y x)
" A! a, H$ g2 k4 x - (goto-line (1+ y))
- e) z, B/ ]/ d9 P" X# j9 b$ m - (beginning-of-line)* d1 c1 q0 o; l3 J0 W
- (forward-char x)7 u5 v2 C5 E4 C# m% W' t& G
- (insert (if (= *wechat-5x5-white-chess* (following-char))
' Z: r' q* \: h: T - *wechat-5x5-black-chess*
& ]7 Q3 y; H" a - *wechat-5x5-white-chess*))
" x! B: W9 ^; `: I A9 y - (delete-char 1)))6 T3 {( C& E: [8 Y( W; i) @0 y3 P
4 m1 }/ B' }- }1 h* _( o- (defun board-put (y x)0 c$ }2 i$ ?2 a1 s" e+ ^
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
7 x% y; d; F7 n% w - (board-toggle (+ y (first dir))) t1 y$ C/ I& O3 i4 m
- (+ x (second dir)))))* P, N# _& K% i9 P* _* r
- + E) }( a4 [4 ^4 u6 k; s
- (defun game-over-p ()
" c' P0 z4 B; U/ M3 [# N - (beginning-of-buffer)* @2 N- o! I# ?# b) X1 G1 M
- (not (search-forward (string *wechat-5x5-white-chess*) nil t)))! w. `5 V" k8 a; q' w/ _
$ m- O* \# r" h- X. y4 i. `- (defun board-show ()$ f" |0 d0 Y+ W& E. V
- (with-board
4 v7 P0 }7 L' o0 p) _; T/ T - (concat (buffer-string)5 k a3 w5 F/ X! b, y; {) n4 L
- (if (game-over-p)" [% d: ]+ u9 h1 G
- (format "共%d步,输入任意内容返回大厅" (session "step"))% u. s; s, M* X. @2 u+ B
- (format "第%d步" (1+ (session "step")))))))
9 z* O. o0 J- C2 i6 w - $ {# X C4 T. g
- (defun board-position-parse (cmd): v# ?0 r0 s, [1 H% v3 Y1 y
- (if (= (length cmd) 2)
8 H$ G/ T2 C0 u! n! p - (list (string-to-int (substring cmd 0 1)); y7 U- N9 J, K, [7 y4 X8 Z8 Z4 A
- (string-to-int (substring cmd 1 2)))
) @0 O: Y+ p7 v. [1 P( n7 c- I - '(0 0)))- [2 U6 H; b0 q. y6 h2 d; V N* c
- 9 N t9 }6 g' i! D6 W7 P( e
- ;;; 游戏房间
7 m4 u9 o7 W* Q5 n( u3 f - (defun game-room-init (cmd)( q( }" P# F/ `8 @$ l
- (let* ((middle (string-to-int cmd))4 m8 t4 W5 _5 U1 r: X. L. i0 \- F1 k
- (size (1- (* 2 middle))))+ y% C% a6 N4 N- b
- (with-board7 |. _$ c" ]2 K6 }# [% i
- (board-init size)
. E( o3 w9 B/ a% c5 x; t4 q - (board-put middle middle)))
7 `( N ~/ H0 F, [( Q - 'game-room)
. k; w" |' L6 P, ~, G- b( M" @
7 n6 q( s; M4 B" H. q! l; d6 t- (def-room game-room3 S7 E% L! v7 u0 p
- #'board-show
0 t3 \. ?3 K. r7 {- Q - (t (lambda (cmd)" E9 `* d( `: T K
- (with-board1 y {2 i4 K7 ]1 E1 S8 Q
- (if (game-over-p)$ S _' i* t; q0 f% M( C5 b6 d
- 'living-room
! f: z6 B& V7 h. Z- X - (destructuring-bind (y x) (board-position-parse cmd)5 O9 ]/ x1 l J5 X* J- D: O
- (when (board-contains-p y x)1 e. v A2 }' D y
- (board-toggle y x)( ?8 v( n9 W6 s) p: ~( G" M* O( S8 h
- (session "step" (1+ (session "step"))))! ?2 d1 H5 h ^& D
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|