#lang racket
;; シナリオのロード
(define *scenario*
(with-input-from-file "img8/scenario-rkt.txt"
(lambda ()
(let loop ((s-expression (read)) (acc '()))
(if (eof-object? s-expression)
(reverse acc)
(loop (read) (cons s-expression acc)))))))
;; 初期メッセージ
(define *init-message* "Enterでスタート")
;;; 終了メッセージ
(define *end-message* "終わり")
;; World 構造体
(struct world
(back branches characters color message scenario)
#:transparent)
;; eval
(define (world-go exp w)
(let loop ((back (world-back w))
(branches (world-branches w))
(characters (world-characters w))
(color (world-color w))
(message (world-message w))
(scenario (world-scenario w)))
(let ((s-expression (car scenario)))
(let ((head (car s-expression)) (tail (cdr s-expression)))
(case head
((back) (loop (car tail) branches characters
color message (cdr scenario)))
((branch) (loop back (cons tail branches) characters
color message (cdr scenario)))
((break) (cond ((or (char=? exp #\1)
(char=? exp #\2))
(world-go #\newline
(world back '() characters
color message
(find-label
(third
branches))
scenario))))
(world-go #\newline
(world back '() characters
color message
(find-label
(second
(assoc (list->string `(,exp))
(map reverse branches)))
scenario))))
(else (world back branches characters
color message scenario))))
((end) (world back branches characters
color *end-message* scenario))
((jump) (world-go #\newline
(world back branches characters
color message
(find-label (car tail) scenario))))
((label) (world back branches characters
color message (cons '(break) scenario)))
((msg) (world back branches characters
color
(car tail
) (if (char=? exp #\newline) (cdr scenario)
scenario)))
((putChar) (loop back branches
(if (member tail characters)
characters
(cons tail characters))
color message (cdr scenario)))
(else (error "Can't do " head)))))))
;; 補助関数
(define (digit-value ch)
(string->number (list->string `(,ch))))
(define (find-label x scenario)
(unless (null? scenario)
(let ((s-expression (car scenario)))
(let ((head (car s-expression)) (tail (cdr s-expression)))
(if (and (eq? head 'label) (eq? x (car tail)))
(cdr scenario)
(find-label x (cdr scenario)))))))
;;; ゲーム終了条件
(define (game-ends? w)
(string=? (world-message w) *end-message*))
;;; 出力関数
(define (print w)
(display
(format "~a~%" (if (null? (world-branches w))
(string-replace (world-message w) "~%" "\n")
(apply string-append
(map (lambda (x)
(string-append
(number->string (car x))
" "
(second x)
"\n"))
(reverse (world-branches w))))))))
;;; REPL(Read-Eval-Print Loop)
(define (repl w)
(print w)
(if (game-ends? w)
(exit)
(repl (world-go (read-char) w))))
(repl (world #f '() '() 1 *init-message* *scenario*))