2015-05-10 20:03:21 +00:00
|
|
|
# Chessboard program: you type in moves in algebraic notation, and it'll
|
|
|
|
# display the position after each move.
|
2015-05-08 01:35:33 +00:00
|
|
|
|
2016-03-08 09:30:14 +00:00
|
|
|
def main [
|
2016-10-14 06:05:22 +00:00
|
|
|
local-scope
|
2015-06-22 06:53:17 +00:00
|
|
|
open-console # take control of screen, keyboard and mouse
|
2017-05-18 17:09:17 +00:00
|
|
|
clear-screen 0/screen # non-scrolling app
|
2015-05-10 20:01:58 +00:00
|
|
|
|
2016-03-09 22:54:41 +00:00
|
|
|
# The chessboard function takes keyboard and screen objects as 'ingredients'.
|
2015-05-10 20:01:58 +00:00
|
|
|
#
|
2016-10-22 23:56:07 +00:00
|
|
|
# In Mu it is good form (though not required) to explicitly state what
|
|
|
|
# hardware a function needs.
|
2015-05-10 20:01:58 +00:00
|
|
|
#
|
2015-06-22 06:53:17 +00:00
|
|
|
# Here the console and screen are both 0, which usually indicates real
|
2015-05-11 07:51:28 +00:00
|
|
|
# hardware rather than a fake for testing as you'll see below.
|
2015-11-19 05:36:36 +00:00
|
|
|
chessboard 0/screen, 0/console
|
2015-05-10 20:01:58 +00:00
|
|
|
|
2016-04-28 00:59:46 +00:00
|
|
|
close-console # clean up screen, keyboard and mouse
|
2015-05-10 20:01:58 +00:00
|
|
|
]
|
|
|
|
|
2016-10-22 23:56:07 +00:00
|
|
|
## But enough about Mu. Here's what it looks like to run the chessboard program.
|
2015-05-14 19:06:16 +00:00
|
|
|
|
|
|
|
scenario print-board-and-read-move [
|
2016-10-14 06:05:22 +00:00
|
|
|
local-scope
|
2015-10-07 06:38:28 +00:00
|
|
|
trace-until 100/app
|
2015-05-14 23:04:26 +00:00
|
|
|
# we'll make the screen really wide because the program currently prints out a long line
|
2015-07-28 21:33:22 +00:00
|
|
|
assume-screen 120/width, 20/height
|
2015-05-14 22:40:31 +00:00
|
|
|
# initialize keyboard to type in a move
|
2015-06-23 04:16:31 +00:00
|
|
|
assume-console [
|
|
|
|
type [a2-a4
|
2015-05-14 19:39:12 +00:00
|
|
|
]
|
2015-06-23 04:16:31 +00:00
|
|
|
]
|
2015-05-14 19:06:16 +00:00
|
|
|
run [
|
2016-09-17 19:55:10 +00:00
|
|
|
screen:&:screen, console:&:console <- chessboard screen:&:screen, console:&:console
|
2015-05-18 22:27:33 +00:00
|
|
|
# icon for the cursor
|
2016-09-17 07:31:55 +00:00
|
|
|
cursor-icon:char <- copy 9251/␣
|
2016-05-27 04:16:14 +00:00
|
|
|
screen <- print screen, cursor-icon
|
2015-05-14 19:06:16 +00:00
|
|
|
]
|
|
|
|
screen-should-contain [
|
2015-05-14 23:04:26 +00:00
|
|
|
# 1 2 3 4 5 6 7 8 9 10 11
|
2015-05-14 22:40:31 +00:00
|
|
|
# 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
|
|
.Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves. .
|
|
|
|
. .
|
|
|
|
.8 | r n b q k b n r .
|
|
|
|
.7 | p p p p p p p p .
|
|
|
|
.6 | .
|
|
|
|
.5 | .
|
|
|
|
.4 | P .
|
|
|
|
.3 | .
|
|
|
|
.2 | P P P P P P P .
|
|
|
|
.1 | R N B Q K B N R .
|
|
|
|
. +---------------- .
|
|
|
|
. a b c d e f g h .
|
|
|
|
. .
|
|
|
|
.Type in your move as <from square>-<to square>. For example: 'a2-a4'. Then press <enter>. .
|
|
|
|
. .
|
|
|
|
.Hit 'q' to exit. .
|
|
|
|
. .
|
2015-05-18 22:27:33 +00:00
|
|
|
.move: ␣ .
|
2015-05-14 22:40:31 +00:00
|
|
|
. .
|
|
|
|
. .
|
2015-05-14 19:06:16 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-05-20 01:23:20 +00:00
|
|
|
## Here's how 'chessboard' is implemented.
|
|
|
|
|
2016-10-14 06:05:22 +00:00
|
|
|
type board = &:@:&:@:char # a 2-D array of arrays of characters
|
2016-09-12 07:06:40 +00:00
|
|
|
|
2016-09-17 19:55:10 +00:00
|
|
|
def chessboard screen:&:screen, console:&:console -> screen:&:screen, console:&:console [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-09-12 07:06:40 +00:00
|
|
|
board:board <- initial-position
|
2015-05-10 20:09:53 +00:00
|
|
|
# hook up stdin
|
2016-09-17 19:55:10 +00:00
|
|
|
stdin-in:&:source:char, stdin-out:&:sink:char <- new-channel 10/capacity
|
2016-03-19 22:57:10 +00:00
|
|
|
start-running send-keys-to-channel, console, stdin-out, screen
|
2015-05-10 20:09:53 +00:00
|
|
|
# buffer lines in stdin
|
2016-09-17 19:55:10 +00:00
|
|
|
buffered-stdin-in:&:source:char, buffered-stdin-out:&:sink:char <- new-channel 10/capacity
|
2016-03-19 22:57:10 +00:00
|
|
|
start-running buffer-lines, stdin-in, buffered-stdin-out
|
2015-05-10 20:09:53 +00:00
|
|
|
{
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves.
|
2015-05-10 20:09:53 +00:00
|
|
|
]
|
2015-07-29 08:23:22 +00:00
|
|
|
cursor-to-next-line screen
|
|
|
|
print-board screen, board
|
|
|
|
cursor-to-next-line screen
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [Type in your move as <from square>-<to square>. For example: 'a2-a4'. Then press <enter>.
|
2015-05-10 20:09:53 +00:00
|
|
|
]
|
2015-07-29 08:23:22 +00:00
|
|
|
cursor-to-next-line screen
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen [Hit 'q' to exit.
|
2015-05-10 20:09:53 +00:00
|
|
|
]
|
|
|
|
{
|
2015-07-29 08:23:22 +00:00
|
|
|
cursor-to-next-line screen
|
2016-03-14 20:00:21 +00:00
|
|
|
screen <- print screen, [move: ]
|
2016-10-08 17:52:58 +00:00
|
|
|
m:&:move, quit:bool, error:bool <- read-move buffered-stdin-in, screen
|
2016-10-22 19:08:10 +00:00
|
|
|
break-if quit, +quit
|
2016-03-19 22:57:10 +00:00
|
|
|
buffered-stdin-in <- clear buffered-stdin-in # cleanup after error. todo: test this?
|
2015-07-29 08:23:22 +00:00
|
|
|
loop-if error
|
2015-05-10 20:09:53 +00:00
|
|
|
}
|
2015-07-29 08:23:22 +00:00
|
|
|
board <- make-move board, m
|
2015-11-19 05:36:36 +00:00
|
|
|
screen <- clear-screen screen
|
2015-05-10 20:09:53 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
+quit
|
|
|
|
]
|
|
|
|
|
2015-05-08 01:35:33 +00:00
|
|
|
## a board is an array of files, a file is an array of characters (squares)
|
2015-05-10 20:02:33 +00:00
|
|
|
|
2016-09-17 20:00:39 +00:00
|
|
|
def new-board initial-position:&:@:char -> board:board [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2015-05-06 19:13:04 +00:00
|
|
|
# assert(length(initial-position) == 64)
|
2016-09-17 07:43:13 +00:00
|
|
|
len:num <- length *initial-position
|
2016-10-08 17:52:58 +00:00
|
|
|
correct-length?:bool <- equal len, 64
|
2015-07-29 08:23:22 +00:00
|
|
|
assert correct-length?, [chessboard had incorrect size]
|
2015-05-06 19:13:04 +00:00
|
|
|
# board is an array of pointers to files; file is an array of characters
|
2016-04-24 18:54:30 +00:00
|
|
|
board <- new {(address array character): type}, 8
|
2016-09-17 07:43:13 +00:00
|
|
|
col:num <- copy 0
|
2015-05-06 19:13:04 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
done?:bool <- equal col, 8
|
2015-07-29 08:23:22 +00:00
|
|
|
break-if done?
|
2016-09-17 20:00:39 +00:00
|
|
|
file:&:@:char <- new-file initial-position, col
|
2016-04-23 21:51:20 +00:00
|
|
|
*board <- put-index *board, col, file
|
2015-07-29 08:23:22 +00:00
|
|
|
col <- add col, 1
|
2015-05-06 19:13:04 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2016-09-17 20:00:39 +00:00
|
|
|
def new-file position:&:@:char, index:num -> result:&:@:char [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2015-07-29 08:23:22 +00:00
|
|
|
index <- multiply index, 8
|
2015-11-19 05:36:36 +00:00
|
|
|
result <- new character:type, 8
|
2016-09-17 07:43:13 +00:00
|
|
|
row:num <- copy 0
|
2015-05-06 19:13:04 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
done?:bool <- equal row, 8
|
2015-07-29 08:23:22 +00:00
|
|
|
break-if done?
|
2016-09-17 07:31:55 +00:00
|
|
|
square:char <- index *position, index
|
2016-04-23 21:51:20 +00:00
|
|
|
*result <- put-index *result, row, square
|
2015-07-29 08:23:22 +00:00
|
|
|
row <- add row, 1
|
|
|
|
index <- add index, 1
|
2015-05-06 19:13:04 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2016-09-17 19:55:10 +00:00
|
|
|
def print-board screen:&:screen, board:board -> screen:&:screen [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-09-17 07:43:13 +00:00
|
|
|
row:num <- copy 7 # start printing from the top of the board
|
2016-09-17 07:31:55 +00:00
|
|
|
space:char <- copy 32/space
|
2015-05-06 19:13:04 +00:00
|
|
|
# print each row
|
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
done?:bool <- lesser-than row, 0
|
2015-07-29 08:23:22 +00:00
|
|
|
break-if done?
|
2015-05-06 19:13:04 +00:00
|
|
|
# print rank number as a legend
|
2016-09-17 07:43:13 +00:00
|
|
|
rank:num <- add row, 1
|
2017-01-22 20:05:24 +00:00
|
|
|
print screen, rank
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [ | ]
|
2015-05-06 19:13:04 +00:00
|
|
|
# print each square in the row
|
2016-09-17 07:43:13 +00:00
|
|
|
col:num <- copy 0
|
2015-05-06 19:13:04 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
done?:bool <- equal col:num, 8
|
|
|
|
break-if done?:bool
|
2016-09-17 20:00:39 +00:00
|
|
|
f:&:@:char <- index *board, col
|
2016-09-17 07:31:55 +00:00
|
|
|
c:char <- index *f, row
|
2015-11-21 18:19:34 +00:00
|
|
|
print screen, c
|
2015-12-28 16:44:36 +00:00
|
|
|
print screen, space
|
2015-07-29 08:23:22 +00:00
|
|
|
col <- add col, 1
|
2015-05-06 19:13:04 +00:00
|
|
|
loop
|
|
|
|
}
|
2015-07-29 08:23:22 +00:00
|
|
|
row <- subtract row, 1
|
|
|
|
cursor-to-next-line screen
|
2015-05-06 19:13:04 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
# print file letters as legend
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [ +----------------]
|
|
|
|
cursor-to-next-line screen
|
|
|
|
print screen, [ a b c d e f g h]
|
|
|
|
cursor-to-next-line screen
|
2015-05-06 19:13:04 +00:00
|
|
|
]
|
|
|
|
|
2016-09-13 07:07:38 +00:00
|
|
|
def initial-position -> board:board [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-05-08 16:11:12 +00:00
|
|
|
# layout in memory (in raster order):
|
|
|
|
# R P _ _ _ _ p r
|
|
|
|
# N P _ _ _ _ p n
|
|
|
|
# B P _ _ _ _ p b
|
|
|
|
# Q P _ _ _ _ p q
|
|
|
|
# K P _ _ _ _ p k
|
|
|
|
# B P _ _ _ _ p B
|
|
|
|
# N P _ _ _ _ p n
|
|
|
|
# R P _ _ _ _ p r
|
2016-09-17 20:00:39 +00:00
|
|
|
initial-position:&:@:char <- new-array 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r, 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, 81/Q, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 113/q, 75/K, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 107/k, 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r
|
2015-07-28 21:33:22 +00:00
|
|
|
#? 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r,
|
|
|
|
#? 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n,
|
|
|
|
#? 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b,
|
|
|
|
#? 81/Q, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 113/q,
|
|
|
|
#? 75/K, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 107/k,
|
|
|
|
#? 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b,
|
|
|
|
#? 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n,
|
|
|
|
#? 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r
|
2015-11-19 05:36:36 +00:00
|
|
|
board <- new-board initial-position
|
2015-05-08 16:11:12 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
scenario printing-the-board [
|
2016-10-14 06:05:22 +00:00
|
|
|
local-scope
|
|
|
|
board:board <- initial-position
|
2015-07-28 21:33:22 +00:00
|
|
|
assume-screen 30/width, 12/height
|
2015-05-08 16:11:12 +00:00
|
|
|
run [
|
2016-09-17 19:55:10 +00:00
|
|
|
screen:&:screen <- print-board screen:&:screen, board
|
2015-05-06 19:13:04 +00:00
|
|
|
]
|
|
|
|
screen-should-contain [
|
|
|
|
# 012345678901234567890123456789
|
|
|
|
.8 | r n b q k b n r .
|
|
|
|
.7 | p p p p p p p p .
|
|
|
|
.6 | .
|
|
|
|
.5 | .
|
|
|
|
.4 | .
|
|
|
|
.3 | .
|
|
|
|
.2 | P P P P P P P P .
|
|
|
|
.1 | R N B Q K B N R .
|
|
|
|
. +---------------- .
|
|
|
|
. a b c d e f g h .
|
|
|
|
. .
|
|
|
|
. .
|
|
|
|
]
|
|
|
|
]
|
2015-05-08 01:35:33 +00:00
|
|
|
|
|
|
|
## data structure: move
|
2015-05-10 20:02:33 +00:00
|
|
|
|
2015-05-08 01:35:33 +00:00
|
|
|
container move [
|
|
|
|
# valid range: 0-7
|
2016-09-17 07:43:13 +00:00
|
|
|
from-file:num
|
|
|
|
from-rank:num
|
|
|
|
to-file:num
|
|
|
|
to-rank:num
|
2015-05-08 01:35:33 +00:00
|
|
|
]
|
|
|
|
|
2015-05-10 18:38:18 +00:00
|
|
|
# prints only error messages to screen
|
2016-10-08 17:52:58 +00:00
|
|
|
def read-move stdin:&:source:char, screen:&:screen -> result:&:move, quit?:bool, error?:bool, stdin:&:source:char, screen:&:screen [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-10-08 17:52:58 +00:00
|
|
|
from-file:num, quit?:bool, error?:bool <- read-file stdin, screen
|
2016-03-10 00:41:40 +00:00
|
|
|
return-if quit?, 0/dummy
|
|
|
|
return-if error?, 0/dummy
|
2015-05-08 01:35:33 +00:00
|
|
|
# construct the move object
|
2016-09-17 19:55:10 +00:00
|
|
|
result:&:move <- new move:type
|
2016-04-17 05:19:53 +00:00
|
|
|
*result <- put *result, from-file:offset, from-file
|
2016-09-17 07:43:13 +00:00
|
|
|
from-rank:num, quit?, error? <- read-rank stdin, screen
|
2016-03-10 00:41:40 +00:00
|
|
|
return-if quit?, 0/dummy
|
|
|
|
return-if error?, 0/dummy
|
2016-04-17 05:19:53 +00:00
|
|
|
*result <- put *result, from-rank:offset, from-rank
|
2015-07-29 08:23:22 +00:00
|
|
|
error? <- expect-from-channel stdin, 45/dash, screen
|
2016-03-10 00:41:40 +00:00
|
|
|
return-if error?, 0/dummy, 0/quit
|
2016-09-17 07:43:13 +00:00
|
|
|
to-file:num, quit?, error? <- read-file stdin, screen
|
2016-10-08 17:52:58 +00:00
|
|
|
return-if quit?:bool, 0/dummy
|
|
|
|
return-if error?:bool, 0/dummy
|
2016-04-17 05:19:53 +00:00
|
|
|
*result <- put *result, to-file:offset, to-file
|
2016-09-17 07:43:13 +00:00
|
|
|
to-rank:num, quit?, error? <- read-rank stdin, screen
|
2016-03-10 00:41:40 +00:00
|
|
|
return-if quit?, 0/dummy
|
|
|
|
return-if error?, 0/dummy
|
2016-04-27 07:10:20 +00:00
|
|
|
*result <- put *result, to-rank:offset, to-rank
|
2015-07-29 08:23:22 +00:00
|
|
|
error? <- expect-from-channel stdin, 10/newline, screen
|
2016-03-10 00:41:40 +00:00
|
|
|
return-if error?, 0/dummy, 0/quit
|
2015-05-08 01:35:33 +00:00
|
|
|
]
|
|
|
|
|
2015-05-10 18:38:18 +00:00
|
|
|
# valid values for file: 0-7
|
2016-10-08 17:52:58 +00:00
|
|
|
def read-file stdin:&:source:char, screen:&:screen -> file:num, quit:bool, error:bool, stdin:&:source:char, screen:&:screen [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-10-08 17:52:58 +00:00
|
|
|
c:char, eof?:bool, stdin <- read stdin
|
2016-04-28 05:28:55 +00:00
|
|
|
return-if eof?, 0/dummy, 1/quit, 0/error
|
2015-05-08 01:35:33 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
q-pressed?:bool <- equal c, 81/Q
|
2015-07-29 08:23:22 +00:00
|
|
|
break-unless q-pressed?
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 1/quit, 0/error
|
2015-05-08 05:27:30 +00:00
|
|
|
}
|
|
|
|
{
|
2015-07-29 08:23:22 +00:00
|
|
|
q-pressed? <- equal c, 113/q
|
|
|
|
break-unless q-pressed?
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 1/quit, 0/error
|
2015-05-08 01:35:33 +00:00
|
|
|
}
|
2015-05-14 19:39:12 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
empty-fake-keyboard?:bool <- equal c, 0/eof
|
2015-07-29 08:23:22 +00:00
|
|
|
break-unless empty-fake-keyboard?
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 1/quit, 0/error
|
2015-05-14 19:39:12 +00:00
|
|
|
}
|
2015-05-10 18:44:33 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
newline?:bool <- equal c, 10/newline
|
2015-07-29 08:23:22 +00:00
|
|
|
break-unless newline?
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [that's not enough]
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 0/quit, 1/error
|
2015-05-10 18:44:33 +00:00
|
|
|
}
|
2016-09-17 07:43:13 +00:00
|
|
|
file:num <- subtract c, 97/a
|
2015-05-08 01:35:33 +00:00
|
|
|
# 'a' <= file <= 'h'
|
2015-05-10 18:38:18 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
above-min:bool <- greater-or-equal file, 0
|
2015-07-29 08:23:22 +00:00
|
|
|
break-if above-min
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [file too low: ]
|
2015-11-21 18:19:34 +00:00
|
|
|
print screen, c
|
2015-07-29 08:23:22 +00:00
|
|
|
cursor-to-next-line screen
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 0/quit, 1/error
|
2015-05-10 18:38:18 +00:00
|
|
|
}
|
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
below-max:bool <- lesser-than file, 8
|
2015-07-29 08:23:22 +00:00
|
|
|
break-if below-max
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [file too high: ]
|
2015-11-21 18:19:34 +00:00
|
|
|
print screen, c
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 0/quit, 1/error
|
2015-05-10 18:38:18 +00:00
|
|
|
}
|
2016-03-08 09:30:14 +00:00
|
|
|
return file, 0/quit, 0/error
|
2015-05-08 01:35:33 +00:00
|
|
|
]
|
|
|
|
|
2016-04-28 05:28:55 +00:00
|
|
|
# valid values for rank: 0-7
|
2016-10-08 17:52:58 +00:00
|
|
|
def read-rank stdin:&:source:char, screen:&:screen -> rank:num, quit?:bool, error?:bool, stdin:&:source:char, screen:&:screen [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-10-08 17:52:58 +00:00
|
|
|
c:char, eof?:bool, stdin <- read stdin
|
2016-04-28 05:28:55 +00:00
|
|
|
return-if eof?, 0/dummy, 1/quit, 0/error
|
2015-05-08 01:35:33 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
q-pressed?:bool <- equal c, 8/Q
|
2015-07-29 08:23:22 +00:00
|
|
|
break-unless q-pressed?
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 1/quit, 0/error
|
2015-05-08 05:27:30 +00:00
|
|
|
}
|
|
|
|
{
|
2015-07-29 08:23:22 +00:00
|
|
|
q-pressed? <- equal c, 113/q
|
|
|
|
break-unless q-pressed?
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 1/quit, 0/error
|
2015-05-08 01:35:33 +00:00
|
|
|
}
|
2015-05-10 18:44:33 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
newline?:bool <- equal c, 10 # newline
|
2015-07-29 08:23:22 +00:00
|
|
|
break-unless newline?
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [that's not enough]
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 0/quit, 1/error
|
2015-05-10 18:44:33 +00:00
|
|
|
}
|
2016-09-17 07:43:13 +00:00
|
|
|
rank:num <- subtract c, 49/'1'
|
2015-05-08 01:35:33 +00:00
|
|
|
# assert'1' <= rank <= '8'
|
2015-05-10 18:38:18 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
above-min:bool <- greater-or-equal rank, 0
|
2015-07-29 08:23:22 +00:00
|
|
|
break-if above-min
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [rank too low: ]
|
2015-11-21 18:19:34 +00:00
|
|
|
print screen, c
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 0/quit, 1/error
|
2015-05-10 18:38:18 +00:00
|
|
|
}
|
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
below-max:bool <- lesser-or-equal rank, 7
|
2015-07-29 08:23:22 +00:00
|
|
|
break-if below-max
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [rank too high: ]
|
2015-11-21 18:19:34 +00:00
|
|
|
print screen, c
|
2016-03-08 09:30:14 +00:00
|
|
|
return 0/dummy, 0/quit, 1/error
|
2015-05-10 18:38:18 +00:00
|
|
|
}
|
2016-03-08 09:30:14 +00:00
|
|
|
return rank, 0/quit, 0/error
|
2015-05-08 01:35:33 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
# read a character from the given channel and check that it's what we expect
|
2015-05-10 18:38:18 +00:00
|
|
|
# return true on error
|
2016-10-08 17:52:58 +00:00
|
|
|
def expect-from-channel stdin:&:source:char, expected:char, screen:&:screen -> result:bool, stdin:&:source:char, screen:&:screen [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-10-08 17:52:58 +00:00
|
|
|
c:char, eof?:bool, stdin <- read stdin
|
2016-04-28 05:28:55 +00:00
|
|
|
return-if eof? 1/true
|
2015-05-10 18:38:18 +00:00
|
|
|
{
|
2016-10-08 17:52:58 +00:00
|
|
|
match?:bool <- equal c, expected
|
2015-07-29 08:23:22 +00:00
|
|
|
break-if match?
|
2016-03-14 20:00:21 +00:00
|
|
|
print screen, [expected character not found]
|
2015-05-10 18:38:18 +00:00
|
|
|
}
|
2015-11-19 05:36:36 +00:00
|
|
|
result <- not match?
|
2015-05-08 01:35:33 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
scenario read-move-blocking [
|
2016-10-14 06:05:22 +00:00
|
|
|
local-scope
|
2015-07-28 21:33:22 +00:00
|
|
|
assume-screen 20/width, 2/height
|
2016-10-14 06:05:22 +00:00
|
|
|
source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
|
|
|
|
read-move-routine:num/routine <- start-running read-move, source, screen:&:screen
|
2015-05-08 01:35:33 +00:00
|
|
|
run [
|
|
|
|
# 'read-move' is waiting for input
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-09-17 07:43:13 +00:00
|
|
|
read-move-state:num <- routine-state read-move-routine
|
2016-10-08 17:52:58 +00:00
|
|
|
waiting?:bool <- not-equal read-move-state, 2/discontinued
|
2016-05-27 04:16:14 +00:00
|
|
|
assert waiting?, [
|
2015-05-08 01:35:33 +00:00
|
|
|
F read-move-blocking: routine failed to pause after coming up (before any keys were pressed)]
|
|
|
|
# press 'a'
|
2016-05-27 04:16:14 +00:00
|
|
|
sink <- write sink, 97/a
|
|
|
|
restart read-move-routine
|
2015-05-08 01:35:33 +00:00
|
|
|
# 'read-move' still waiting for input
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-05-27 04:16:14 +00:00
|
|
|
read-move-state <- routine-state read-move-routine
|
2016-09-15 07:49:58 +00:00
|
|
|
waiting? <- not-equal read-move-state, 2/discontinued
|
2016-05-27 04:16:14 +00:00
|
|
|
assert waiting?, [
|
2015-05-08 01:35:33 +00:00
|
|
|
F read-move-blocking: routine failed to pause after rank 'a']
|
|
|
|
# press '2'
|
2016-05-27 04:16:14 +00:00
|
|
|
sink <- write sink, 50/'2'
|
|
|
|
restart read-move-routine
|
2015-05-08 01:35:33 +00:00
|
|
|
# 'read-move' still waiting for input
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-05-27 04:16:14 +00:00
|
|
|
read-move-state <- routine-state read-move-routine
|
2016-09-15 07:49:58 +00:00
|
|
|
waiting? <- not-equal read-move-state, 2/discontinued
|
2016-05-27 04:16:14 +00:00
|
|
|
assert waiting?, [
|
2015-05-08 01:35:33 +00:00
|
|
|
F read-move-blocking: routine failed to pause after file 'a2']
|
|
|
|
# press '-'
|
2016-05-27 04:16:14 +00:00
|
|
|
sink <- write sink, 45/'-'
|
|
|
|
restart read-move-routine
|
2015-05-08 01:35:33 +00:00
|
|
|
# 'read-move' still waiting for input
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-05-27 04:16:14 +00:00
|
|
|
read-move-state <- routine-state read-move-routine
|
2016-09-15 07:49:58 +00:00
|
|
|
waiting? <- not-equal read-move-state, 2/discontinued
|
2016-05-27 04:16:14 +00:00
|
|
|
assert waiting?, [
|
2015-05-08 01:35:33 +00:00
|
|
|
F read-move-blocking: routine failed to pause after hyphen 'a2-']
|
|
|
|
# press 'a'
|
2016-05-27 04:16:14 +00:00
|
|
|
sink <- write sink, 97/a
|
|
|
|
restart read-move-routine
|
2015-05-08 01:35:33 +00:00
|
|
|
# 'read-move' still waiting for input
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-05-27 04:16:14 +00:00
|
|
|
read-move-state <- routine-state read-move-routine
|
2016-09-15 07:49:58 +00:00
|
|
|
waiting? <- not-equal read-move-state, 2/discontinued
|
2016-05-27 04:16:14 +00:00
|
|
|
assert waiting?, [
|
2015-05-08 01:35:33 +00:00
|
|
|
F read-move-blocking: routine failed to pause after rank 'a2-a']
|
|
|
|
# press '4'
|
2016-05-27 04:16:14 +00:00
|
|
|
sink <- write sink, 52/'4'
|
|
|
|
restart read-move-routine
|
2015-05-08 01:35:33 +00:00
|
|
|
# 'read-move' still waiting for input
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-05-27 04:16:14 +00:00
|
|
|
read-move-state <- routine-state read-move-routine
|
2016-09-15 07:49:58 +00:00
|
|
|
waiting? <- not-equal read-move-state, 2/discontinued
|
2016-05-27 04:16:14 +00:00
|
|
|
assert waiting?, [
|
2015-05-08 01:35:33 +00:00
|
|
|
F read-move-blocking: routine failed to pause after file 'a2-a4']
|
|
|
|
# press 'newline'
|
2016-05-27 04:16:14 +00:00
|
|
|
sink <- write sink, 10 # newline
|
|
|
|
restart read-move-routine
|
2015-05-08 01:35:33 +00:00
|
|
|
# 'read-move' now completes
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-05-27 04:16:14 +00:00
|
|
|
read-move-state <- routine-state read-move-routine
|
2016-10-08 17:52:58 +00:00
|
|
|
completed?:bool <- equal read-move-state, 1/completed
|
2016-05-27 04:16:14 +00:00
|
|
|
assert completed?, [
|
2015-05-08 01:35:33 +00:00
|
|
|
F read-move-blocking: routine failed to terminate on newline]
|
2015-08-21 17:37:25 +00:00
|
|
|
trace 1, [test], [reached end]
|
2015-05-08 01:35:33 +00:00
|
|
|
]
|
|
|
|
trace-should-contain [
|
|
|
|
test: reached end
|
|
|
|
]
|
|
|
|
]
|
2015-05-08 05:27:30 +00:00
|
|
|
|
|
|
|
scenario read-move-quit [
|
2016-10-14 06:05:22 +00:00
|
|
|
local-scope
|
2015-07-28 21:33:22 +00:00
|
|
|
assume-screen 20/width, 2/height
|
2016-10-14 06:05:22 +00:00
|
|
|
source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
|
|
|
|
read-move-routine:num <- start-running read-move, source, screen:&:screen
|
2015-05-08 05:27:30 +00:00
|
|
|
run [
|
|
|
|
# 'read-move' is waiting for input
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-09-17 07:43:13 +00:00
|
|
|
read-move-state:num <- routine-state read-move-routine
|
2016-10-08 17:52:58 +00:00
|
|
|
waiting?:bool <- not-equal read-move-state, 2/discontinued
|
2016-05-27 04:16:14 +00:00
|
|
|
assert waiting?, [
|
2015-05-08 05:27:30 +00:00
|
|
|
F read-move-quit: routine failed to pause after coming up (before any keys were pressed)]
|
|
|
|
# press 'q'
|
2016-05-27 04:16:14 +00:00
|
|
|
sink <- write sink, 113/q
|
|
|
|
restart read-move-routine
|
2015-05-08 05:27:30 +00:00
|
|
|
# 'read-move' completes
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-05-27 04:16:14 +00:00
|
|
|
read-move-state <- routine-state read-move-routine
|
2016-10-08 17:52:58 +00:00
|
|
|
completed?:bool <- equal read-move-state, 1/completed
|
2016-05-27 04:16:14 +00:00
|
|
|
assert completed?, [
|
2015-05-08 05:27:30 +00:00
|
|
|
F read-move-quit: routine failed to terminate on 'q']
|
2015-08-21 17:37:25 +00:00
|
|
|
trace 1, [test], [reached end]
|
2015-05-08 05:27:30 +00:00
|
|
|
]
|
|
|
|
trace-should-contain [
|
|
|
|
test: reached end
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario read-move-illegal-file [
|
2016-10-14 06:05:22 +00:00
|
|
|
local-scope
|
2015-07-28 21:33:22 +00:00
|
|
|
assume-screen 20/width, 2/height
|
2016-10-14 06:05:22 +00:00
|
|
|
source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
|
|
|
|
read-move-routine:num <- start-running read-move, source, screen:&:screen
|
2015-05-08 05:27:30 +00:00
|
|
|
run [
|
|
|
|
# 'read-move' is waiting for input
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-09-17 07:43:13 +00:00
|
|
|
read-move-state:num <- routine-state read-move-routine
|
2016-10-08 17:52:58 +00:00
|
|
|
waiting?:bool <- not-equal read-move-state, 2/discontinued
|
2016-05-27 04:16:14 +00:00
|
|
|
assert waiting?, [
|
2016-09-15 07:49:58 +00:00
|
|
|
F read-move-illegal-file: routine failed to pause after coming up (before any keys were pressed)]
|
2016-05-27 04:16:14 +00:00
|
|
|
sink <- write sink, 50/'2'
|
|
|
|
restart read-move-routine
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2015-05-08 05:27:30 +00:00
|
|
|
]
|
2015-05-10 18:38:18 +00:00
|
|
|
screen-should-contain [
|
|
|
|
.file too low: 2 .
|
|
|
|
. .
|
2015-05-08 05:27:30 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario read-move-illegal-rank [
|
2016-10-14 06:05:22 +00:00
|
|
|
local-scope
|
2015-07-28 21:33:22 +00:00
|
|
|
assume-screen 20/width, 2/height
|
2016-10-14 06:05:22 +00:00
|
|
|
source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
|
|
|
|
read-move-routine:num <- start-running read-move, source, screen:&:screen
|
2015-05-08 05:27:30 +00:00
|
|
|
run [
|
|
|
|
# 'read-move' is waiting for input
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-09-17 07:43:13 +00:00
|
|
|
read-move-state:num <- routine-state read-move-routine
|
2016-10-08 17:52:58 +00:00
|
|
|
waiting?:bool <- not-equal read-move-state, 2/discontinued
|
2016-05-27 04:16:14 +00:00
|
|
|
assert waiting?, [
|
2016-09-15 07:49:58 +00:00
|
|
|
F read-move-illegal-rank: routine failed to pause after coming up (before any keys were pressed)]
|
2016-05-27 04:16:14 +00:00
|
|
|
sink <- write sink, 97/a
|
|
|
|
sink <- write sink, 97/a
|
|
|
|
restart read-move-routine
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2015-05-08 05:27:30 +00:00
|
|
|
]
|
2015-05-10 18:38:18 +00:00
|
|
|
screen-should-contain [
|
|
|
|
.rank too high: a .
|
|
|
|
. .
|
2015-05-10 18:44:33 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario read-move-empty [
|
2016-10-14 06:05:22 +00:00
|
|
|
local-scope
|
2015-07-28 21:33:22 +00:00
|
|
|
assume-screen 20/width, 2/height
|
2016-10-14 06:05:22 +00:00
|
|
|
source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
|
|
|
|
read-move-routine:num <- start-running read-move, source, screen:&:screen
|
2015-05-10 18:44:33 +00:00
|
|
|
run [
|
|
|
|
# 'read-move' is waiting for input
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2016-09-17 07:43:13 +00:00
|
|
|
read-move-state:num <- routine-state read-move-routine
|
2016-10-08 17:52:58 +00:00
|
|
|
waiting?:bool <- not-equal read-move-state, 2/discontinued
|
2016-05-27 04:16:14 +00:00
|
|
|
assert waiting?, [
|
2016-09-15 07:49:58 +00:00
|
|
|
F read-move-empty: routine failed to pause after coming up (before any keys were pressed)]
|
2016-05-27 04:16:14 +00:00
|
|
|
sink <- write sink, 10/newline
|
|
|
|
sink <- write sink, 97/a
|
|
|
|
restart read-move-routine
|
2016-08-26 21:27:44 +00:00
|
|
|
wait-for-routine-to-block read-move-routine
|
2015-05-10 18:44:33 +00:00
|
|
|
]
|
|
|
|
screen-should-contain [
|
|
|
|
.that's not enough .
|
|
|
|
. .
|
2015-05-08 05:27:30 +00:00
|
|
|
]
|
|
|
|
]
|
2015-05-08 06:18:46 +00:00
|
|
|
|
2016-09-17 19:55:10 +00:00
|
|
|
def make-move board:board, m:&:move -> board:board [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-09-17 07:43:13 +00:00
|
|
|
from-file:num <- get *m, from-file:offset
|
|
|
|
from-rank:num <- get *m, from-rank:offset
|
|
|
|
to-file:num <- get *m, to-file:offset
|
|
|
|
to-rank:num <- get *m, to-rank:offset
|
2016-09-17 20:00:39 +00:00
|
|
|
from-f:&:@:char <- index *board, from-file
|
|
|
|
to-f:&:@:char <- index *board, to-file
|
2016-09-17 07:31:55 +00:00
|
|
|
src:char/square <- index *from-f, from-rank
|
2016-04-23 21:51:20 +00:00
|
|
|
*to-f <- put-index *to-f, to-rank, src
|
|
|
|
*from-f <- put-index *from-f, from-rank, 32/space
|
2015-05-08 06:18:46 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
scenario making-a-move [
|
2016-10-14 06:05:22 +00:00
|
|
|
local-scope
|
2015-07-28 21:33:22 +00:00
|
|
|
assume-screen 30/width, 12/height
|
2016-10-14 06:05:22 +00:00
|
|
|
board:board <- initial-position
|
|
|
|
move:&:move <- new move:type
|
|
|
|
*move <- merge 6/g, 1/'2', 6/g, 3/'4'
|
2015-05-08 06:18:46 +00:00
|
|
|
run [
|
2016-05-27 04:16:14 +00:00
|
|
|
board <- make-move board, move
|
2016-09-17 19:55:10 +00:00
|
|
|
screen:&:screen <- print-board screen:&:screen, board
|
2015-05-08 06:18:46 +00:00
|
|
|
]
|
|
|
|
screen-should-contain [
|
|
|
|
# 012345678901234567890123456789
|
|
|
|
.8 | r n b q k b n r .
|
|
|
|
.7 | p p p p p p p p .
|
|
|
|
.6 | .
|
|
|
|
.5 | .
|
|
|
|
.4 | P .
|
|
|
|
.3 | .
|
|
|
|
.2 | P P P P P P P .
|
|
|
|
.1 | R N B Q K B N R .
|
|
|
|
. +---------------- .
|
|
|
|
. a b c d e f g h .
|
|
|
|
. .
|
|
|
|
]
|
|
|
|
]
|