# Chessboard program: you type in moves in algebraic notation, and it'll # display the position after each move. # recipes are mu's names for functions recipe main [ open-console # take control of screen, keyboard and mouse # The chessboard recipe takes keyboard and screen objects as 'ingredients'. # # In mu it is good form (though not required) to explicitly show the # hardware you rely on. # # The chessboard also returns the same keyboard and screen objects. In mu it # is good form to not modify ingredients of a recipe unless they are also # results. Here we clearly modify both keyboard and screen, so we return # both. # # Here the console and screen are both 0, which usually indicates real # hardware rather than a fake for testing as you'll see below. chessboard 0/screen, 0/console close-console # cleanup screen, keyboard and mouse ] ## But enough about mu. Here's what it looks like to run the chessboard program. scenario print-board-and-read-move [ trace-until 100/app # we'll make the screen really wide because the program currently prints out a long line assume-screen 120/width, 20/height # initialize keyboard to type in a move assume-console [ type [a2-a4 ] ] run [ screen:address:screen, console:address:console <- chessboard screen:address:screen, console:address:console # icon for the cursor screen <- print screen, 9251/␣ ] screen-should-contain [ # 1 2 3 4 5 6 7 8 9 10 11 # 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 -. For example: 'a2-a4'. Then press . . . . .Hit 'q' to exit. . . . .move: ␣ . . . . . ] ] ## Here's how 'chessboard' is implemented. recipe chessboard screen:address:screen, console:address:console -> screen:address:screen, console:address:console [ local-scope load-ingredients board:address:array:address:array:character <- initial-position # hook up stdin stdin:address:channel <- new-channel 10/capacity start-running send-keys-to-channel:recipe, console, stdin, screen # buffer lines in stdin buffered-stdin:address:channel <- new-channel 10/capacity start-running buffer-lines:recipe, stdin, buffered-stdin { msg:address:array:character <- new [Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves. ] print screen, msg cursor-to-next-line screen print-board screen, board cursor-to-next-line screen msg <- new [Type in your move as -. For example: 'a2-a4'. Then press . ] print screen, msg cursor-to-next-line screen msg <- new [Hit 'q' to exit. ] print screen, msg { cursor-to-next-line screen msg <- new [move: ] screen <- print screen, msg m:address:move, quit:boolean, error:boolean <- read-move buffered-stdin, screen break-if quit, +quit:label buffered-stdin <- clear-channel buffered-stdin # cleanup after error. todo: test this? loop-if error } board <- make-move board, m screen <- clear-screen screen loop } +quit ] ## a board is an array of files, a file is an array of characters (squares) recipe new-board initial-position:address:array:character -> board:address:array:address:array:character [ local-scope load-ingredients # assert(length(initial-position) == 64) len:number <- length *initial-position correct-length?:boolean <- equal len, 64 assert correct-length?, [chessboard had incorrect size] # board is an array of pointers to files; file is an array of characters board <- new location:type, 8 col:number <- copy 0 { done?:boolean <- equal col, 8 break-if done? file:address:address:array:character <- index-address *board, col *file <- new-file initial-position, col col <- add col, 1 loop } ] recipe new-file position:address:array:character, index:number -> result:address:array:character [ local-scope load-ingredients index <- multiply index, 8 result <- new character:type, 8 row:number <- copy 0 { done?:boolean <- equal row, 8 break-if done? dest:address:character <- index-address *result, row *dest <- index *position, index row <- add row, 1 index <- add index, 1 loop } ] recipe print-board screen:address:screen, board:address:array:address:array:character -> screen:address:screen [ local-scope load-ingredients row:number <- copy 7 # start printing from the top of the board # print each row { done?:boolean <- lesser-than row, 0 break-if done? # print rank number as a legend rank:number <- add row, 1 print-integer screen, rank s:address:array:character <- new [ | ] print screen, s # print each square in the row col:number <- copy 0 { done?:boolean <- equal col:number, 8 break-if done?:boolean f:address:array:character <- index *board, col c:character <- index *f, row print screen, c print screen, 32/space col <- add col, 1 loop } row <- subtract row, 1 cursor-to-next-line screen loop } # print file letters as legend s <- new [ +----------------] print screen, s screen <- cursor-to-next-line screen s <- new [ a b c d e f g h] screen <- print screen, s screen <- cursor-to-next-line screen ] recipe initial-position -> board:address:array:address:array:character [ local-scope # 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 initial-position:address:array:character <- 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 #? 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 board <- new-board initial-position ] scenario printing-the-board [ assume-screen 30/width, 12/height run [ 1:address:array:address:array:character/board <- initial-position screen:address:screen <- print-board screen:address:screen, 1:address:array:address:array:character/board ] 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 . . . . . ] ] ## data structure: move container move [ # valid range: 0-7 from-file:number from-rank:number to-file:number to-rank:number ] # prints only error messages to screen recipe read-move stdin:address:channel, screen:address:screen -> result:address:move, quit?:boolean, error?:boolean, stdin:address:channel, screen:address:screen [ local-scope load-ingredients from-file:number, quit?:boolean, error?:boolean <- read-file stdin, screen reply-if quit?, 0/dummy, quit?, error? reply-if error?, 0/dummy, quit?, error? # construct the move object result:address:move <- new move:type x:address:number <- get-address *result, from-file:offset *x <- copy from-file x <- get-address *result, from-rank:offset *x, quit?, error? <- read-rank stdin, screen reply-if quit?, 0/dummy, quit?, error? reply-if error?, 0/dummy, quit?, error? error? <- expect-from-channel stdin, 45/dash, screen reply-if error?, 0/dummy, 0/quit, error? x <- get-address *result, to-file:offset *x, quit?, error? <- read-file stdin, screen reply-if quit?:boolean, 0/dummy, quit?:boolean, error?:boolean reply-if error?:boolean, 0/dummy, quit?:boolean, error?:boolean x:address:number <- get-address *result, to-rank:offset *x, quit?, error? <- read-rank stdin, screen reply-if quit?, 0/dummy, quit?, error? reply-if error?, 0/dummy, quit?, error? error? <- expect-from-channel stdin, 10/newline, screen reply-if error?, 0/dummy, 0/quit, error? reply result, quit?, error? ] # valid values for f
/* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
 * See LICENSE file for license details.
 */
#include "dwm.h"

/* static */

static Client *
nexttiled(Client *c) {
	for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
	return c;
}

static void
togglemax(Client *c) {
	XEvent ev;
		
	if(c->isfixed)
		return;

	if((c->ismax = !c->ismax)) {
		c->rx = c->x; c->x = wax;
		c->ry = c->y; c->y = way;
		c->rw = c->w; c->w = waw - 2 * BORDERPX;
		c->rh = c->h; c->h = wah - 2 * BORDERPX;
	}
	else {
		c->x = c->rx;
		c->y = </