wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。0 P; m+ ^' m, F5 E, u" M( B. [" D
借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。
$ K0 T7 @4 r! G- W1 q, \* J- <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 H, ]- ^7 {, I - (def-map "/game/5x5.el" ; 对外开放的URL e- o, x# l: f1 h% X
- 'tutorial-room-0) ; 默认的入口5 }) \" M: l: N) `1 g) N! q
- |3 L# c* D1 n! K
- ;;; 游戏大厅2 N, o* q) L6 X8 N
- (def-room living-room
; h5 @, L) y. l$ ~) W - ;; 进入该房间后的提示语
+ a Z1 T( M# T" x: r, ~0 R# k - "1. 教程
! J; E5 H: j) {- y9 J$ l - 2. 入门(3x3), E$ Q9 L. A; \, _! \* N6 T
- 3. 初级(5x5)4 Y _: R$ M# c B B$ g
- 4. 中级(7x7)& M; ]& g9 r n9 V1 a
- 5. 高级(9x9)- t q- W4 q, ?) v( e& x1 S0 Y
- 0. 关于作者
" C* K [. E) B2 ? - 请选择1-5开始新游戏:"& ]/ r0 H x/ W! Y8 m
- ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名1 j7 w- t: V! g; m4 Q8 C( X6 D
- ("1" tutorial-room-0)- H" M; u7 i( |. R
- ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配
1 M/ V- z- _! ]' @( G3 b$ Q - ; 相应的返回也可以为函数,动态返回房间名
7 c$ o9 k. V3 z1 W0 R' ~ - (t living-room)) ; 如果条件为t,为永真' Q0 M" \+ c: p! G4 l. l
6 [7 y' ~, V+ {- ;;; 作者信息
2 h+ p6 A- B8 Z - (def-room about-room$ `$ i- B8 c, d. K, g
- "作者:redraiment
' h& ~* a: I' A) m- U2 A6 j - 微博:http://weibo.com/redraiment* O+ h l: K& ?: i4 m+ q6 E+ U. N
- 有任何建议,欢迎在微博或微信上联系redraiment。
/ p# U$ `4 O" K3 i$ C - 请输入任意数字返回游戏大厅。"/ k) X" t# E6 u
- (t living-room))
* G- h5 d- Q5 G" R - 3 v" R0 Y( }+ I+ W- J
- ;;; 教程
+ P, B- Z" _4 {8 r0 C - (defvar *wechat-5x5-tutorial-rooms* 09 S! {; g+ }$ C* T+ ^+ u
- "The number of tutorial rooms")# z- Q$ \! Q& G
- # p1 {% M$ g* L9 r$ z8 l" j; h" e9 J
- ;;; 简化教程的定义
# q2 b# |* F" `& ?+ h3 U( ^ - (defun string-last-line (content)
& ~# q/ g5 A5 H- y3 V, C+ P* `0 y4 a - "多行内容组成的字符串中的最后一行"
5 L8 `( M u5 F. k4 |7 _ - (with-temp-buffer
E2 [& k s Q7 s8 y( y - (insert content)
G+ r0 G1 ]$ D3 l2 `' i, o4 w" c - (buffer-substring (line-beginning-position)& t. ^* ^+ t7 e. L6 ]4 T6 g5 w
- (point-max))))- U3 F T* b1 s8 B' ?) R2 ] p
/ ^" D$ @. A9 I) v" w6 y- y- x- (defun def-tutorial-room (prompt)# n; [3 Y5 `8 X. y& o, O+ c, `
- "根据提示语自动生成教程房间。
# y5 b6 |) a! U! _; l9 H& a: G
+ X" O& U7 G4 T N- 1. 提取最后一行作为问题;6 S# L: c6 b2 ^6 f7 D+ k7 t
- 2. 分析问题,获取期望用户输入的内容;
9 s. u3 m3 y: j5 ?1 {1 N - 3. 定义教程房间和重复提问房间。"
1 p, A6 I* a9 q T( o - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
1 a+ u% c, ^# Q9 @! b - (repeat-room (concat room-name "-repeat"))
' n& U3 u: }5 Q4 L/ X5 M( O - (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))3 X1 C2 w9 Z5 J4 j
- (question (string-last-line prompt))
) `9 a' p# z* }/ M/ r; s7 ] - (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)
* r( q. ^; ?1 z7 M& F. R - (match-string 1 question)))) S- `* ~% M. e
- (doors (if except7 U1 E- A' I G: N1 Z- @3 L$ N
- `((,except ,(intern next-room))
9 k: Y! H: t) {# S - ("q" living-room)
% r6 {/ `8 r4 z: H! }5 h; P - ("Q" living-room)
# P9 i8 P, h# w1 f& Q# h - (t ,(intern repeat-room)))& g, K. K7 {. b u
- '((t living-room)))))* T8 b+ ?# [' l4 v
- (def-room-raw (intern room-name) prompt doors)
$ E& t6 y( E( c; l/ K - (def-room-raw (intern repeat-room) question doors)))
; S6 A. `* D- o# W) j/ z - 8 Y- T0 L+ O p: B6 N* _7 O
- (defun def-tutorial (&rest prompts)
3 Z* ~7 r6 S" F8 O* |8 ` - "批量生成教程房间。": W; M& w! ~5 H: L: d s
- (dolist (prompt prompts)
3 ?/ L/ H' K8 T1 s3 [ - (def-tutorial-room prompt)))
F0 l4 t9 t8 L+ z5 P# x
+ l; \# @% p9 `- }5 `- (def-tutorial
$ S4 C5 u2 z: {# \# i$ a, ~4 z( r - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。% S2 m8 \* @0 A6 T, O2 p3 b$ g& `
- 1. 教程 z! d3 a# W+ s2 O
- 2. 入门(3x3)
t8 J: ^7 p/ P4 Q& ~! U7 m - 3. 初级(5x5)
. ]# y0 ~) ^! y4 }0 G - 4. 中级(7x7)
2 j! O6 t9 U% P! ~7 m - 5. 高级(9x9)
# ~2 R5 i4 ^7 n) y - 0. 关于作者, ]* t' @! z# I9 @
- 请选择1-5开始新游戏:
- }% t( Y% g' n& v - 您现在正在游戏大厅里。8 U2 D. ~+ F# n8 I& R; @5 ?$ e
- 请输入“2”进入入门级房间"& o' S! P6 i* ]9 W* v- V( M4 [6 z
- " ①②③
9 ~5 }- \: \% m3 m4 s: X - 1 ■ % d2 f& Z* u4 A; Q# ]: L0 n2 y
- 2■■■1 ?2 u' q/ Y, I: W( t6 o3 g: r6 W
- 3 ■
0 z4 ^5 O1 _9 `7 m! s - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
7 _5 A4 A0 _. ` - 请输入“22”来关闭第2行第2列的窗户。"
: c4 @( Z% D/ |; m$ m& ^) f ? - " ①②③
5 O. C* f: Q3 o) x/ a! F - 1
7 s3 o5 M/ K `5 m4 l. t. t - 2
5 \1 M" o) S$ m$ S - 3 8 n& e4 i4 | p8 }3 y2 X$ U( T
- 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。/ H6 l' y9 D- P0 u l% o
- 请输入“11”,试着开启左上角的窗户。"
% g8 F6 J) R- `5 c' F* B# q - " ①②③4 f2 W; w: y$ H9 S& t' E: G
- 1■■ + I# K# [4 |3 \. r& h
- 2■
' j0 g' {. d& e! b( a9 V- a - 3
+ L" w; @7 C# `- I1 k. { - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。
3 p; m* \$ B! |1 P0 i/ r1 B - 请输入“13”开启右上角的窗户。"
, n4 o0 `. b S# a6 l6 ~ - " ①②③% V# F8 r3 L6 w' o A4 D, y
- 1■ ■8 K0 G X# f0 O. M% G T4 R8 S
- 2■ ■; `% r6 {, W+ g1 [, t# X
- 3
$ ^, i7 {' k0 j9 K8 a - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。
6 g. z% Y$ K- O2 j; N - 请输入“31”开启左下角的窗户。"' q5 a: O) a" w E! ]! w* i
- " ①②③
- F: n2 ^% [# R* \ - 1■ ■
* _% {# V2 j" ~# i) Y' F - 2 ■
8 i, {# G: K+ T- q - 3■■
8 t* G& L* b* X1 {! I6 ^. E - 此时,总共有5扇窗户被开启了。
k1 T5 Z, ]) m+ b$ Q - 请输入“33”开启右下角的窗户。": s8 N6 t9 N& _( g8 K" z: e5 {
- " ①②③
* u6 E9 Y- F) E+ O; x+ D) {: q7 o - 1■ ■
0 Y! o v# M" q+ i( [/ ^ - 2
* e7 W: y8 \# F* f3 C - 3■ ■
}, P) W& S9 C! m" ^# ]! k - 现在,只有四个角落的窗户被打开。
6 \( T6 b0 h9 B9 O( f - 请输入“22”完成最后一击!"1 B% ~; \$ Q. i$ ]4 U
- " ①②③" M% s& v7 F2 x/ s
- 1■■■, _& v2 D6 V# C$ M' I
- 2■■■7 E& y7 G8 F, w2 z: Z) L" z
- 3■■■
1 Q) W" \8 t3 U! x- f) l. B - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")
- F* @6 U5 y8 r2 a - " x' Z( K) l) l+ \
- ;;; 棋盘" K$ C! q9 K5 h, l
- (defconst *wechat-5x5-white-chess* 12288
8 e4 I7 ^+ s2 l - " "). ?" j1 O- x K- n
- 3 d1 \1 |6 C) k' T- |; O: ~
- (defconst *wechat-5x5-black-chess* 9632
+ E, Y* S" s# v# w* y1 R2 p6 r - "■")
) u( g% |$ X, i! ]1 m" h0 S - $ _) g8 u4 \7 K/ l
- (defmacro with-board (&rest body)& R; A! s% I. c8 A$ @1 J
- `(with-temp-buffer
0 a8 _7 l6 K( t9 a2 t* r+ s% E - (unwind-protect' ^7 a$ q! x: b( }/ ]
- (progn! @9 M6 t# B% @7 H0 P
- (if (session "board")
$ c2 [: o' U8 ]% y1 M: F - (insert (session "board")))
6 o, m) r$ {0 H8 W - ,@body)
3 o4 @4 Q* ^1 N& e - (session "board" (buffer-string)))))
2 X: R' v( ?. s8 X2 Z: O
`! h7 T* y* Y& @+ y0 ]- (defun board-init (size)& m% `) R/ m7 h( d. ~
- (session "size" size)- z3 K [1 j$ G# D
- (session "step" 0)$ C" G6 m7 y, j m3 c. S0 H- s
- (erase-buffer)
' M4 |& b9 Q1 L - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))" k2 M, H3 T1 N: _* `1 J
- (dotimes (row size)
' Z5 C3 `4 D* u$ s& R) H - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
% F0 W! D/ V$ d% r& ? - + a; ~, v1 ?1 O) L& M
- (defun board-contains-p (y x)
l) ~" G) g/ s; e) p [5 J7 E$ U$ ` - (let ((size (session "size")))! Q" Z$ @. L4 T0 n% A& ?
- (and (<= 1 y) (<= y size)
8 D& R6 k. [/ ?5 ?) E0 E - (<= 1 x) (<= x size))))
, \4 m" J3 I! T
9 h3 [" X$ y% F9 ^( s$ p- (defun board-toggle (y x)
, ~- V q" `( m8 c, ^ - (when (board-contains-p y x)" H6 }5 g, ]8 i
- (goto-line (1+ y))/ b1 @+ Q3 c8 ?0 w) _
- (beginning-of-line)
1 P& ~# F/ g6 M$ C8 ? - (forward-char x)
( E& u* i+ [" e. m4 O - (insert (if (= *wechat-5x5-white-chess* (following-char))* f1 i, n2 j5 D [2 C
- *wechat-5x5-black-chess*
( E" X M. Q. U4 v9 @ - *wechat-5x5-white-chess*))
& k' e2 S5 V1 w* J - (delete-char 1)))5 \7 z5 y7 u9 f1 Q0 {
; s3 {' u; J/ G. l2 D Q- (defun board-put (y x)* d6 A) h5 R$ ?" Q
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))# U+ n3 x0 e2 E
- (board-toggle (+ y (first dir))
0 `' \% C; {2 J6 B' s) @/ h - (+ x (second dir)))))* \- r% B1 L; b
- $ O* ` a. F7 R. K4 S8 ]' e) c" T
- (defun game-over-p ()5 w/ ]5 h; g/ z' T. A4 A+ ?* s S R
- (beginning-of-buffer)
m* o: a" N' D: B - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
: o. w7 x9 n# `% P, h( \ - 7 I( S; j2 z# v. Y5 t9 j
- (defun board-show ()' Q8 i6 X9 e3 {7 F
- (with-board
! x1 O# r0 s* u - (concat (buffer-string)2 r* Y2 @7 ]4 B' A2 O0 q
- (if (game-over-p): p& ?! F# ^( G" ^! e7 Y. V- o4 ?' x
- (format "共%d步,输入任意内容返回大厅" (session "step"))
9 x' c. ~" k% m2 U1 Q7 S- \, E: o - (format "第%d步" (1+ (session "step")))))))+ x* |$ F- t( L* R7 a
( \% P" B. Q7 h, t- m: c- (defun board-position-parse (cmd)& z) T7 R5 G# X- b( o1 \
- (if (= (length cmd) 2)% l# @: T/ y' u1 `
- (list (string-to-int (substring cmd 0 1)): w3 W/ k( P6 j& M% O! Z
- (string-to-int (substring cmd 1 2)))
1 ^( }/ m. b0 p' ~ - '(0 0)))
) o( b0 w: S* `5 o- m9 M - , X v6 f& n& a# m6 y
- ;;; 游戏房间5 r4 K7 U8 p, V# B
- (defun game-room-init (cmd)% d" E) r* J9 d. G1 O! O
- (let* ((middle (string-to-int cmd))$ ?4 A1 @) C* O: q ^& _
- (size (1- (* 2 middle))))
. o. G6 p' m* P - (with-board2 h+ J& e: ? u/ \6 [1 |5 N
- (board-init size)
1 M0 Z* S# M& R" k" p# h1 H6 W - (board-put middle middle)))
7 G' _& N1 I4 X. D( w" C: [" B" V - 'game-room)5 z3 x. P; E$ k. K6 R7 R9 ?( \
- # ^5 q0 V) y8 y$ i' H
- (def-room game-room& b$ L+ U2 I2 h* C2 ~
- #'board-show* v. K+ e& \( ] V9 a+ n; s
- (t (lambda (cmd)
# @' V* E: {( Q( t7 F# r; c5 Q5 x - (with-board( Q/ j2 m; L- g# d0 X2 z
- (if (game-over-p)
; R1 k) z" _. P _, j% s - 'living-room
$ u+ K, r! ~' k6 s - (destructuring-bind (y x) (board-position-parse cmd)
2 A. D! ]& G6 z: B k5 g* { - (when (board-contains-p y x)8 X( U2 Q7 o# M" Y1 u' q. H
- (board-toggle y x)# N: ]; b }$ N7 G' r& |
- (session "step" (1+ (session "step"))))$ K+ S+ L5 K/ J3 k; c' |5 v
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|