wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。+ L' M0 Q# o: Y8 E
借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- 5 k7 V9 F# }+ B$ H2 K
- <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;">;; 定义新的游戏地图; E% }# f3 ]7 M7 j
- (def-map "/game/5x5.el" ; 对外开放的URL
9 \1 }; s, Z( g, f" \4 o9 M1 Z - 'tutorial-room-0) ; 默认的入口+ K8 M9 \; J" d/ A9 R: }
+ n) D" T/ V- M6 z" a: n: ]' l- ;;; 游戏大厅
, d# ^+ t% q7 O" m& V( |; g - (def-room living-room6 S; Z, Z; _' S
- ;; 进入该房间后的提示语
0 K+ G! r, G5 f8 H4 Z: r0 b% j( x0 I - "1. 教程
& h) h x, ?$ Z5 r, \& t - 2. 入门(3x3)
% b, g( ]: g) z: S. ]# B" n - 3. 初级(5x5)
0 i) ]: V/ F1 S/ y" C - 4. 中级(7x7)! B. h" P+ D8 p W; b- x
- 5. 高级(9x9). ]* h' n( f8 g# V$ V
- 0. 关于作者 c! w5 e1 u$ g! R
- 请选择1-5开始新游戏:"
4 m- S! w. F; N" _8 J - ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名9 }* D; |! b. m# q5 H2 R
- ("1" tutorial-room-0)
( C7 ?0 n/ t/ ^+ y6 E# `" \ - ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配
- H* i7 Z; D" E8 c! Z, E - ; 相应的返回也可以为函数,动态返回房间名
" |; v" I0 o' I! i6 a) o2 [/ o - (t living-room)) ; 如果条件为t,为永真$ f$ P2 r; p/ Z! l
: I0 s8 ]( X( Z) ^3 k; ^8 g. U- p3 f- ;;; 作者信息
+ E J: C- {4 n, \9 R - (def-room about-room( ]7 u9 s& n6 K( r7 K5 J
- "作者:redraiment
# s! j6 @& }1 u4 N2 F - 微博:http://weibo.com/redraiment) u8 E; ]* y& v! a, _0 S9 i
- 有任何建议,欢迎在微博或微信上联系redraiment。
. @, K6 d' r a6 z6 u: p) a - 请输入任意数字返回游戏大厅。"4 v: _% [2 R1 C
- (t living-room))2 E; a/ {) W6 h" w: o1 \7 p
2 s. J" B# q7 T' c- f1 @- ;;; 教程
; R/ p3 z2 q1 `/ n& Q - (defvar *wechat-5x5-tutorial-rooms* 0
( j' j0 U& o3 S" {. V - "The number of tutorial rooms")# x( U0 H5 g+ w* I
- . n5 L0 O9 U" j4 z; Z3 Y$ ~
- ;;; 简化教程的定义
% ]* G. q" ]' Q* C; I0 j( A - (defun string-last-line (content)
5 ^; S/ b5 E: n0 j7 N9 F - "多行内容组成的字符串中的最后一行"" s% r2 g( e: B
- (with-temp-buffer' R1 q; y" r8 M* d' n) N7 I8 L5 D# A
- (insert content)
Y7 W8 }3 c# N* _' ] f! f& c; C6 q - (buffer-substring (line-beginning-position)
5 n' V* _# d) k( V' Q( t - (point-max))))+ W2 s; ?, j2 I2 \" V
- 6 }' H1 }/ `* \) p! S2 n
- (defun def-tutorial-room (prompt)
* i0 p* @, }3 n - "根据提示语自动生成教程房间。
) x2 G( r7 }0 x- d
6 W; ^2 P& T7 w( ~7 q( Q- 1. 提取最后一行作为问题;
- i9 Y& X8 y; |( w- [1 O8 |2 ~ - 2. 分析问题,获取期望用户输入的内容;3 h: ?8 @3 P8 |* C. d0 u9 y# b
- 3. 定义教程房间和重复提问房间。"
1 O7 c* d2 g3 J - (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
8 u1 s/ i; f" ~, Q$ m; g' }% b - (repeat-room (concat room-name "-repeat")). z" k& G# U+ u: s
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))9 B6 B- ]* `* b& S4 b3 A+ Q7 ~
- (question (string-last-line prompt))% {$ n: x6 T$ S8 c p$ f* X6 h7 U( F# U
- (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)9 M/ G, \: n0 H0 Y. d
- (match-string 1 question)))2 P5 N0 ]' m! a+ X/ k5 B; S
- (doors (if except
6 V; U# _" `+ h& C$ c - `((,except ,(intern next-room))
' B8 P9 B, ~6 Q/ ^. m - ("q" living-room)
3 P+ _7 P* o" \; u2 z - ("Q" living-room)4 {# ]2 w" i2 n- h) l3 J3 c( q
- (t ,(intern repeat-room)))/ }8 j% g7 j0 g& z
- '((t living-room)))))" j( o( V" a: A) f V
- (def-room-raw (intern room-name) prompt doors)
' _/ W% N. R! O6 ?( R# h6 y - (def-room-raw (intern repeat-room) question doors)))( u7 G- s5 H/ ?) F1 c! C+ G
) c7 f' |( Q7 r0 G7 Y4 y5 W- (defun def-tutorial (&rest prompts)
2 m" B/ q* f, Q. h0 s4 n - "批量生成教程房间。" O) C+ }2 o7 _4 U4 |+ H0 K, h
- (dolist (prompt prompts)
) v; X' Q; a/ T: |/ e9 m- t - (def-tutorial-room prompt)))
6 r- n/ @7 o9 c/ b d- v
6 X4 e: \) L9 C) O' |- p/ B- }- (def-tutorial
- M( c" ?( C$ I4 h7 x, [2 h - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。
. Z9 b0 \9 @$ E- X" ^ - 1. 教程6 s% ]0 O1 } H" _* @8 i
- 2. 入门(3x3)
5 E' t' [1 N. E" ^ - 3. 初级(5x5)8 |& `+ s* u) {2 b2 u& Y; Y
- 4. 中级(7x7)" _) ?5 U2 A+ F. P! K }) y- i
- 5. 高级(9x9)$ Y+ ~5 M7 u7 v) Y+ ^' @
- 0. 关于作者: Q8 N2 F0 W. I" N1 {1 i& Z
- 请选择1-5开始新游戏:
+ O# C7 p2 _6 o V- y {1 y& g - 您现在正在游戏大厅里。+ w& z! \- d) h8 O$ Q
- 请输入“2”进入入门级房间"
+ `" w2 x5 E( B& _ - " ①②③
0 v8 f9 B5 R, i3 j0 P - 1 ■ / v( J" g% I* d
- 2■■■
& N' d' Q1 c* [- L0 C- ^7 K/ s - 3 ■
3 o/ C( l+ J$ Z1 ~2 j9 n I - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
, k4 K) U' J) N$ Q+ ? - 请输入“22”来关闭第2行第2列的窗户。"8 m; R+ O% ] l( V! o9 x
- " ①②③
& S* K+ l$ E2 @3 a3 e0 R - 1
' O$ A6 s4 a% Q( f - 2 : Q( S# ?$ k0 R1 b+ c
- 3 . _% o. d0 O( Z' E8 s8 i3 ]4 _
- 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。
( c6 w1 m0 J4 T3 J - 请输入“11”,试着开启左上角的窗户。"
6 {( _0 Q- k* N - " ①②③
: j. E- e2 y' R - 1■■
# v0 E2 v* ~. |3 a - 2■
1 Y6 @: j2 X5 r- _2 r k - 3 " u8 ]9 k8 e }3 h% Q$ [( q h5 x
- 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。( D+ F+ @. {! o2 Y0 d0 c3 q
- 请输入“13”开启右上角的窗户。"
! m5 v' X: q' @ - " ①②③
, I3 | B6 ~9 f+ p# e2 Q6 I% A0 @ - 1■ ■
" B3 x! l/ |& a' M" _4 P" e+ o - 2■ ■ ^5 ]) |2 A# J; k
- 3
/ g% U1 i2 ~6 N9 n4 g1 Q: `8 ^ - 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。1 |9 q/ y' O7 v- ^
- 请输入“31”开启左下角的窗户。"6 g4 ?$ Q4 L% o! X, ~
- " ①②③
2 u7 R1 U, t0 n. w# g: m4 l& h - 1■ ■
3 s. I! ^9 K$ b- p& v; E - 2 ■
* i' U O3 ]# h - 3■■ 1 W. Q8 c1 X ~+ W1 _5 h8 s
- 此时,总共有5扇窗户被开启了。
' L) X( k# K% Z) A/ [ - 请输入“33”开启右下角的窗户。"
! V! M$ f" D& Y8 R# ^ - " ①②③
' h, b2 Z' T5 `0 w& Z - 1■ ■2 g; j* v8 }. N
- 2 + G* M& o7 Z F1 J* ]1 r/ g
- 3■ ■4 D) Q% \2 k# q5 B" S
- 现在,只有四个角落的窗户被打开。. @! |' x; W, F) `
- 请输入“22”完成最后一击!"6 F6 U" j5 G6 h+ A9 V7 t8 H
- " ①②③
) r- |/ d j" u, x& v - 1■■■' Q# q* N2 y, u3 \
- 2■■■; N' S0 B+ k! w, U
- 3■■■
; q/ D6 c: D6 U' C1 Y) i( e, Q - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!") H' J. W/ ^. [' R+ s
4 B& P Y# v/ Y0 u' r. Q& ~- ;;; 棋盘, y; ~7 @/ G8 J5 q) @
- (defconst *wechat-5x5-white-chess* 122887 q% G4 W' ] u3 w" A
- " ")
/ {( d$ x: N' l N - 8 n, B6 G9 Z- G2 G" q
- (defconst *wechat-5x5-black-chess* 9632. D7 F& I5 n* x; S" T5 f- V
- "■")
7 @# t# {* b! e( H0 r; k1 c- c - & {# f% q: S0 S8 Y" {) P1 C
- (defmacro with-board (&rest body)
$ o/ D* J3 v/ b0 z" W( K. h, n - `(with-temp-buffer; Q% \1 l( {+ `
- (unwind-protect# R8 U- Q5 d" l
- (progn- ^! H+ m) l, z l$ i" ]
- (if (session "board")8 C* t% Q7 t+ g# @: t1 w2 z+ {$ r
- (insert (session "board")))
# w6 f3 I+ f$ M# Q' g9 B - ,@body)
. V1 I4 I0 ^6 a! b" X - (session "board" (buffer-string)))))
+ V7 |: U: s3 U% H9 v, K$ G5 d
4 M- c' B( H d) _. \7 o- (defun board-init (size)
/ I) U1 S3 ?8 K. T1 k0 A - (session "size" size)# k0 U6 c6 ]: D1 \# J- l$ v$ U
- (session "step" 0)
' r% ]. E% ~" i: ~ - (erase-buffer)& L) ~- E( P Z
- (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨"))' ^/ O E7 X3 d1 q0 p
- (dotimes (row size)) K0 B) |0 m1 J! |9 x/ ?8 ~6 a
- (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
6 d) \7 B# T) z0 T
% d; _( N$ j! B7 F t/ `+ G' H- (defun board-contains-p (y x)' y7 t! D$ `9 E) K0 p
- (let ((size (session "size")))0 ~+ y L8 Q) U3 |: ~' K/ K
- (and (<= 1 y) (<= y size)3 U1 {8 p& ^6 t6 y4 |9 E
- (<= 1 x) (<= x size))))
, I% E7 a ~3 l* ^& N
; W5 W7 c- ]; ~: z9 z- (defun board-toggle (y x)" ]5 C3 X4 E! N9 L* } |
- (when (board-contains-p y x), U- [' w) n' {) T+ ]8 \$ ?
- (goto-line (1+ y))* L# [# A5 a! [4 }6 }0 |2 {: r
- (beginning-of-line)5 G* z5 |+ K! l A0 E9 ?
- (forward-char x)' J4 k6 h3 M0 E# \, S& L$ ^
- (insert (if (= *wechat-5x5-white-chess* (following-char))4 v3 r, J6 j; |; p
- *wechat-5x5-black-chess*
) @6 [# D# @; g( h% Q - *wechat-5x5-white-chess*))3 Y, e( W, K h* @8 B
- (delete-char 1))); k& Q7 q/ a/ i+ B' R
- : N2 t' A: u: g6 p, m
- (defun board-put (y x)' C- j+ m5 l2 t7 P/ [7 n/ ?) m
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))
7 E D/ f5 {# t - (board-toggle (+ y (first dir))
8 @2 ?% n+ f) P7 m - (+ x (second dir)))))) D! N c5 M8 [8 a# P
, I& T( J5 t7 \2 W8 p- (defun game-over-p ()
+ G0 o* r5 q- q: X - (beginning-of-buffer)
5 T" ~" o) Y1 M; n% n, v - (not (search-forward (string *wechat-5x5-white-chess*) nil t)))8 H- r/ c( X2 y" y) G
) V4 j( e+ e9 L7 p& W N2 O- (defun board-show ()
- P' l& _' u& w: @ - (with-board" M! m, W- p5 Y& s- {- ~) c F
- (concat (buffer-string)
O* n7 _& V1 g! Z3 m+ C5 R- f - (if (game-over-p)
W4 |- K) G7 e* f G - (format "共%d步,输入任意内容返回大厅" (session "step"))2 E' Z# G S1 z+ X, ]; E
- (format "第%d步" (1+ (session "step")))))))
; i5 {" Q8 j, p Q5 \! [
* c' B; ]* E% q! Q& ?- (defun board-position-parse (cmd)
8 i8 Q( N: M( A - (if (= (length cmd) 2)
" N; }* f1 e* F! p - (list (string-to-int (substring cmd 0 1))
* Y9 Q0 P6 O" W- n' t# Y7 {6 X7 X1 t - (string-to-int (substring cmd 1 2)))) m X% d* x8 y+ e! G+ _4 u# @9 K& M0 B9 S
- '(0 0)))
0 e5 k0 E3 j/ @& ?
+ x% E) _3 u# w- ;;; 游戏房间/ N& g; k4 M2 S; X( o
- (defun game-room-init (cmd)) t- l- C8 Y& k- b! a! k3 W( ]
- (let* ((middle (string-to-int cmd))2 `0 ^% m! `0 j5 ~8 B
- (size (1- (* 2 middle))))
' }; ~# j: E1 u3 \. D% f - (with-board; C/ ]6 |; S8 o) F7 {4 r
- (board-init size)
9 x% |; Q) W* T6 J5 x+ t - (board-put middle middle)))
3 b4 w' p/ ]" d7 Q& i1 G" j; A9 j: w2 q( Q - 'game-room)+ i4 Z7 d* m a* t2 N$ m ~, S5 Q
- ! N2 N, x& a+ ~$ G
- (def-room game-room
2 `" \% \7 n9 [. v; H# F" \1 O& l - #'board-show# O% l8 @- j9 Q
- (t (lambda (cmd)
3 V. p; j* I# o3 b7 d3 d. N( ^5 ] - (with-board
) a7 }3 E0 Z( q0 Y4 K - (if (game-over-p)
2 R! _& H7 T# O$ u - 'living-room
; a6 {3 K' D7 |; o3 A& Y# ~! Y$ x) r8 W - (destructuring-bind (y x) (board-position-parse cmd)( [# T: C3 D! v, Y6 A
- (when (board-contains-p y x)
" d% @3 p2 C" s6 N4 I - (board-toggle y x)
5 w3 m) u2 S5 ]- |0 w: s - (session "step" (1+ (session "step"))))
" Z @" J9 ~+ u6 g: C2 M* {* ]6 B - 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|