wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
5 A1 K: D8 E( ^. I- L& Z3 G# H4 F借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。
) f3 t. x9 v7 e: `. p- <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;">;; 定义新的游戏地图3 ~* w8 ]( {' v
- (def-map "/game/5x5.el" ; 对外开放的URL
) F9 F: |/ N" M- A' P& `8 G - 'tutorial-room-0) ; 默认的入口
: v7 a0 c9 @7 d) ] - # c6 N" F+ k W6 H
- ;;; 游戏大厅- I! r7 W; I7 ~' H( c; [3 N
- (def-room living-room* V# b' v/ j+ j$ o6 K c8 h
- ;; 进入该房间后的提示语 ~! k& m6 D& G
- "1. 教程! G( G9 Y/ R' l7 n) s, s
- 2. 入门(3x3)
/ I8 H; A! ~ u$ B7 M6 @ - 3. 初级(5x5)
; G8 C9 K5 ?. ]9 [8 ?$ O - 4. 中级(7x7)
; i0 |: ]# n0 Q( k; e$ r - 5. 高级(9x9)" s: H! d! b" G
- 0. 关于作者# g) `' I; E' f$ [( X. W: [
- 请选择1-5开始新游戏:"+ `) X- e6 z! C* o" y' l0 I" b9 |
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名' U4 f! b# [2 j" I7 x- g5 Q
- ("1" tutorial-room-0)1 y3 f3 c) Q% d. f! d3 Y4 L. t
- ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配4 |2 n1 m' G* W& W8 r
- ; 相应的返回也可以为函数,动态返回房间名
; ^7 @8 U8 B# F+ q. M/ t - (t living-room)) ; 如果条件为t,为永真# i% \* G7 c: Z
- 7 H* |- a2 B7 x0 T
- ;;; 作者信息3 c6 G# U+ v7 C# g3 x V: Y! V
- (def-room about-room
( S; w. v+ d; J" r( L - "作者:redraiment. L8 B; r% e# q( b6 h
- 微博:http://weibo.com/redraiment% z8 r- w. d9 o3 Y9 l
- 有任何建议,欢迎在微博或微信上联系redraiment。
2 X8 ~1 b; E$ y' R1 \' H - 请输入任意数字返回游戏大厅。"
) q( H; a5 N$ e2 D - (t living-room))0 o( Q! [$ a- c" e' T8 @
- $ K* N$ G: t: F T0 H
- ;;; 教程
1 N' z- h( Z2 O. e2 Y3 ] - (defvar *wechat-5x5-tutorial-rooms* 0% s. z0 q0 I8 D- w
- "The number of tutorial rooms")+ ?, }/ H0 S6 z5 A2 @& b2 c
- , A/ ~- H. W) y! e
- ;;; 简化教程的定义
5 V# r3 z: F, \ - (defun string-last-line (content)
/ J/ m$ K! i. \( e" h1 m - "多行内容组成的字符串中的最后一行"& y5 p$ ]1 R. c! C$ C+ Q2 u8 H6 [2 t% ]
- (with-temp-buffer
8 A/ s& _7 c6 C8 `5 _& |2 k - (insert content) k, x3 ?6 {, z
- (buffer-substring (line-beginning-position)
- u" X9 {8 u- K9 j- t- N - (point-max))))
0 o! g4 Z: U6 ~4 _ - 3 L4 W( Y, O- G5 b. y- m
- (defun def-tutorial-room (prompt)( z1 @+ y# |, w, r2 l2 a
- "根据提示语自动生成教程房间。
3 s1 N0 m& J" R F! f - " O6 {$ Q& `. }2 v9 C; F" J1 U; }
- 1. 提取最后一行作为问题;
, @8 s( `; K3 ~4 x# Z8 N1 n5 W - 2. 分析问题,获取期望用户输入的内容;
& X& v% [6 N" @/ C - 3. 定义教程房间和重复提问房间。"
: m& D, t9 Z: [8 w - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))( _0 K/ h* A1 e7 {" a, B
- (repeat-room (concat room-name "-repeat")) ~+ O9 \+ S/ p; C
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))
2 x) s- L6 {; Y- b - (question (string-last-line prompt))
, l( i) S! C0 X1 r - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question); N0 l) k& K, ?. Q; h& H! A' Z% T
- (match-string 1 question)))
$ b1 [. I& j) i3 F; h( S# m/ O! H3 i - (doors (if except' f, I7 v* ?+ z, Q4 S; M6 d X
- `((,except ,(intern next-room))6 }+ s. M. z' c
- ("q" living-room)4 l1 ~ ~9 i# M8 l
- ("Q" living-room)1 ^, S3 t4 t8 z5 |$ a& t0 U5 q
- (t ,(intern repeat-room)))5 A1 q I1 J* f! q1 ]' {; Q2 C& P
- '((t living-room))))); Y Y' j+ C7 u1 O
- (def-room-raw (intern room-name) prompt doors)
; h$ ?: `! Z7 m7 K - (def-room-raw (intern repeat-room) question doors)))+ a& m- U* a) r3 @8 Y/ ^
: v1 Y f" {- U1 M# c. a }, W- (defun def-tutorial (&rest prompts)/ ^ J$ G+ D5 S( X- {
- "批量生成教程房间。"; J) a( a. s9 c0 P2 u( s) v: n
- (dolist (prompt prompts)
% O/ P! b7 @, {) D7 m) X5 Y. W! c" E - (def-tutorial-room prompt)))
5 S0 N" t: y+ o- e! y" _7 O - : U% S0 n! b! o' x% t4 g/ X
- (def-tutorial
+ ^- J7 m! @9 Q - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。) U& _- i7 r& F) n1 U0 N8 m
- 1. 教程
; Z3 h( y' V1 |9 j) _& r- n - 2. 入门(3x3)
# o! i* A3 i7 l+ f7 a - 3. 初级(5x5)0 ^- C; P/ G X" B
- 4. 中级(7x7)
7 L# b5 n2 ~1 l - 5. 高级(9x9); p/ K/ S- Y4 |7 e1 M- ]
- 0. 关于作者7 Q! d5 U" v. e
- 请选择1-5开始新游戏:- l+ Z. \- `; w& {$ {" ~8 i
- 您现在正在游戏大厅里。7 b: C7 R( R. H. [$ G; V
- 请输入“2”进入入门级房间"
# O* @+ k0 `4 N, o - " ①②③2 k/ _& k+ \1 @0 F
- 1 ■
% f' o2 C5 I, f - 2■■■! t8 e9 ~7 p+ {8 ^/ H2 t" ~
- 3 ■
1 E$ S3 \. \; b$ F+ Q - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
" {) ?. \3 v3 F( H1 i - 请输入“22”来关闭第2行第2列的窗户。"% ^' ^) t3 b2 J
- " ①②③
; N; m3 C4 r2 g, U; y4 l - 1
8 l5 G- |& u ~, p0 _! P - 2 ! V' {7 s- n+ m2 Y4 p0 @0 B: f
- 3 0 m8 h8 {8 [- U, e
- 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。) k/ O, t1 C8 A* x
- 请输入“11”,试着开启左上角的窗户。"
% W& N4 J& Q- R# ^ - " ①②③
) H* B1 |) W4 ^; [( O1 b - 1■■ # }, {: J9 s2 t# `0 |$ @
- 2■ 0 T/ K. E1 D6 j+ I
- 3 * x. A4 t6 {7 _* x$ m8 H$ P1 t" t* z
- 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。! i- \5 W2 c4 e- `, W' Q
- 请输入“13”开启右上角的窗户。"
1 B; j+ w+ ^8 R - " ①②③
3 b! e$ m2 u9 E! p1 D9 j- u - 1■ ■5 r2 W" d! W# q4 P* u. i4 B
- 2■ ■
$ P8 f) W5 D- G) Z; U - 3
6 e" V0 E+ Y, s( P' N8 w& R7 M7 l$ E7 L0 G$ U - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
# K$ ]& h* \% }7 Q - 请输入“31”开启左下角的窗户。"
- q) s) {! _ m) b, e/ b$ V7 k0 m - " ①②③
# z- h* W; `% X, b' Z$ ~ - 1■ ■* a2 t1 j8 U% P- f6 y' T3 c
- 2 ■3 e! H" u( B( }' J" E" L, N/ M4 P
- 3■■ 2 q! _" a1 O1 o* Z: e
- 此时,总共有5扇窗户被开启了。
2 X# n; @/ [& g+ m, B1 K - 请输入“33”开启右下角的窗户。"3 h0 |9 j' m0 u/ K
- " ①②③
8 K+ J7 b1 L5 g4 b - 1■ ■
4 x% f) X) y6 ]& T0 ?2 n0 N3 h - 2 - J: }( Z9 s4 y9 ?5 C4 _, ~
- 3■ ■
3 F# J4 ^% @' y+ t' b- w* { - 现在,只有四个角落的窗户被打开。" Q0 E$ f$ `8 ^+ k- K6 N( {. l1 u
- 请输入“22”完成最后一击!"
0 ~: f0 g! k( M- {( C) i - " ①②③& e% v: V9 d+ F, j- T
- 1■■■( _7 w- I+ L, X B% K. r
- 2■■■* e/ D0 q0 T( v
- 3■■■- A4 f9 |. Z+ E6 ]# ^# o" O
- 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!"), s6 |7 y2 `- t, k7 t- @6 X: ^# Y) b
$ E x6 R( W8 \* V" @3 H( D- ;;; 棋盘
% ?, ]3 X! ^; ~/ K2 N& H2 h - (defconst *wechat-5x5-white-chess* 12288
6 c2 @; F7 N& h1 [, d/ H3 `0 G - " ")
% f3 R4 V8 I# T- Y* |! A; W$ ?
0 d' ^$ W6 {* W! }. S# y1 R- (defconst *wechat-5x5-black-chess* 9632
- `) E9 I2 S. b - "■")
( T+ }* \# A; h3 S% t4 ]* m
9 p' c" a+ |0 e- (defmacro with-board (&rest body)% \& G5 U7 C4 w$ j3 ]; P' e8 r z
- `(with-temp-buffer
5 ~6 b; N3 `6 x4 O! f5 X7 p' w - (unwind-protect
! C6 d/ D' _( ?# _) c# Z( T% {, y - (progn- \. ~3 L& C- r5 u# w( ^" O
- (if (session "board")
* ~- C+ O, g( ~ - (insert (session "board")))2 C3 ~4 j$ a5 V' \$ K
- ,@body)% a4 N/ n) w% q
- (session "board" (buffer-string)))))
" s& g4 N" v. d! Q v
0 i' r2 A% R& \- y" R- (defun board-init (size)1 g, L% r3 |* S" K' U
- (session "size" size)* P0 a% t2 t# ?3 P7 n
- (session "step" 0)+ P" a7 _" e! j" F! \
- (erase-buffer)' `/ F# B- }5 n
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))& w6 f0 s2 m7 W
- (dotimes (row size)
& g6 G$ U7 e* N - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
7 u( _) C0 u- h# C1 A8 J! @4 W
; W8 }8 _- |& i/ j% P- (defun board-contains-p (y x): X8 R) H9 t! q( c' S
- (let ((size (session "size")))# W, G) K# Q" s8 I
- (and (<= 1 y) (<= y size)
# \! o" O, X, t7 ?# ?- i* _, } - (<= 1 x) (<= x size))))& j! N G1 e9 G) }3 g+ _
1 k& d4 K p- i- (defun board-toggle (y x)
" ~, e$ e, h) Z, [) N, Z% @ - (when (board-contains-p y x)( l1 N9 \9 g- M8 m' F' g
- (goto-line (1+ y))
4 w* _- }. r/ S Z. o6 n. D - (beginning-of-line)- ~+ S( p- U. m2 _* x0 G* H U
- (forward-char x); N& i; H2 h* P. a& }
- (insert (if (= *wechat-5x5-white-chess* (following-char))
0 o- g v1 L8 J; ~: ~ - *wechat-5x5-black-chess*( D/ c8 {* y$ N" R
- *wechat-5x5-white-chess*))$ ^+ c% m' ^2 g: _
- (delete-char 1)))# Q' t$ G' e* H" O! ?- ]" J
- , v1 ?6 H% V7 J3 o9 ^1 f3 f
- (defun board-put (y x), L4 I, m2 z( a# l9 R; t& a
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
5 d0 d& l2 U3 B' A0 \ - (board-toggle (+ y (first dir))( }( e* c% g. f9 u- v! g1 B
- (+ x (second dir)))))3 C4 k' ?$ q; [4 F- {
1 L" L- T' J/ I; B) ^$ z U- (defun game-over-p ()
( t+ |6 b( R0 Q9 n - (beginning-of-buffer)
) M$ D8 y6 C' q5 A8 V8 e7 Y7 h - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
3 p/ W9 a& f* z0 }) A% ?! e+ U! a' R
- p J J, l& V$ d3 q2 S- (defun board-show ()
# O: \6 C/ O% ^" ^# w0 J& R - (with-board0 W, I) g1 x9 J- d1 {
- (concat (buffer-string)
+ n% M* ?8 K ^! X1 K! p - (if (game-over-p)
1 a, h- n6 \6 B/ z - (format "共%d步,输入任意内容返回大厅" (session "step"))2 c# F8 A. O* `9 ^; T8 M: P
- (format "第%d步" (1+ (session "step"))))))); i$ C6 r5 x/ v5 b* N1 {
- . w/ y- Z+ P+ O( E- @2 V" ~9 x
- (defun board-position-parse (cmd)
+ H- m; I+ f/ a) ^" e3 m( A - (if (= (length cmd) 2)
: V' _6 s% a, W+ |" f0 L3 q' Z* l - (list (string-to-int (substring cmd 0 1))4 G# Z4 W+ i4 w2 @+ `6 l) T
- (string-to-int (substring cmd 1 2)))
2 ^# G% ?4 W' o# D0 U& P - '(0 0))): ~1 |3 L: v6 |* O. S- y9 V7 Z" x C; z
0 }& f1 Z( q8 x& f- ;;; 游戏房间0 c" M ?2 i9 b; Q K& [; |! O
- (defun game-room-init (cmd); e0 ^5 [$ q8 T, I+ T) E
- (let* ((middle (string-to-int cmd))
; D9 S {. T* o' D+ }0 k2 Z - (size (1- (* 2 middle))))
8 K a2 m; C" e5 D$ b) F7 t& g - (with-board
, }: c% T3 s% X# H - (board-init size)1 x) L9 ^6 h: B1 k" p9 H" N
- (board-put middle middle)))
- L+ Z1 `7 a1 x4 E7 X$ U - 'game-room)
7 v+ S' s& B! l8 e7 F: {
+ q& B9 C! B0 F$ N7 F+ P8 x9 L- (def-room game-room
5 {* V4 R/ d8 C4 B. _6 L" I8 W0 u - #'board-show
$ K8 t5 t- ] z7 e5 h- W6 n - (t (lambda (cmd)4 y. F& o3 }6 C3 ~8 n
- (with-board
9 Y7 H. j7 I. a, ?7 y - (if (game-over-p)
/ y/ T( }, y9 j5 C2 {( d9 V - 'living-room
5 O! N2 g ^8 N8 T2 d - (destructuring-bind (y x) (board-position-parse cmd)$ z7 T) c# B2 [3 H
- (when (board-contains-p y x)3 E, y! j$ V, n: h' e' O
- (board-toggle y x)
; a; Q) H) f# `1 g9 f1 ` - (session "step" (1+ (session "step"))))! P6 k$ f- L g/ w0 E. N- t" J: }! I
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|