# Macros

Sometimes you need to play some repeating actions several times. In such a case most of the text editors provide so called macros. In general you record some actions and then you can play them several times. With YSokoban you can do that with simple text editor and just use copy/paste functionality in YSokoban. Since version 1.500 you can do that with a help of a Macro Dialog. Activate it by pressing [Macro] button. In macro dialog you can create new macro by simply typing it using lurd notation or you can press [Record] button. Then YSokoban will record all your actions. When you finish - press [stop rec] button ("Macro" changes name to "stop rec") and you will have all of your moves recorded in New Macro. Now you can play it many times and/or you can save it under some name, by giving name in "Name" edit box and pressing [Save] button. Left part of a Macro Dialog will show all saved macros. You can select them and play selected one.

## Play macro

One can use M and Shift-M keys in YSokoban to play New or Selected Macro.

Clicking with mouse on list of saved macros will:

- left click - loads macro
- left double click - loads macro and plays it
- right click - loads macro and plays it infinitely (stops on error)

## Local macro variables

It is possible to provide a local name to a macro (instead of saving it as a file). Syntax is: $macroname=macrotext

## Repeat counter

If '*' is used as a repeat counter (instead of number) then following command (or macro or group) will be repeated until failure, for example: *(lddr) or *{macro} or just *l. Using *(lr) or *(ldru) will move man infinitely (if there is space for it to move).

## Strict checking

If using '&' instead of '*' as repeat counter then YSokoban will make a strict check for move/push. This means that when strict check is active it will not make a push if move is specified. So for strict check 'r' means move right, not push right and 'R' means push right not just move.

## Undo in macro

It is possible to specify undo in macro, use '~' for undo.

## Preserve man position (and go back to there)

Sometime there is a need to preserve current man position and later on go to that place.

- '+' will push current position
- '^' will pop position and man will try to go there.
- '#' will pop position and man will not move.

It is possible to specify relative offset to pushed position by using [x,y] or push absolute position with (x,y). For example +[3,4] will push man position +3 columns and 4 rows (positive numbers means right or down, negative means left or up). But +(3,4) will push absolute position 3,4. Later on ^ (or '@') will pop that position and move man there.

@[3,5] will not pop position from stack, simply man will move relatively to offset 3,5 (position current_x+3 and current_y+5).

@(3,5) (note parenthesis instead of brackets) will move man to absolute position 3, 5 (again without popping anything from stack).

Absolute coordinates are same as in alt-R (ruler with numbers), first coordinate is x (columns), second one is y (rows)

To summarize what all this symbols do:

Symbol | Action | Action with [x,y] | Action with (x,y)
--- | --- | --- | ---
+ | push current man position to stack | push current position modified with relative coordinates | push absolute position x, y
^ | pop position from stack and go there | pop position from stack add relative coordinates and go there | pop position from stack and go to absolute position x, y (actually do not use position from stack)
# | pop position from stack (do not use it) | pop position from stack modify it with relative coordinates and push back to stack (modify top of stack) | pop position from stack and push back to stack absolute coordinates (modify top of stack)
@ | pop position from stack and go there (same as ^) | go to current position + relative coordinates (do not pop) | go to absolute position x, y (do not pop)

## Autselect nearest box and push it to a target

To autoselect nearest box an push it to a cell with coordinatex x, y - use syntax:

- b(x,y) - push nearest box to a cell with absolute coordinates x, y
- b[x,y] - push nearest box to a cell with relative (to man) coordinates x, y

## Conditional execution

### IF

It is possible to use something like if-then-else construct in macros. Syntax is

    ? expression : then-moves / else-moves ;

or just

    ? expression : then-moves ;

So key characters are ? : / and ;

### WHILE

It is possible to use something like while-do-otherwise construct in macros. Syntax is (same like if, but with double ?)

    ?? expression : do-moves / otherwise-moves ;

or just

    ?? expression : do-moves ;

In this case `do-move` are executed repeatedly while expression evaluates to true. If expression becomes false then `otherwise-moves` will be executed, but just once.

### Expression

One can use any kind of expression inside conditional expressions (for example 1+2 > 3). Following arithmetic operators can be used:

- * - multiplication
- / - division
- % - modulo
- + - addition
- - - subtraction

Operands can be:

- integer constant
- B - number of all boxes
- b - number of boxes NOT on target (entire level)
- T - number of all targets (entire level) actually B == T
- t - number of empty targets (entire level)

### Conditional expression - integer comparison

Integer values can be compared with: <, >, =, !=, <=, >=

### Conditional expression - cell comparison

Inside conditional expression one can compare content of some cell, by specifying cell coordinates:

- c[x,y] - are relative coordinates to current man position
- c(x,y) - are absolute coordinates

Cell can be compared to:

- '*' - box on target
- '+' - man on target
- '@' - man not on target
- '.' - target
- '$' - box
- '-' - empty space
- ' ' - empty space (same as above)
- '#' - wall
- '_' - same as - or . (any empty cell)
- 'b' - same as * or $ (box regardless of whether on target or not)
- 't' - same as . or * (target regardless of having or not box on it)

Comparison can be done with:

- = (or ==) for equality
- ! (or !=) for inequality

### Combining conditional expressions

It is possible to use binary operators:

- & (or &&) for and
- | (or ||) for or

### Breaking the loop

To break loop use !

It will break ?? loops or &(...) or *(...)

When used inside / ... ; part of ?? loop it will break outer loop (there is no reason to break / part of ?? because it is executed just once).

Examples:

    *(
      ...                // some moves
      ? [1,1]=# : ! ;    // this will break *( ... ) loop
      ...                // some other moves
     )

    *(
      ...                   // some moves
      ?? [1,1]=_ : rd / ! ; // this will go right and down and then at the end of ?? will break *( ... ) loop
      ...                   // some other moves
     )

If you want to break several nested loops, use more several ! in a row (without spaces). For example:

    *(
      *(
        ...                // some moves
        ? [1,1]=# : !! ;    // this will break *( *( ...) ) loop
        ...                // some other moves
       )
     )

or another example:

    *(
      ?? [1,1]=_ :
        ...                // some moves
        ? [1,1]=# : !! ;    // this will break *( ) loop (actually both loops, the *(...) and the ?? ... ;)
        ...                // some other moves
      ;
     )

### Comments

Macro text can contain C++ style comments, so everything after // till the end of the line is simply skipped by macro.

### Debug mode

When debug mode is active, then macro will be executed step by step. Debug mode is activated by pressing dbg button.

### Reseting macro execution

To reset macro execution - press rst button.

### Breakpoint

Putting symbol ` (back single quote) somewhere in macro will break macro execution and bring macro dialog active even if macro is not currently in debug mode. Debug mode will not be switched on, so pressing play it will continue execution. One can switch to debug mode and continue step by step execution.

Created with Ywiki