Created
April 1, 2010 09:11
-
-
Save youz/351580 to your computer and use it in GitHub Desktop.
A CommonLisp Implementation of the programming language "ModanShogi".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; ref. http://github.com/yhara/ShogiModan | |
(eval-when (:compile-toplevel :load-toplevel :execute) | |
(unless (find-package :modanshogi) | |
(defpackage :modanshogi | |
(:use #+:xyzzy :lisp | |
#-:xyzzy :common-lisp)))) | |
(provide 'modanshogi) | |
(in-package :modanshogi) | |
(export '(parse-kifu run compile-and-run)) | |
(defvar *delimiter-chars* "*△▲") | |
(defvar *operator-chars* "と歩金銀桂香龍馬玉王飛角") | |
(defvar *operators* | |
#(:mov :add :sub :mul :div :mod :push :pop :putc :putn :jumpif :jumpifp)) | |
(defvar *column-chars* "同123456789") | |
(defvar *row-chars* " 一二三四五六七八九") | |
;;; conditions | |
(define-condition kifu-error (error) | |
(kifu) | |
(:report | |
(lambda (c s) | |
(format s "kifu-error at :~{~A~}" (kifu-error-kifu c))))) | |
(define-condition runtime-error (error) | |
(op col row stack cond) | |
(:report | |
(lambda (c s) | |
(format s "runtime-error~%~A~% on ~S(X: ~A Y: ~A)~% stack:[~{~A~^,~}]" | |
(runtime-error-cond c) | |
(runtime-error-op c) | |
(runtime-error-col c) | |
(runtime-error-row c) | |
(runtime-error-stack c))))) | |
;;; parser | |
(defun readinst (is c) | |
(let* ((chars (list #1=(read-char is nil nil) #1# #1#)) | |
(inst (mapcar #'position chars | |
(list *column-chars* *row-chars* *operator-chars*)))) | |
(when (some #'null inst) | |
(error 'kifu-error :kifu (cons c chars))) | |
(list (svref *operators* (caddr inst)) (car inst) (cadr inst)))) | |
(defun parse-kifu (source) | |
(let ((table (make-hash-table :test 'eql)) | |
(i 0) insts last) | |
(with-input-from-string (is source) | |
(do ((c #1=(read-char is nil nil) #1#)) | |
((null c)) | |
(when (find c *delimiter-chars*) | |
(case c | |
(#\* (let ((label (read is))) | |
(setf (gethash label table) i) | |
(push (list :label label 0) insts))) | |
(t (let ((inst (readinst is c))) | |
(when (= (cadr inst) 0) | |
(setf (cdr inst) (cdr last))) | |
(push (setq last inst) insts)))) | |
(incf i))) | |
(values (nreverse insts) table)))) | |
;;; evaluator | |
(defun evaluate (insts jumptbl) | |
(do ((insts (apply #'vector insts)) | |
(reg (make-array 10 :initial-contents '(0 1 2 3 4 5 6 7 8 9))) | |
(stack (list)) | |
(end (length insts)) | |
(cur 0 (1+ cur))) | |
((= cur end)) | |
(let* ((inst (aref insts cur)) | |
(op (car inst)) | |
(c (cadr inst)) | |
(r (caddr inst))) | |
(handler-case | |
(case op | |
(:mov (setf #1=(aref reg c) #2=(aref reg r))) | |
(:add (incf #1# #2#)) | |
(:sub (decf #1# #2#)) | |
(:mul (setf #1# (* #1# #2#))) | |
(:div (setf #1# (/ #1# #2#))) | |
(:mod (setf #1# (mod #1# #2#))) | |
(:push (push #1# stack)) | |
(:pop (setf #1# (pop stack))) | |
(:putc (princ (code-char (round #1#)))) | |
(:putn (princ #1#)) | |
(:jumpif (when (/= #1# 0) | |
(setq cur (gethash #2# jumptbl)))) | |
(:jumpifp (when (>= #1# 0) | |
(setq cur (gethash #2# jumptbl)))) | |
(:label t)) | |
(error (c) | |
#3=(error 'runtime-error | |
:cond c | |
:op op :col c :row r :stack stack))) | |
(unless cur #3#)))) | |
(defun run (src) | |
(multiple-value-call #'evaluate (parse-kifu src))) | |
;;; compiler | |
(defmacro w/uniq (names &body body) | |
`(let ,(mapcar #'(lambda (s) | |
`(,s (make-symbol ,(symbol-name s)))) | |
(if (consp names) names (list names))) | |
,@body)) | |
(defun compile% (src) | |
(w/uniq (greg gstack glabel gstart) | |
(let ((clauses (list)) | |
(exprs (list gstart))) | |
(dolist (insts (parse-kifu src)) | |
(let ((op (car insts)) | |
(c (cadr insts)) | |
(r (caddr insts))) | |
(if (eq op :label) | |
(progn | |
(push c exprs) | |
(push (nreverse exprs) clauses) | |
(setq exprs (list c))) | |
(let ((x `(aref ,greg ,c)) | |
(y `(aref ,greg ,r))) | |
(push | |
(case op | |
(:mov `(setf ,x ,y)) | |
(:add `(incf ,x ,y)) | |
(:sub `(decf ,x ,y)) | |
(:mul `(setf ,x (* ,x ,y))) | |
(:div `(setf ,x (/ ,x ,y))) | |
(:mod `(setf ,x (mod ,x ,y))) | |
(:push `(push ,x ,gstack)) | |
(:pop `(setf ,x (pop ,gstack))) | |
(:putc `(princ (code-char (round ,x)))) | |
(:putn `(princ ,x)) | |
(:jumpif `(when (/= ,x 0) (return ,y))) | |
(:jumpifp `(when (>= ,x 0) (return ,y)))) | |
exprs))))) | |
(push nil exprs) | |
(push (reverse exprs) clauses) | |
`(let ((,greg (make-array 10 :initial-contents '(0 1 2 3 4 5 6 7 8 9))) | |
(,gstack (list))) | |
(do ((,glabel ',gstart | |
(block () | |
(case ,glabel | |
,@(reverse clauses))))) | |
((null ,glabel))))))) | |
(defun compile-and-run (src) | |
(w/uniq (gfn) | |
(eval | |
`(progn | |
(compile (defun ,gfn () ,(compile% src))) | |
(,gfn))))) | |
(defvar *kifu-fib-1to1k* | |
"▲9九金 △8七金 ▲6四歩 △5五歩 ▲6六銀 △6五銀 ▲7七金 △7六金 *1 ▲7二角 △7一歩 ▲8四王 △5八玉 ▲8八龍 △8九歩 ▲9二馬 △1一飛 *2" | |
"fork of http://github.com/yhara/ShogiModan/blob/master/examples/fib1000.modan") | |
(defvar *kifu-fib-10k* | |
"▲9九金 △8七金 ▲6四歩 △5五歩 ▲6六銀 △同 銀 ▲7七金 △7六金 *1 ▲7二角 △7一歩 ▲8八龍 △8九歩 ▲9二馬 △1一飛 *2 ▲8四王 △5八玉 " | |
"print fib(10000)") | |
(defvar *kifu-hw-strict* | |
"▲2六歩 △6二銀 ▲6六歩 △7一銀 ▲5六歩 △6二金 | |
▲6八金 △6四歩 ▲6九金 △6三金 ▲6八玉 △5二玉 | |
▲5九金右 △6二金 ▲5八金直 △6三金 ▲5七金 △6二金 | |
▲5九金 △6五歩 ▲6七金 △6三金 ▲5八金 △5一金 | |
▲5九金 △5四歩 ▲5五歩 △5三玉 ▲5七玉 △4二銀 | |
▲6八玉 △5二金 ▲5八金 △5一金 ▲5七金上 △5二金 | |
▲5八金 △5一金 ▲5七金上 △5二金 ▲5八金 △3一銀 | |
▲5七玉 △4二玉 ▲5四歩 △同 金 ▲5五歩 △5一金 | |
▲5四歩 △4一金 ▲5六玉 △5一金 ▲6五玉 △5七歩 | |
▲3六歩 △3二玉 ▲5九金 △6一金 ▲6九金 △5一金 | |
▲5七金 △6二金 ▲5六玉 △6三金 ▲5八金上 △7四金 | |
▲5五玉 △4四歩 ▲3四金 △同 歩 ▲5九金 △3五金 | |
▲4八金 △3六金 ▲6七金 △2六金 ▲3八金 △3六金 | |
▲4八金 △3三玉 ▲5七金上 △2六金 ▲4六金 △2五金 | |
▲4五金 △同 歩 ▲3五歩 △同 金 ▲5七金 △4三金 | |
▲5六金 △4二玉" | |
"from http://yowaken.dip.jp/tdiary/20100402.html#p01") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment