home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / freecell.zip / freecell.cmd next >
OS/2 REXX Batch file  |  1996-09-11  |  23KB  |  790 lines

  1. /*rexx*/
  2. /*_____________________________________________________________________________
  3. FreeCell
  4. Philip R Brenan, 1996, phil@bga.com
  5. _____________________________________________________________________________*/
  6.  
  7. parse arg gameDepth; if gameDepth = '' then gameDepth = 1
  8.  
  9. call setUpSystem
  10.  
  11. /*_____________________________________________________________________________
  12. The game
  13. _____________________________________________________________________________*/
  14.  
  15. do game = 1 by 1
  16.   call initializeGame(randomGame())
  17.  
  18.   do forever
  19.     if countEmptyColumn() = game.!columns then game.!msg = 'Success!'
  20.     call save
  21. /*  call possibleMoves */
  22.     if game.!turn = game.!maxTurn then if autoMove() then iterate
  23.     call drawboard 1
  24.     call input
  25.     call update
  26.   end
  27. end 
  28.  
  29. /*_____________________________________________________________________________
  30. Possible moves
  31. _____________________________________________________________________________*/
  32.  
  33. possibleMoves: procedure expose game.
  34.  
  35.   do f = 0 to game.!suites
  36.     do j = 1 to game.!columns
  37.       game.!possible.f.c = 0
  38.     end
  39.   end
  40.  
  41.   do i = 1 to game.!columns
  42.     do while game.!depth.i > 0 & countEmptyFreeCell() > 0
  43.       do j = 1 to game.!columns
  44.         if i <> j then do
  45.           do j = 1 to game.!columns
  46.             game.!possible.f.c = 0
  47.           end
  48.         end
  49.       end
  50.     end
  51.   end
  52.  
  53.   call undoCmd
  54.   call save
  55. return
  56.  
  57. /*_____________________________________________________________________________
  58. Update board
  59. _____________________________________________________________________________*/
  60.  
  61. update: procedure expose game.
  62.   game.!depth = 0
  63.   do j = 1 to game.!columns
  64.     game.!depth = max(game.!depth, game.!depth.j)
  65.   end
  66. return
  67.  
  68. /*_____________________________________________________________________________
  69. Auto move
  70. _____________________________________________________________________________*/
  71.  
  72. autoMove: procedure expose game.
  73.   a.1 = min(cardNo(game.!home.2), cardNo(game.!home.3)) + 1
  74.   a.2 = min(cardNo(game.!home.1), cardNo(game.!home.4)) + 1
  75.   a.3 = a.2
  76.   a.4 = a.1
  77.  
  78.   do f = 1 to game.!suits
  79.     c = game.!freecell.f
  80.     s = suitNo(c)
  81.     if c > 0 & cardNo(c) <= a.s & homeable(c) > 0 then do
  82.       call drawBoard 0
  83.       call homeFreeCmd f
  84.       call sleep
  85.       return 1
  86.     end
  87.   end
  88.  
  89.   do j = 1 to game.!columns
  90.     d = game.!depth.j
  91.     if d > 0 then do
  92.       c = game.!board.d.j
  93.       s = suitNo(c)
  94.       if c > 0 & cardNo(c) <= a.s & homeable(c) > 0 then do
  95.         call drawBoard 0
  96.         call homeCmd j
  97.         call sleep
  98.         return 1
  99.       end
  100.     end
  101.   end
  102. return 0
  103.  
  104. /*_____________________________________________________________________________
  105. Get user input
  106. _____________________________________________________________________________*/
  107.  
  108. input: procedure expose game. gameDepth
  109.   game.!msg = ''
  110.   pull in
  111.   if length(in) = 0 then in = '?'
  112.   s = translate(left(in, 1))
  113.   game.!thisMove = s in
  114.  
  115.   if abbrev(s, 'X') then exit
  116.  
  117.   if abbrev(s, '?') then do
  118.     call sysCls
  119.     say 'FreeCell! Version 1996/09/11'
  120.     say 'Freeware: Philip R Brenan, 1996, phil@bga.com'
  121.     say
  122.     say 'C   - move column C to free cell'
  123.     say 'CC  - move column C to home'
  124.     say 'CD  - move column C to column D'
  125.     say 'FFC - move free cell F to column C'
  126.     say 'gN  - play Game N'
  127.     say 'hF  - move free cell F to Home'
  128.     say 'l   - show last move'
  129.     say 'o   - OK, resume play after undo, redo'
  130.     say 'r   - redo last move'
  131.     say 's   - reStart current game'
  132.     say 'u   - undo last move'
  133.     say 'x   - eXit'
  134.     say 'z   - start a nested game'
  135.     say
  136.     say 'Commands can be concatenated'
  137.     say
  138.     say 'any key to continue'
  139.     pull .
  140.     return
  141.   end
  142.  
  143.   if abbrev(s, 'Z') then do
  144.     call fc(game.!gameDepth + 1)
  145.     return
  146.   end
  147.  
  148.   if abbrev(s, 'S') then do
  149.     call initializeGame(game.!game)
  150.     return
  151.   end
  152.  
  153.   if abbrev(s, 'O') then do
  154.     game.!maxTurn = game.!turn
  155.     return
  156.   end
  157.  
  158.   if abbrev(s, 'U') then do
  159.     call undo
  160.     return
  161.   end
  162.  
  163.   if abbrev(s, 'L') then do
  164.     say game.!lastMove
  165.     pull .
  166.     return
  167.   end
  168.  
  169.   if abbrev(s, 'R') then do
  170.     if redo() then return
  171.     game.!thisMove = game.!lastMove
  172.     parse value game.!lastMove with s in
  173.   end
  174.  
  175.   if abbrev(s, 'G') then do
  176.     n = randomGame()
  177.     if length(in) > 1 then if datatype(substr(in, 2)) = 'NUM' then n = abs(left(substr(in, 2), 5))
  178.     call initializeGame(n)
  179.     return
  180.   end
  181.  
  182.   if abbrev(s, 'H') then do
  183.     if length(in)= 2 & datatype(substr(in, 2)) = 'NUM',
  184.     then call homeFreeCmd substr(in, 2)
  185.     else game.!msg = 'Invalid free cell for hN command - move free cell N to home'
  186.     return
  187.   end
  188.  
  189.   drop a.; a. = ''; do i = 1 to length(in); a.i = substr(in, i, 1); a.0 = i; end
  190.  
  191.   if datatype(in) = 'NUM' then do
  192.     if      length(in) = 1              then call freeCmd     a.1
  193.     else if length(in) = 2 & a.1 \= a.2 then call moveCmd     a.1, a.2
  194.     else if length(in) = 2 & a.1  = a.2 then call homeCmd     a.1
  195.     else if length(in) = 3              then call getFreeCmd  a.1, a.3
  196.     else game.!msg = 'Invalid Move command' in 
  197.   end
  198.   else game.!msg = 'Invalid command' in 
  199. return
  200.  
  201. /*_____________________________________________________________________________
  202. Move column to column
  203. _____________________________________________________________________________*/
  204.  
  205. moveCmd: procedure expose game.
  206.   c = arg(1)
  207.   d = arg(2)
  208.  
  209.   if invalidColumn(c) | invalidColumn(d) | errorEmptyColumn(c) then return
  210.  
  211.   di = game.!depth.d
  212.   dc = game.!board.di.d
  213.   if di = 0 then target = 'onto column' d; else target = 'onto' cardLongName(dc);
  214.  
  215.   ci = game.!depth.c
  216.   sc = game.!board.ci.c
  217.   ci = ci + 1
  218.  
  219.   if di = 0,
  220.   then maxCards = min((countEmptyFreeCell() + 1) * 2 ** countEmptyColumn() - 1, game.!depth.c)
  221.   else maxCards = min((countEmptyFreeCell() + 1) * 2 ** countEmptyColumn() - 0, game.!depth.c)
  222.  
  223.   do j = 1 to game.!depth.c
  224.     if j > 1 & \onto4(ci, c, ci - 1, c) then leave
  225.     ci = ci - 1
  226.     cc = game.!board.ci.c
  227.  
  228.     if j > maxCards then do
  229.       game.!msg = 'I can move' maxCards 'but column' c target 'requires' j 'free cells'
  230.       return;
  231.     end
  232.     if (di = 0 & (j = maxCards /*game.!depth.c*/ | \onto4(ci, c, ci - 1, c))) | onto2(cc, dc) then do
  233.       do k = 1 to j
  234.         si = game.!depth.c - k + 1
  235.         sc = game.!board.si.c
  236.         ti = game.!depth.d + j - k + 1
  237.         game.!board.ti.d = sc
  238.         game.!board.si.c = 0
  239.       end
  240.       game.!depth.d  = game.!depth.d + j
  241.       game.!depth.c  = game.!depth.c - j
  242.       if j > 1,
  243.       then call madeMove j 'cards from column' c target
  244.       else call madeMove cardLongName(sc) ||     target
  245.       return
  246.     end
  247.   end
  248.   game.!msg = 'Cannot move' cardLongName(sc) 'onto' cardLongName(dc) 
  249. return
  250.  
  251. /*_____________________________________________________________________________
  252. Move card to free cell
  253. _____________________________________________________________________________*/
  254.  
  255. freeCmd: procedure expose game.
  256.   j = arg(1)
  257.   if invalidColumn(j) | errorEmptyColumn(j) then return
  258.  
  259.   do f = 1 to game.!suits
  260.     if game.!freecell.f = 0 then do
  261.       i = game.!depth.j
  262.       game.!freecell.f = game.!board.i.j
  263.       game.!board.i.j  = 0
  264.       game.!depth.j    = game.!depth.j - 1
  265.       call madeMove cardLongName(game.!freecell.f) 'to free cell' f
  266.       return
  267.     end
  268.   end
  269.   game.!msg = 'No more free cells'
  270. return
  271.  
  272. /*_____________________________________________________________________________
  273. Move card to home
  274. _____________________________________________________________________________*/
  275.  
  276. homeCmd: procedure expose game.
  277.   j = arg(1)
  278.   
  279.   if invalidColumn(j) | errorEmptyColumn(j) then return
  280.  
  281.   i = game.!depth.j
  282.   c = game.!board.i.j
  283.   s = homeable(c)
  284.  
  285.   if s > 0 then do
  286.     game.!home.s    = c
  287.     game.!board.i.j = 0
  288.     game.!depth.j   = game.!depth.j - 1
  289.     call madeMove cardLongName(c) 'home'
  290.     return
  291.   end
  292.   game.!msg = 'Cannot move' cardLongName(c) 'home yet'
  293. return
  294.  
  295. /*_____________________________________________________________________________
  296. Can card be moved home yet? Return suit if possible
  297. _____________________________________________________________________________*/
  298.  
  299. homeable: procedure expose game.
  300.   c = arg(1)
  301.   s = suitNo(c)
  302.   h = game.!home.s
  303.  
  304.   if (h = 0 & cardNo(c) = 1) | (cardNo(c) = cardNo(h) + 1) then return s
  305. return 0
  306.  
  307. /*_____________________________________________________________________________
  308. Move free cell to column
  309. _____________________________________________________________________________*/
  310.  
  311. getFreeCmd: procedure expose game.
  312.   f = arg(1); j = arg(2)
  313.  
  314.   if invalidFreeCell(f) | errorEmptyFreeCell(f) | invalidColumn(j) then return
  315.  
  316.   i  = game.!depth.j
  317.   fc = game.!freecell.f
  318.   jc = game.!board.i.j
  319.  
  320.   if i > 0 then if \onto2(fc, jc) then do
  321.     game.!msg = 'Cannot move' cardLongName(fc) 'from free cell onto' cardLongName(jc)
  322.     return
  323.   end
  324.  
  325.   i = i + 1
  326.   game.!depth.j    = i
  327.   game.!board.i.j  = game.!freecell.f
  328.   game.!freecell.f = 0
  329.   call madeMove cardLongName(fc) 'onto' cardLongName(jc)
  330. return
  331.  
  332. /*_____________________________________________________________________________
  333. Move free cell to home
  334. _____________________________________________________________________________*/
  335.  
  336. homeFreeCmd: procedure expose game.
  337.   f = arg(1)
  338.  
  339.   if invalidFreeCell(f) | errorEmptyFreeCell(f) then return
  340.  
  341.   c = game.!freecell.f
  342.   s = suitNo(c)
  343.   h = game.!home.s
  344.  
  345.   if (h = 0 & cardNo(c) = 1) | (cardNo(c) = cardNo(h) + 1) then do
  346.     game.!home.s     = c
  347.     game.!freecell.f = 0
  348.     call madeMove cardLongName(c) 'home'
  349.   end
  350.   else game.!msg = 'Cannot move' cardLongName(c) 'home yet'
  351. return
  352.  
  353. /*_____________________________________________________________________________
  354. Made a move
  355. _____________________________________________________________________________*/
  356.  
  357. madeMove: procedure expose game.
  358.   t = arg(1)
  359.   turn           = game.!turn + 1
  360.   game.!turn     = turn
  361.   game.!maxTurn  = turn
  362.   game.!msg      = 'Moved' t
  363.   game.!lastMove = game.!thisMove
  364. return
  365.  
  366. /*_____________________________________________________________________________
  367. Count empty free cells, columns
  368. _____________________________________________________________________________*/
  369.  
  370. countEmptyFreeCell: procedure expose game.
  371.   n = 0
  372.   do f = 1 to game.!suits
  373.     if game.!freecell.f = 0 then n = n + 1
  374.   end
  375. return n
  376.  
  377. countEmptyColumn: procedure expose game.
  378.   n = 0
  379.   do j = 1 to game.!columns
  380.     if game.!depth.j = 0 then n = n + 1
  381.   end
  382. return n
  383.  
  384. /*_____________________________________________________________________________
  385. Error if there are no cards in a free cell or a column
  386. _____________________________________________________________________________*/
  387.  
  388. errorEmptyFreeCell: procedure expose game.
  389.   f = arg(1)
  390.   if game.!freecell.f = 0 then do
  391.     game.!msg = 'No cards in free cell' f
  392.     return 1
  393.   end
  394. return 0
  395.  
  396. errorEmptyColumn: procedure expose game.
  397.   j = arg(1)
  398.   if game.!depth.j = 0 then do
  399.     game.!msg = 'No cards in column' j
  400.     return 1
  401.   end
  402. return 0
  403.  
  404. /*_____________________________________________________________________________
  405. Invalid column or free cell?
  406. _____________________________________________________________________________*/
  407.  
  408. invalidFreeCell: procedure expose game.
  409.   f = arg(1)
  410.  
  411.   if f < 1 | f > game.!suits then do
  412.     game.!msg = 'Invalid free cell' f 'specified'
  413.     return 1
  414.   end
  415. return 0
  416.  
  417. invalidColumn: procedure expose game.
  418.   j = arg(1)
  419.  
  420.   if j < 1 | j > game.!columns then do
  421.     game.!msg = 'Invalid column' j 'specified'
  422.     return 1
  423.   end
  424. return 0
  425.  
  426. /*_____________________________________________________________________________
  427. Check whether one card can be place on top of another.
  428. 2 - Card number
  429. 4 - Board Cordinates
  430. _____________________________________________________________________________*/
  431.  
  432. onto2: procedure expose game.
  433.  sc = arg(1)
  434.  tc = arg(2)
  435.  
  436.  if cardRed(sc) \= cardRed(tc) & cardNo(sc) = cardNo(tc) - 1 then return 1
  437. return 0 
  438.  
  439. onto4: procedure expose game.
  440.  sr = arg(1); sc = arg(2)
  441.  tr = arg(3); tc = arg(4)
  442.  
  443.  sc = game.!board.sr.sc
  444.  tc = game.!board.tr.tc
  445.  
  446. return onto2(sc, tc)
  447.  
  448. /*_____________________________________________________________________________
  449. Draw the current state of the game
  450. _____________________________________________________________________________*/
  451.  
  452. drawboard: procedure expose game.
  453.   mode = arg(1)
  454.  
  455.   parse value SysTextScreenSize() with game.!rows game.!cols
  456.   game.!board = ''; game.!boardColor = ''
  457.  
  458.   row = 1; cols = game.!columns; colw = game.!cols / game.!suits / 2
  459.  
  460.   call out center('Free Cell !', game.!cols), row, 1
  461.   call out 'Game' game.!game', turn' game.!turn', max' game.!maxTurn, row, 1
  462.   text = 'Depth ' game.!gameDepth
  463.   call out text, row, game.!cols - length(text)
  464.  
  465.   row = row + 1
  466.   call out copies(copies('-', colw - 1)'+', game.!suits), row, 1
  467.   call out copies('=', colw * game.!suits), row, game.!cols / 2 + 1
  468.  
  469.   do i = 1 to game.!suits;
  470.     call out i, row, 1 + (i - 1) * colw + colw / 2 - length(i) / 2 - 1
  471.   end
  472.  
  473.   do i = 1 to 3
  474.     call out '|', row + i, game.!cols / 2
  475.   end
  476.  
  477.   row = row + 1
  478.   do i = 1 to game.!suits;
  479.     c = game.!freecell.i
  480.     if c > 0 then do
  481.       parse value cardName(c) with suit card
  482.       if suit \= '' then do
  483.         color = colorCard(c)
  484.         col   = 1 + (i - 1) * colw
  485.         call out center(card, colw), row,     col, color
  486.         call out center('of', colw), row + 1, col, color
  487.         call out center(suit, colw), row + 2, col, color
  488.       end
  489.     end
  490.  
  491.     c = game.!home.i
  492.     parse value cardName(c) with suit card
  493.     if suit \= '' then do
  494.       color = colorCard(c)
  495.       col   = game.!cols / 2 + 1 + (i - 1) * colw
  496.       call out center(card, colw), row,     col, color
  497.       call out center('of', colw), row + 1, col, color
  498.       call out center(suit, colw), row + 2, col, color
  499.     end
  500.   end
  501.  
  502.   row = row + 3
  503.   call out copies(copies('-', colw - 1)'+', cols), row, 1
  504.  
  505.   do i = 1 to game.!columns;
  506.     call out i, row, 1 + (i - 1) * colw + colw / 2 - length(i) / 2 - 1
  507.   end
  508.  
  509.   do i = 1 to game.!depth
  510.     do j = 1 to cols
  511.       if i <= game.!depth.j then do
  512.         c = game.!board.i.j
  513.         if c > 0 then do
  514.           col = 1 + (j - 1) * colw
  515.           parse value cardName(c) with suit card
  516.           call out card, row + i,     col, colorCard(c)
  517.         end
  518.       end
  519.     end
  520.   end
  521.  
  522.   row = row + game.!depth + 3
  523.   call out game.!msg, row, 1
  524.  
  525.   if mode = 0 then text = 'Auto moving ...'
  526.   else             text = 'Enter Command, X to exit, ENTER for help:'
  527.   row = row + 2
  528.   call out text, row, 1
  529.  
  530.   call InsertColour
  531.  
  532.   if game.!turn = 1 then call syscls
  533.   call sysCurPos 0, 0
  534.   call charout , left(game.!board, length(game.!board) + game.!cols)
  535.   call sysCurPos row - 1, length(text) + 2
  536. return
  537.  
  538. /*_____________________________________________________________________________
  539. Insert colors - done in reverse to preserve card positions
  540. _____________________________________________________________________________*/
  541.  
  542. InsertColour: procedure expose game.
  543.   normalText = D2C(27)'[0m'D2C(27)'[37m'      /* light gray  */
  544.   redCard    = D2C(27)'[1m'D2C(27)'[31m'      /* bright red  */
  545.   blackCard  = D2C(27)'[1m'D2C(27)'[34m'      /* bright blue */
  546.  
  547.   b = game.!board; c = reverse(game.!boardColor); l = length(b); t = normalText;
  548.  
  549.   i = verify(c, ' ')
  550.   s = substr(c, i, 1)
  551.   do while i > 0
  552.     j = verify(c, ' ',, i + 1)
  553.     if j > 0 then t = substr(c, j, 1); else t = ''
  554.     if t \= s then do
  555.       select
  556.         when s = 'n' then b = insert(normalText, b, l - i + 1)
  557.         when s = 'b' then b = insert(blackCard,  b, l - i + 1)
  558.         when s = 'r' then b = insert(redCard,    b, l - i + 1)
  559.         otherwise nop
  560.       end
  561.     end
  562.     s = t; i = j
  563.   end
  564.   game.!board = b
  565. return
  566.  
  567.  
  568. InsertColour: procedure expose game.
  569.   normalText = D2C(27)'[0m'D2C(27)'[37m'      /* light gray  */
  570.   redCard    = D2C(27)'[1m'D2C(27)'[31m'      /* bright red  */
  571.   blackCard  = D2C(27)'[1m'D2C(27)'[34m'      /* bright blue */
  572.  
  573.   b = game.!board; c = game.!boardColor; t = normalText;
  574.  
  575.   do i = 1 to length(b)
  576.     s = substr(c, i, 1)
  577.     if pos(s, 'nbr') > 0 then do
  578.       select
  579.         when s = 'n' then t = t''normalText
  580.         when s = 'b' then t = t''blackCard
  581.         when s = 'r' then t = t''redCard
  582.         otherwise nop
  583.       end
  584.     end
  585.     t = t''substr(b, i, 1)
  586.   end
  587.   game.!board = t
  588. return
  589.  
  590. /*_____________________________________________________________________________
  591. Write a string into the output buffer
  592. _____________________________________________________________________________*/
  593. out:
  594. /*out: procedure expose game.*/
  595.   t = strip(arg(1), 't')
  596.   c = arg(4); if c = '' then c = 'n'
  597.   p = (arg(2) - 1) * game.!cols + format(arg(3),,0)
  598.   game.!board      = overlay(t,   game.!board,      p)
  599.   game.!boardColor = overlay(c,   game.!boardColor, p)
  600.   game.!boardColor = overlay('n', game.!boardColor, p + length(t))
  601. return
  602.  
  603. /*_____________________________________________________________________________
  604. Generate a random game
  605. _____________________________________________________________________________*/
  606.  
  607. randomGame: return random(1, 99999)
  608.  
  609. /*_____________________________________________________________________________
  610. Initialize a game
  611. _____________________________________________________________________________*/
  612.  
  613. initializeGame: procedure expose game. gameDepth
  614.   drop game.; game. = 0; game.!msg = 'New Game' arg(1); game.!game = arg(1)
  615.   game.!turn = 1; game.!maxTurn = 1; game.!gameDepth = gameDepth
  616.  
  617.   call cards; cards = game.!suits * game.!cards
  618.   game.!columns = game.!suits * 2
  619.  
  620.   do i = 1 to cards; place.i = i; end
  621.  
  622.   j = random(1, cards, game.!game)
  623.   do i = 1 to cards * cards
  624.     j = random(1, cards)
  625.     k = random(1, cards)
  626.     t = place.j; place.j = place.k; place.k = t
  627.   end
  628.  
  629.   do i = 1 to game.!suits; game.!freecell.i = 0; game.!home.i = 0; end
  630.  
  631.   cardNo = 0
  632.   do i = 1 by 1
  633.     do j = 1 to game.!columns
  634.       cardNo = cardNo + 1
  635.       if cardNo <= cards then do
  636.         game.!board.i.j = place.cardNo
  637.         game.!depth.j = i
  638.         game.!depth   = max(i, game.!depth)
  639.       end
  640.       else leave i
  641.     end
  642.   end
  643. return
  644.  
  645. /*_____________________________________________________________________________
  646. The cards
  647. _____________________________________________________________________________*/
  648.  
  649. cards: procedure expose game.
  650.   s = 'spades hearts diamonds clubs'
  651.  
  652.   game.!suits = words(s)
  653.   do i = 1 to words(s)
  654.     game.!suit.i = word(s, i)
  655.   end
  656.  
  657.   s = '01-ace 02-two 03-three 04-four 05-five 06-six 07-seven 08-eight 09-nine 10-ten 11-jack 12-queen 13-king'
  658.  
  659.   game.!cards = words(s)
  660.   do i = 1 to words(s)
  661.     game.!card.i = word(s, i)
  662.   end
  663. return
  664.  
  665. /*_____________________________________________________________________________
  666. Card name from card number
  667. _____________________________________________________________________________*/
  668.  
  669. cardName: procedure expose game.
  670.   n    = arg(1)
  671.   if n = 0 then return ''
  672.   card = cardNo(n); 
  673.   suit = suitNo(n); 
  674.   card = game.!card.card
  675.   suit = game.!suit.suit
  676.  
  677.   select
  678.     when abbrev(suit, 's') then card = translate(overlay(d2c(6), card, 3));
  679.     when abbrev(suit, 'h') then card = overlay(d2c(3), card, 3);
  680.     when abbrev(suit, 'd') then card = overlay(d2c(4), card, 3);
  681.     when abbrev(suit, 'c') then card = translate(overlay(d2c(5), card, 3));
  682.     otherwise
  683.   end  
  684. return suit card
  685.  
  686. /*_____________________________________________________________________________
  687. Card long name from card number
  688. _____________________________________________________________________________*/
  689.  
  690. cardLongName: procedure expose game.
  691.   parse value cardName(arg(1)) with suit card
  692. return ''''card 'of' suit''''
  693.  
  694. /*_____________________________________________________________________________
  695. Card color
  696. _____________________________________________________________________________*/
  697.  
  698. cardRed: procedure expose game.
  699.   n = suitNo(arg(1))
  700. return n = 2 | n = 3
  701.  
  702. colorCard: procedure expose game.
  703. if cardRed(arg(1)) then return 'r'; else return 'b'
  704.  
  705. /*_____________________________________________________________________________
  706. Card/Suite number from card number
  707. _____________________________________________________________________________*/
  708.  
  709. cardNo: procedure expose game. ; return (arg(1) - 1) // game.!cards + 1
  710. suitNo: procedure expose game. ; return (arg(1) - 1) %  game.!cards + 1
  711.  
  712. /*_____________________________________________________________________________
  713. System set up
  714. _____________________________________________________________________________*/
  715.  
  716. setUpSystem:
  717.   call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  718.   call SysLoadFuncs
  719. return
  720.  
  721. /*_____________________________________________________________________________
  722. Sleep
  723. _____________________________________________________________________________*/
  724.  
  725. sleep:
  726.   call sysSleep 1
  727. return
  728.  
  729. /*_____________________________________________________________________________
  730. Save
  731. _____________________________________________________________________________*/
  732.  
  733. save: procedure expose game.
  734.   state =           game.!turn game.!maxTurn game.!game game.!columns game.!rows game.!cols game.!depth game.!suits game.!cards
  735.   do i = 1 to game.!suits
  736.     state = state game.!suite.i game.!freecell.i game.!home.i
  737.   end
  738.   do i = 1 to game.!cards
  739.     state = state game.!cards.i
  740.   end
  741.   do i = 1 to game.!columns
  742.     state = state game.!depth.i
  743.     do j = 1 to game.!depth.i
  744.       state = state game.!board.i.j
  745.     end
  746.   end
  747.   state = state game.!msg
  748.   turn = game.!turn
  749.   game.!state.turn = state
  750. return
  751.  
  752. /*_____________________________________________________________________________
  753. Undo
  754. _____________________________________________________________________________*/
  755.  
  756. undo: procedure expose game.
  757.   if game.!turn > 1 then do
  758.     turn = game.!turn - 1
  759.     state = game.!state.turn
  760.  
  761.     parse var state game.!turn .             game.!game game.!columns game.!rows game.!cols game.!depth game.!suits game.!cards state
  762.     do i = 1 to game.!suits
  763.       parse var state game.!suite.i game.!freecell.i game.!home.i state
  764.     end
  765.     do i = 1 to game.!cards
  766.       parse var state game.!cards.i state
  767.     end
  768.     do i = 1 to game.!columns
  769.       parse var state game.!depth.i state
  770.       do j = 1 to game.!depth.i
  771.         parse var state game.!board.i.j state
  772.       end
  773.     end
  774.     parse var state game.!msg
  775.   end
  776. return
  777.  
  778. /*_____________________________________________________________________________
  779. Redo
  780. _____________________________________________________________________________*/
  781.  
  782. redo: procedure expose game.
  783.   if game.!turn < game.!maxTurn then do
  784.     game.!turn = game.!turn + 2
  785.     call undo
  786.     return 1
  787.   end
  788. return 0
  789.  
  790.