wechat.el是用Emacs Lisp打造的微信公众平台开发框架,基于elnode。源码已经托管在Github上:https://github.com/redraiment/wechat.el,现已收录在oschina。
' s, b: t( D% t4 e借助Lisp语言强大的可定制性,使得开发一个公众平台的应用犹如编写一段剧本一样简单!例如本例——开窗游戏,展示了如何给予wechat.el实现自己的应用。- , Y+ |6 H5 Q1 W. L4 D3 N
- <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;">;; 定义新的游戏地图" f w, p0 r1 Z5 @! W
- (def-map "/game/5x5.el" ; 对外开放的URL
" h9 R. i+ U* R& u - 'tutorial-room-0) ; 默认的入口
9 _8 T9 F& X7 w! J - 8 B. E u& c+ E& O9 O
- ;;; 游戏大厅
% K7 e. K4 p' i - (def-room living-room
: t; L4 O( @' {; t i* A- A - ;; 进入该房间后的提示语
. j, U0 ]' h5 ]1 i* @ - "1. 教程
) e" Q6 u/ f+ z( H7 z& l+ u/ g - 2. 入门(3x3)0 t9 n1 S2 }& a# n3 _
- 3. 初级(5x5)
- g! ^; O8 |* O0 M8 R. x6 |- M - 4. 中级(7x7)' u' f$ W" ?- h
- 5. 高级(9x9)* O1 h6 ]( I' |# E; N& J9 ]8 S
- 0. 关于作者7 y7 Q3 D8 L) s
- 请选择1-5开始新游戏:"
6 @ E( B9 b$ J1 h! r7 i - ("0" about-room) ; 期望用户输入的信息以及相应的后续房间名
3 w( @7 \6 {& A# A8 i) _! z+ H - ("1" tutorial-room-0)% q" W' I; e4 t9 [) ^: Y
- ("[2-5]" game-room-init) ; 用户输入信息可用正则表达式匹配: |( \- b8 R' g; o. |" F
- ; 相应的返回也可以为函数,动态返回房间名2 n* I8 N3 C# v, y) z
- (t living-room)) ; 如果条件为t,为永真
5 Q( e+ z$ {* |5 z! [ - 4 H3 z$ F' e" `/ p2 P4 m
- ;;; 作者信息% Q3 C- W7 _( H. }% F0 f
- (def-room about-room0 B0 I5 _; S& z4 Q6 s' x0 [. d
- "作者:redraiment
/ Y" r( k3 V8 |& y, a% ~ c J - 微博:http://weibo.com/redraiment3 e2 f* h& Q" `( g" i
- 有任何建议,欢迎在微博或微信上联系redraiment。2 K! S, X4 t8 T$ k0 u) k
- 请输入任意数字返回游戏大厅。"
: P9 p( }6 d( U( H - (t living-room))6 L, R5 S% D4 v. i# Q# p* X
- 9 `0 B/ l# P, R- e* e+ s: D- k
- ;;; 教程+ J" I% @# h4 \+ b) O0 j* r# d' s% i
- (defvar *wechat-5x5-tutorial-rooms* 0
- Q0 h3 o0 O( b - "The number of tutorial rooms")1 r" K/ Q! \0 @
9 l- {, o2 O/ Q8 b3 V7 I2 j% o- ;;; 简化教程的定义9 g" o x# O; b# d! `4 m' J7 i
- (defun string-last-line (content)
2 {$ R$ I7 ~$ J; \ d) @1 ` - "多行内容组成的字符串中的最后一行") a/ f' }! b. c6 R
- (with-temp-buffer' ?1 V7 `& C! [7 F( S- T
- (insert content)
, q. f6 d+ E% f4 k. b/ q - (buffer-substring (line-beginning-position) z: w/ D8 @# s# \
- (point-max))))
+ N/ d: Q+ V2 X2 `
4 R2 q5 f6 d P9 Q/ Y& K- (defun def-tutorial-room (prompt)! G; ?, S6 o H; Z+ d# [9 b
- "根据提示语自动生成教程房间。
9 @# V$ K, E. t5 o - ; K' K& b, m% m& P( v- V$ {
- 1. 提取最后一行作为问题;
4 n+ y$ S! `1 a! G1 v. d7 Y - 2. 分析问题,获取期望用户输入的内容;
$ Z/ j3 ]( v& j9 W4 ?& @ - 3. 定义教程房间和重复提问房间。"% j/ t5 H' v3 Z- Q+ ~
- (let* ((room-name (concat "tutorial-room-" (number-to-string *wechat-5x5-tutorial-rooms*)))
7 N$ x5 _2 I: w2 d - (repeat-room (concat room-name "-repeat"))" z" w# c! _; n, }, I) F
- (next-room (concat "tutorial-room-" (number-to-string (incf *wechat-5x5-tutorial-rooms*))))2 w' F5 J" d0 e4 w9 A2 O) H
- (question (string-last-line prompt))% D+ ?5 R- g4 d7 P2 ?
- (except (if (string-match "请输入“\\([0-9a-zA-Z]+\\)”" question)
! |! I& |% w3 o& B - (match-string 1 question)))
$ S7 E2 P: m& C5 D$ ^- H - (doors (if except. G! F' j. G, j; M( U5 ?$ I
- `((,except ,(intern next-room))6 o! l- [! t4 I }7 A. {
- ("q" living-room), p1 r+ D& B) n: e: U3 l
- ("Q" living-room)3 i/ b$ P, u6 y( _) v9 `& u1 T- |
- (t ,(intern repeat-room)))
, n' |2 @4 w+ J F$ }6 n9 b f - '((t living-room)))))7 D9 b" Y0 }! @) B( J5 o
- (def-room-raw (intern room-name) prompt doors); O; L* l0 D& h8 m/ W
- (def-room-raw (intern repeat-room) question doors)))
& F* \: c& B# c/ `8 Y& i- v - % A6 S& H; S( T5 p$ V; X
- (defun def-tutorial (&rest prompts)
u h& D8 Y* }4 `: S o3 z - "批量生成教程房间。"
& \/ |# {3 e8 e& K7 i3 } - (dolist (prompt prompts)
- X( K, K0 O3 b9 }* W - (def-tutorial-room prompt)))
! V7 D2 B, o& j, D" K
/ {* w p& {8 i( V/ H- (def-tutorial
$ e/ w1 K& G9 N6 @ - "欢迎体验微信版的开窗游戏!为了让您尽快熟悉游戏的规则,请根据教程提示一步一步完成要求的操作。注:任何时刻,您都能输入“q”来退出本教程。' B# w8 H$ I2 k( O* `
- 1. 教程6 l# a1 D1 |% w
- 2. 入门(3x3)
' W# D' x; N* C' z! E - 3. 初级(5x5)) j* |" {4 [( ]# r0 f4 [' w; c9 r
- 4. 中级(7x7)) d# l# h- [/ I/ ?
- 5. 高级(9x9)5 u7 x$ w! S2 d5 ^5 g3 {, i4 w8 i
- 0. 关于作者
: [7 _, U3 r, }' u6 C3 S - 请选择1-5开始新游戏:
1 {1 i3 }& w. M$ C3 R - 您现在正在游戏大厅里。, o" W$ @& C, I+ ^+ g. S$ E; ?, o
- 请输入“2”进入入门级房间"6 e4 Y$ n2 _7 T6 {3 g
- " ①②③
3 b) p0 l3 r D8 l1 n5 _+ a - 1 ■
) Z/ u; E0 w, o* \ - 2■■■$ o* G! U) W+ e( k; Y) p/ c6 A( R. W
- 3 ■
4 I Q( ~3 @' \/ [ e- e) s - 进入房间后,您就会看到一个如上图所示的3x3棋盘。其中黑子代表打开的窗户,白子代表关闭的窗户。您可以输入任意一个棋盘上的坐标,来开启或关闭某扇窗户。游戏的目标是开启所有窗户!
0 V) S$ n7 o* G [. T8 }6 z- S4 { - 请输入“22”来关闭第2行第2列的窗户。"9 D$ b6 e) @# x0 B
- " ①②③
9 s: ~& h x! b8 d* m# ]+ I: F1 | - 1
1 f0 j W+ N7 d& o( n - 2 ' K ?; h* [1 u% Z
- 3 B: W, J. m) U8 P3 d7 |2 {+ h
- 你可能被吓了一跳,怎么所有的窗户都被关闭了?我忘了告诉您:这些格子是被按了机关的,只要一个窗户被开启或关闭,它的上下左右四扇窗户也会连锁反应,被开启或关闭。! R8 X2 i/ }9 L* s! W
- 请输入“11”,试着开启左上角的窗户。"
* i) B/ }6 Z; K; J7 L( ~1 P9 _/ D - " ①②③* O% V# w& J8 v% E
- 1■■ * e' ?1 l' T1 j" P+ U3 Y
- 2■
6 f# h1 _) s0 r - 3
- T) O* R# _1 _+ U: |, z6 [ - 因为连锁反应,11右边和下面的窗户也被开启了。但因为11在左上角,没有上面和左边,因此这回总共只开启了三扇窗户。, L9 N, d( _/ ]+ O8 L
- 请输入“13”开启右上角的窗户。"
9 ~6 {" x0 R' G, S1 ]7 ~ - " ①②③
% D, |/ `, ?/ L3 E% m - 1■ ■
- v9 V% N9 I- H0 r - 2■ ■, }4 o& S! B2 @& e& j* W
- 3 $ j& B* z+ z7 p, p' p& p
- 第1行第2列上的窗户因为本来就是处于开启状态的,这回因为13的连锁反应,又重新被关闭了。1 @* f( t$ h+ g+ z9 F
- 请输入“31”开启左下角的窗户。"( F3 ?/ L$ m) E4 y4 O/ Y
- " ①②③- y7 X( U' H0 A- L7 Y
- 1■ ■
: @: f; G2 e* ~8 L8 J - 2 ■4 I0 Q: l+ p8 t( C/ p$ |& p. |
- 3■■ / h1 r! D" `2 F; L0 L h, W
- 此时,总共有5扇窗户被开启了。
! k! J% U1 i) V. ?: d - 请输入“33”开启右下角的窗户。"! I% b2 v x1 Y% h
- " ①②③# p. Y, N8 c4 M: v
- 1■ ■0 u7 T# `9 P4 c* S( I
- 2
1 K0 O! h8 K; {6 i* w7 h9 H - 3■ ■7 |7 ?/ L9 l7 {
- 现在,只有四个角落的窗户被打开。
" @% s' h p* S& r# W% T+ b2 [ - 请输入“22”完成最后一击!"
! u/ O' ?& ?7 s! |. K9 T! c - " ①②③
3 _7 F" F* e- Y& p - 1■■■
. e# a# l$ X! m7 d+ c - 2■■■
1 T2 J+ h+ K1 b! q! s: {$ ~4 D. e - 3■■■
0 {, A! b5 v' G$ u4 s - 您已完成教程的所有内容,输入任意内容返回大厅,开始您的开窗之旅!")5 G0 z8 [+ ~: A2 q. q; h. k9 a
, W3 U; ]# {! |1 p) o } _6 K- ;;; 棋盘
5 I8 Z3 h F; t+ h" G, U - (defconst *wechat-5x5-white-chess* 12288
- d; J1 }. Y8 w, @ z6 K. j+ K/ E - " ")% |2 }. \' a0 Q& q- P5 U% q
/ h- z3 ~% I. I V9 ^* D- (defconst *wechat-5x5-black-chess* 96322 O8 u0 @/ g8 T. n v+ o
- "■")0 x' I, q- D5 c5 I# g0 N: `6 g0 M1 c
- 5 } ^4 n7 B; W& c: e5 c9 d0 j
- (defmacro with-board (&rest body)
' {% B& q7 u* b - `(with-temp-buffer
- g1 A- b9 Z2 q* Q& C# Q# X - (unwind-protect
- A( A: E% v3 }8 f& _ - (progn
! f; u, q* a' x - (if (session "board")* d1 K5 p* Y$ W8 H: m3 h7 f
- (insert (session "board")))7 s+ d! y8 W' y
- ,@body)
) c8 G/ V% ` v- ^9 r: q7 s+ F - (session "board" (buffer-string)))))
$ H* x8 @7 ]4 y( C7 S7 D1 I - 5 M$ ?4 O$ [; D4 H4 @
- (defun board-init (size). Q( v. J* F3 T+ z" Q
- (session "size" size)- Y. G' ?2 B% j; j: R
- (session "step" 0)
) m! X+ Y( D6 |) A0 ?& U8 { - (erase-buffer)
`# G5 Z" I# i9 Y% e - (insert (format (format " %%.%ds\n" size) "①②③④⑤⑥⑦⑧⑨")): y/ I' S7 v. U) |
- (dotimes (row size)
4 m9 b Q( _' \ - (insert (format "%d%s\n" (1+ row) (make-string size *wechat-5x5-white-chess*)))))
5 F, Z' j7 F. W, T1 A - 0 I, v0 y/ B5 O* n* m7 O
- (defun board-contains-p (y x)
( f9 _* E/ l; b, s - (let ((size (session "size")))
! q" S- S+ H. v6 ?+ D9 t- h - (and (<= 1 y) (<= y size)) o, x# [: q* [! z! W
- (<= 1 x) (<= x size))))
/ u; p1 b4 h& {! z7 e( d; @
. v6 m7 z- \! F i/ p- (defun board-toggle (y x)
/ p0 Y) H* O4 e i - (when (board-contains-p y x)
* \6 N2 l4 ]# L. [/ y! z - (goto-line (1+ y))
, [3 q- U( V9 D# I0 B& [$ m - (beginning-of-line)' K! e7 {8 f7 e" c, u
- (forward-char x)0 ]& Z5 Q0 b( _% w8 f
- (insert (if (= *wechat-5x5-white-chess* (following-char))) p# [' o/ j# k! w8 [
- *wechat-5x5-black-chess*
' O0 n5 E' V( a0 p/ X/ U- Y% q - *wechat-5x5-white-chess*)); E9 N$ N6 b# p% b- y8 u$ q! g+ }
- (delete-char 1)))4 p2 N, ?, ]+ U3 k; g" D
- 0 [- Y* x* V' _* J4 K
- (defun board-put (y x), ]9 G/ r6 Q8 a
- (dolist (dir '((-1 0) (0 -1) (0 0) (0 1) (1 0)))1 w9 C1 Z- m* {1 a" v
- (board-toggle (+ y (first dir))
) @/ Q1 @$ O6 k1 v$ d - (+ x (second dir)))))1 o: A, D6 a+ e. g* E, l) _1 u5 L
: V: n+ O1 G, ^3 N6 M; M- (defun game-over-p ()
/ D( ~" N( ]; c+ @ - (beginning-of-buffer)& g1 Y8 @$ {* T/ n8 D! H
- (not (search-forward (string *wechat-5x5-white-chess*) nil t)))
) O) H/ q1 e5 m, ^( q2 i5 g
) z/ {. F# x1 ^, L- (defun board-show ()0 J" F9 m, z8 v7 A0 G
- (with-board5 `) _/ l' e. c9 o8 X
- (concat (buffer-string)* h' r/ y+ u. z
- (if (game-over-p)
% z4 ^- ^; }8 U/ p, R& O - (format "共%d步,输入任意内容返回大厅" (session "step"))* O3 a2 n0 c) y6 }
- (format "第%d步" (1+ (session "step")))))))
! Z \0 g5 \0 f5 l" B- w! N/ C - " s8 l: H4 a1 S
- (defun board-position-parse (cmd) v. m# @# M) x# {5 ^0 | P$ O
- (if (= (length cmd) 2), h, w; E% [5 R$ A9 [9 f
- (list (string-to-int (substring cmd 0 1))
! F* m1 I1 u) r$ u3 C) G: M - (string-to-int (substring cmd 1 2)))" B5 \$ E7 ~. U' T5 A
- '(0 0)))
" D: x5 h7 {8 a8 c& l! t - 5 z+ [8 N P! ~, A
- ;;; 游戏房间' u; G' N9 o g/ A" c4 |
- (defun game-room-init (cmd)
7 ?1 x4 T. W9 \$ q - (let* ((middle (string-to-int cmd))
8 O' Q# r) W8 m' e6 b - (size (1- (* 2 middle))))( Z6 @- T4 m4 w/ Z0 ~- [/ H
- (with-board) S6 P g( \. k2 O
- (board-init size)
* g$ X4 {; ^- j. B - (board-put middle middle)))
z/ C3 g! A+ N" E# C8 U1 Z - 'game-room)8 T# I# z0 @% |( Q, O- m
- U$ R/ k& u6 H1 N5 e1 _: `6 S6 v- (def-room game-room# v" l) {+ p! r( b9 O& D/ K9 @0 _8 e
- #'board-show
- c& [- Z$ m+ b8 h) R - (t (lambda (cmd)
9 } I2 B) { ], ?/ m6 s6 h - (with-board
6 Z( V$ {0 r+ ]6 y" \ - (if (game-over-p)$ [+ L( Z9 v( @& \+ F
- 'living-room6 F% x/ }/ i. m7 l4 M" m* H- P; e9 V
- (destructuring-bind (y x) (board-position-parse cmd)
$ i- e# O; p/ H" I6 @/ W; b - (when (board-contains-p y x)
# X8 f0 ^) r2 d+ i5 S5 A - (board-toggle y x)9 a: G* C8 ^' M, Q
- (session "step" (1+ (session "step"))))- v$ r/ D5 ^8 B+ R7 y
- 'game-room))))))</pre>
复制代码 |
上一篇:微信扫描登录下一篇:微信红包
|