# Chessboard program: you type in moves in algebraic notation, and it'll # display the position after each move. def main [ local-scope open-console # take control of screen, keyboard and mouse clear-screen null/screen # non-scrolling app # The chessboard function takes keyboard and screen objects as inputs. # # In Mu it is good form (though not required) to explicitly state what # hardware a function needs. # # Here the console and screen are both null, which usually indicates real # hardware rather than a fake for testing as you'll see below. chessboard null/screen, null/console close-console # clean up 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 [ local-scope 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, console <- chessboard screen, console # icon for the cursor cursor-icon:char <- copy 9251/␣ screen <- print screen, cursor-icon ] 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. type board = &:@:&:@:char # a 2-D array of arrays of characters def chessboard screen:&:screen, console:&:console -> screen:&:screen, console:&:console [ local-scope load-inputs board:board <- initial-position # hook up stdin stdin-in:&:source:char, stdin-out:&:sink:char <- new-channel 10/capacity start-running send-keys-to-channel, console, stdin-out, screen # buffer lines in stdin buffered-stdin-in:&:source:char, buffered-stdin-out:&:sink:char <- new-channel 10/capacity start-running buffer-lines, stdin-in, buffered-stdin-out { print screen, [Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves. ] cursor-to-next-line screen print screen, board cursor-to-next-line screen print screen, [Type in your move as -. For example: 'a2-a4'. Then press . ] cursor-to-next-line screen print screen [Hit 'q' to exit. ] { cursor-to-next-line screen
//: Let's raise errors when students use real hardware in any recipes besides
//: 'main'. Part of the goal is to teach them testing hygiene and dependency
//: injection.
//:
//: This is easy to sidestep, it's for feedback rather than safety.

:(before "End Globals")
vector<type_tree*> Real_hardware_types;
:(before "Begin transform_all")
setup_real_hardware_types();
:(before "End transform_all")
teardown_real_hardware_types();
:(code)
void setup_real_hardware_types() {
  Real_hardware_types.push_back(parse_type("address:screen"));
  Real_hardware_types.push_back(parse_type("address:console"));
  Real_hardware_types.push_back(parse_type("address:resources"));
}
type_tree* parse_type(string s) {
  reagent x("x:"+s);
  type_tree* result = x.type;
  x.type = NULL;  // don't deallocate on return
  return result;
}
void teardown_real_hardware_types() {
  for (int i = 0;  i < SIZE(Real_hardware_types);  ++i)
    delete Real_hardware_types.at(i);
  Real_hardware_types.clear();
}

:(before "End Checks")
Transform.push_back(check_for_misuse_of_real_hardware);
:(code)
void check_for_misuse_of_real_hardware(const recipe_ordinal r) {
  const recipe& caller = get(Recipe, r);
  if (caller.name == "main") return;
  if (starts_with(caller.name, "scenario_")) return;
  trace(9991, "transform") << "--- check if recipe " << caller.name << " has any dependency-injection mistakes" << end();
  for (int index = 0;  index < SIZE(caller.steps);  ++index) {
    const instruction& inst = caller.steps.at(index);
    if (is_primitive(inst.operation)) continue;
    for (int i = 0;  i < SIZE(inst.ingredients);  ++i) {
      const reagent& ing = inst.ingredients.at(i);
      if (!is_literal(ing) || ing.