Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - qbguy

Pages: [1]
1
Programs / Sudoku solver
« on: April 17, 2019, 07:15:16 pm »
Code: QB64: [Select]
  1. DECLARE SUB UPDATEBOARD ()
  2. DEFINT A-Z
  3. CONST RANK = 3
  4. CONST RANK2 = 9
  5. CONST EDITOR = "notepad"
  6. CONST FILE = "steps.txt"
  7. CONST NUMBERS = "123456789"
  8.  
  9. DIM SHARED BLOCK(1 TO RANK2, 1 TO RANK2, 1 TO RANK2)
  10. DIM SHARED PART(1 TO RANK2, 1 TO RANK2)
  11. OPEN FILE FOR OUTPUT AS #1
  12.  
  13.   PRINT "Which character would you like to use to represent blank (empty squares)? ";
  14.   LINE INPUT BLANK$
  15.   BLANK$ = LEFT$(LTRIM$(RTRIM$(BLANK$)), 1)
  16.   IF BLANK$ = "" THEN BLANK$ = " "
  17. LOOP UNTIL INSTR(NUMBERS, BLANK$) = 0
  18. PRINT "Enter your puzzle in plain text form.  Only numbers (1-9) and blanks have"
  19. PRINT "significance. All other characters are ignored.  This means that the puzzle"
  20. PRINT "may be input all on one line or with line breaks, spaces, and ASCII art to"
  21. PRINT "mark block boundaries or beautify your input."
  22. NUMLEFT = 81
  23. I = 1
  24. J = 0
  25.   FOR N = 1 TO LEN(LINE$)
  26.     X$ = MID$(LINE$, N, 1)
  27.     IF X$ = BLANK$ OR INSTR(NUMBERS, X$) THEN
  28.       J = J + 1
  29.       IF J > 9 THEN J = 1: I = I + 1
  30.       PART(I, J) = INSTR(NUMBERS, X$)
  31.       NUMLEFT = NUMLEFT - 1
  32.     END IF
  33.   NEXT
  34. LOOP UNTIL NUMLEFT = 0
  35. FOR ROW = 1 TO RANK2
  36.   FOR COL = 1 TO RANK2
  37.     FOR I = 1 TO RANK2
  38.       IF PART(ROW, COL) = 0 THEN
  39.         BLOCK(ROW, COL, I) = I
  40.       END IF
  41.     NEXT
  42.   NEXT
  43.  
  44. CALL UPDATEBOARD
  45. FOR ROW = 1 TO RANK2
  46.     FOR VALL = 1 TO RANK2
  47.       COUNT = 0
  48.       FOR I = 1 TO RANK2
  49.         IF BLOCK(ROW, I, VALL) = VALL THEN COUNT = COUNT + 1
  50.       NEXT
  51.       IF COUNT = 1 THEN
  52.         FOR COL = 1 TO RANK2
  53.           IF PART(ROW, COL) <> 0 THEN GOTO 2
  54.           IF BLOCK(ROW, COL, VALL) = VALL THEN
  55.               PART(ROW, COL) = VALL
  56.               PRINT #1, "Only one instance of"; VALL; "in row"; ROW; "-- inserting at column"; COL
  57.               FOR I = 1 TO RANK2
  58.                 BLOCK(ROW, COL, I) = 0
  59.               NEXT
  60.               CALL UPDATEBOARD
  61.               GOTO 4
  62.           END IF
  63. 2       NEXT
  64.       ELSE
  65.         BLK = -1
  66.         FOR COL = 1 TO RANK2
  67.           OLDBLK = BLK
  68.           IF BLOCK(ROW, COL, VALL) = VALL THEN BLK = INT((COL - 1) / RANK)
  69.           IF OLDBLK >= 0 AND BLK <> OLDBLK THEN GOTO 3
  70.         NEXT
  71.         IF BLK = -1 THEN GOTO 3
  72.         FOR I = INT((ROW - 1) / RANK) * RANK + 1 TO INT((ROW - 1) / RANK) * RANK + RANK
  73.           FOR J = BLK * RANK + 1 TO BLK * RANK + RANK
  74.             IF I <> ROW AND BLOCK(I, J, VALL) <> 0 THEN
  75.               BLOCK(I, J, VALL) = 0
  76.               PRINT #1, "Eliminating"; VALL; "from"; I; J; "because it must be in row"; ROW; "in same block"
  77.             END IF
  78.           NEXT
  79.         NEXT
  80.       END IF
  81. 3   NEXT
  82. FOR COL = 1 TO RANK2
  83.     FOR VALL = 1 TO RANK2
  84.       COUNT = 0
  85.       FOR I = 1 TO RANK2
  86.         IF BLOCK(I, COL, VALL) = VALL THEN COUNT = COUNT + 1
  87.       NEXT
  88.       IF COUNT = 1 THEN
  89.         FOR ROW = 1 TO RANK2
  90.           IF PART(ROW, COL) <> 0 THEN GOTO 5
  91.           IF BLOCK(ROW, COL, VALL) = VALL THEN
  92.             PART(ROW, COL) = VALL
  93.             PRINT #1, "Only one instance of"; VALL; "in column"; COL; "-- inserting at row"; ROW
  94.             FOR I = 1 TO RANK2
  95.               BLOCK(ROW, COL, I) = 0
  96.             NEXT
  97.             CALL UPDATEBOARD
  98.             GOTO 7
  99.           END IF
  100. 5       NEXT
  101.       ELSE
  102.         BLK = -1
  103.         FOR ROW = 1 TO RANK2
  104.           OLDBLK = BLK
  105.           IF BLOCK(ROW, COL, VALL) = VALL THEN BLK = INT((ROW - 1) / RANK)
  106.           IF OLDBLK >= 0 AND BLK <> OLDBLK THEN GOTO 6
  107.         NEXT
  108.         IF BLK = -1 THEN GOTO 6
  109.         FOR I = BLK * RANK + 1 TO BLK * RANK + RANK
  110.           FOR J = INT((COL - 1) / RANK) * RANK + 1 TO INT((COL - 1) / RANK) * RANK + RANK
  111.             IF J <> COL AND BLOCK(I, J, VALL) <> 0 THEN
  112.               BLOCK(I, J, VALL) = 0
  113.               PRINT #1, "Eliminating"; VALL; "from"; I; J; "because is must be in col"; COL; "in same block"
  114.             END IF
  115.           NEXT
  116.         NEXT
  117.       END IF
  118. 6    NEXT
  119. FOR I = 0 TO RANK - 1
  120.   FOR J = 0 TO RANK - 1
  121.     FOR VALL = 1 TO RANK2
  122.       COUNT = 0
  123.       FOR K = I * RANK + 1 TO I * RANK + RANK
  124.         FOR L = J * RANK + 1 TO J * RANK + RANK
  125.           IF BLOCK(K, L, VALL) = VALL THEN COUNT = COUNT + 1
  126.         NEXT
  127.       NEXT
  128.       IF COUNT <> 1 THEN GOTO 9
  129.       FOR K = I * RANK + 1 TO I * RANK + RANK
  130.         FOR L = J * RANK + 1 TO J * RANK + RANK
  131.           IF PART(K, L) <> 0 THEN GOTO 8
  132.           IF BLOCK(K, L, VALL) = VALL THEN
  133.             PART(K, L) = VALL
  134.             PRINT #1, "Only one instance of"; VALL; "in box -- inserting at row"; K; "column"; L
  135.             FOR M = 1 TO RANK2
  136.               BLOCK(K, L, M) = 0
  137.             NEXT
  138.             CALL UPDATEBOARD
  139.             GOTO 9
  140.           END IF
  141. 8       NEXT
  142.       NEXT
  143. 9   NEXT
  144. 10  NEXT
  145. FOR ROW = 1 TO RANK2
  146.   FOR COL = 1 TO RANK2
  147.     IF PART(ROW, COL) <> 0 THEN GOTO 11
  148.     COUNT = 0
  149.     FOR VALL = 1 TO RANK2
  150.       IF BLOCK(ROW, COL, VALL) = VALL THEN COUNT = COUNT + 1
  151.     NEXT
  152.     IF COUNT = 1 THEN
  153.       FOR VALL = 1 TO RANK2
  154.         IF BLOCK(ROW, COL, VALL) = VALL THEN
  155.           PRINT #1, "Only"; VALL; "may be legally inserted at"; ROW; "column"; COL
  156.           PART(ROW, COL) = VALL
  157.           FOR I = 1 TO RANK2
  158.             BLOCK(ROW, COL, I) = 0
  159.           NEXT
  160.           CALL UPDATEBOARD
  161.           EXIT FOR
  162.         END IF
  163.       NEXT
  164.     ELSEIF COUNT = 2 THEN
  165.       FOR COL2 = 1 TO RANK2
  166.         EXACT = -1
  167.         FOR J = 1 TO RANK2
  168.           IF BLOCK(ROW, COL2, J) <> BLOCK(ROW, COL, J) OR COL2 = COL THEN EXACT = 0: EXIT FOR
  169.         NEXT
  170.         IF EXACT THEN
  171.           FOR I = 1 TO RANK2
  172.             IF (I <> COL) AND (I <> COL2) THEN
  173.               FOR J = 1 TO RANK2
  174.                 IF BLOCK(ROW, I, J) = BLOCK(ROW, COL, J) AND BLOCK(ROW, I, J) <> 0 THEN
  175.                   PRINT #1, "Eliminating "; J; "from"; ROW; I; "b/c naked pair at"; ROW; COL; "and"; ROW; COL2
  176.                   BLOCK(ROW, I, J) = 0
  177.                 END IF
  178.               NEXT
  179.             END IF
  180.           NEXT
  181.           EXIT FOR
  182.         END IF
  183.       NEXT
  184.       FOR ROW2 = 1 TO RANK2
  185.         EXACT = -1
  186.         FOR J = 1 TO RANK2
  187.           IF BLOCK(ROW2, COL, J) <> BLOCK(ROW, COL, J) OR ROW2 = ROW THEN EXACT = 0: EXIT FOR
  188.         NEXT
  189.         IF EXACT THEN
  190.           FOR I = 1 TO RANK2
  191.             IF (I <> ROW) AND (I <> ROW2) THEN
  192.               FOR J = 1 TO RANK2
  193.                 IF BLOCK(I, COL, J) = BLOCK(ROW, COL, J) AND BLOCK(I, COL, J) <> 0 THEN
  194.                   BLOCK(I, COL, J) = 0
  195.                   PRINT #1, "Eliminating "; J; "from"; I; COL; "b/c naked pair at"; ROW; COL; "and"; ROW2; COL
  196.                 END IF
  197.               NEXT
  198.             END IF
  199.           NEXT
  200.           EXIT FOR
  201.         END IF
  202.       NEXT
  203.       FOR I = INT((ROW - 1) / RANK) * RANK + 1 TO INT((ROW - 1) / RANK) * RANK + RANK
  204.         FOR J = INT((COL - 1) / RANK) * RANK + 1 TO INT((COL - 1) / RANK) * RANK + RANK
  205.           EXACT = -1
  206.           FOR K = 1 TO RANK2
  207.             IF (BLOCK(I, J, K) <> BLOCK(ROW, COL, K)) OR (I = ROW AND J = COL) THEN EXACT = 0: EXIT FOR
  208.           NEXT
  209.           IF EXACT THEN
  210.             FOR M = INT((ROW - 1) / RANK) * RANK + 1 TO INT((ROW - 1) / RANK) * RANK + RANK
  211.               FOR N = INT((COL - 1) / RANK) * RANK + 1 TO INT((COL - 1) / RANK) * RANK + RANK
  212.                 IF ((M <> ROW OR N <> COL) AND (M <> I OR N <> J)) THEN
  213.                   FOR K = 1 TO RANK2
  214.                     IF BLOCK(ROW, COL, K) = BLOCK(M, N, K) AND BLOCK(M, N, K) <> 0 THEN
  215.                       BLOCK(M, N, K) = 0
  216.                       PRINT #1, "Eliminating "; K; "from"; M; N; "b/c naked pair at"; ROW; COL; "and"; I; J
  217.                     END IF
  218.                   NEXT
  219.                 END IF
  220.               NEXT
  221.             NEXT
  222.           GOTO 11
  223.           END IF
  224.         NEXT
  225.       NEXT
  226.     ELSE
  227.       GOTO 11
  228.     END IF
  229. 11 NEXT
  230. OLDSUM = SUM
  231. SUM = 0
  232. SOLVED = -1
  233. FOR I = 1 TO RANK2
  234.   FOR J = 1 TO RANK2
  235.     FOR K = 1 TO RANK2
  236.       IF PART(I, J) = 0 THEN SOLVED = 0
  237.       SUM = SUM + BLOCK(I, J, K)
  238.     NEXT
  239.   NEXT
  240. IF SOLVED THEN
  241.   PRINT "Solution Found!"
  242.   PRINT #1, "Solution Found!"
  243.   EXIT DO
  244. ELSEIF SUM = OLDSUM THEN
  245.   PRINT "I seem to be stuck. Work so far:"
  246.   EXIT DO
  247. FOR I = 1 TO RANK2
  248.   FOR J = 1 TO RANK2
  249.     PRINT PART(I, J);
  250.     PRINT #1, PART(I, J);
  251.   NEXT
  252.   PRINT #1, ""
  253. PRINT "Press ESCAPE to quit or any other key to see the steps"
  254. PRINT "used to reach this point."
  255. NULL$ = INPUT$(1)
  256. IF NULL$ = CHR$(27) THEN
  257.   SHELL EDITOR + CHR$(32) + FILE
  258.  
  259. SUB UPDATEBOARD
  260. FOR ROW = 1 TO RANK2
  261.   FOR COL = 1 TO RANK2
  262.     IF PART(ROW, COL) = 0 THEN GOTO 1
  263.     FOR I = 1 TO RANK2
  264.       IF BLOCK(ROW, I, PART(ROW, COL)) = PART(ROW, COL) THEN
  265.         BLOCK(ROW, I, PART(ROW, COL)) = 0
  266.       END IF
  267.       IF BLOCK(I, COL, PART(ROW, COL)) = PART(ROW, COL) THEN
  268.         BLOCK(I, COL, PART(ROW, COL)) = 0
  269.       END IF
  270.     NEXT
  271.     FOR I = INT((ROW - 1) / RANK) * RANK + 1 TO INT((ROW - 1) / RANK) * RANK + RANK
  272.       FOR J = INT((COL - 1) / RANK) * RANK + 1 TO INT((COL - 1) / RANK) * RANK + RANK
  273.         IF BLOCK(I, J, PART(ROW, COL)) = PART(ROW, COL) THEN
  274.           BLOCK(I, J, PART(ROW, COL)) = 0
  275.         END IF
  276.       NEXT
  277.     NEXT
  278.  

2
Programs / Re: MicroSoft's version of Reversi
« on: October 29, 2018, 09:38:13 am »
My own version has a better AI than Microsoft's: https://www.qb64.org/forum/index.php?topic=677.0
The hereustics are still pretty basic though, just counting squares with some weights.

3
Programs / MicroSoft's version of Reversi
« on: October 29, 2018, 08:50:58 am »
Code: QB64: [Select]
  1. REM This is a sample QBASIC program from MS-DOS 5 (June 1990)
  2. DEFINT A-Z
  3.  
  4. DECLARE FUNCTION CheckPath% (i, IBound, IStep, j, JBound, JStep, Opponent)
  5. DECLARE FUNCTION ValidMove% (Opponent)
  6. DECLARE SUB ComputerMove ()
  7. DECLARE SUB DisplayHelp ()
  8. DECLARE SUB DisplayMsg (a$)
  9. DECLARE SUB DrawCursor (row, col)
  10. DECLARE SUB DrawGamePiece (row, col, PieceColor)
  11. DECLARE SUB GameOver ()
  12. DECLARE SUB InitGame ()
  13. DECLARE SUB TakeBlocks (row, col, player)
  14. DECLARE SUB UpdateScore ()
  15. DECLARE SUB UserMove ()
  16. DECLARE SUB DrawGameBoard ()
  17.  
  18. CONST TRUE = -1
  19. CONST FALSE = 0
  20. CONST QUIT = 113
  21. CONST UP = 72
  22. CONST DOWN = 80
  23. CONST LEFT = 75
  24. CONST RIGHT = 77
  25. CONST BBLOCK = 1
  26. CONST EBLOCK = 8
  27. CONST ENTER = 13
  28. CONST ULEFT = 71
  29. CONST URIGHT = 73
  30. CONST DLEFT = 79
  31. CONST DRIGHT = 81
  32. CONST PASS = 112
  33. CONST DIFF = 100
  34. CONST START = 115
  35. CONST HELP = 104
  36. CONST FMOVE = 99
  37. CONST SPACE = 32
  38.  
  39. TYPE GameGrid
  40.     player AS INTEGER
  41.     nTake  AS INTEGER
  42.     cx     AS INTEGER
  43.     cy     AS INTEGER
  44.  
  45. TYPE GameStatus
  46.     curRow   AS INTEGER
  47.     curCol   AS INTEGER
  48.     stat     AS INTEGER
  49.     rScore   AS INTEGER
  50.     bScore   AS INTEGER
  51.     mDisplay AS INTEGER
  52.     dLevel   AS STRING * 6
  53.     GColor   AS INTEGER
  54.  
  55. DIM SHARED GS AS GameStatus, smode AS INTEGER
  56. DIM SHARED GG(8, 8) AS GameGrid, GBoard AS INTEGER
  57. DIM SHARED GP(8, 8, 8) AS INTEGER, GW(8, 8) AS INTEGER
  58.  
  59. ON ERROR GOTO BadMode
  60.  
  61.   READ smode
  62.   vmode = TRUE
  63.   SCREEN smode
  64. LOOP UNTIL vmode = TRUE
  65.  
  66. IF smode = 0 THEN
  67.   CLS
  68.   LOCATE 10, 15: PRINT "No graphics screen mode available; cannot run REVERSI.BAS"
  69.   GS.stat = START
  70.   GS.dLevel = "Novice"
  71.   WHILE GS.stat <> QUIT
  72.     IF GS.stat = START THEN
  73.       InitGame
  74.       DrawGameBoard
  75.     END IF
  76.     IF GS.stat <> COMP THEN
  77.       IF ValidMove(COMP) THEN
  78.         UserMove
  79.       ELSEIF ValidMove(HUMAN) THEN
  80.         DO
  81.           DisplayMsg "You have no valid moves.  Select pass."
  82.           DO
  83.             a$ = INKEY$
  84.           LOOP UNTIL a$ <> ""
  85.         LOOP UNTIL ASC(RIGHT$(a$, 1)) = PASS
  86.         LINE (0, 420)-(640, 447), 3, BF
  87.         GS.mDisplay = FALSE
  88.         GS.stat = COMP
  89.         ComputerMove
  90.       ELSE
  91.         GameOver
  92.       END IF
  93.     ELSE
  94.       IF ValidMove(HUMAN) THEN
  95.         ComputerMove
  96.       ELSEIF ValidMove(COMP) THEN
  97.         DisplayMsg "Computer has no valid moves.  Your Turn."
  98.         GS.stat = HUMAN
  99.         UserMove
  100.       ELSE
  101.         GameOver
  102.       END IF
  103.     END IF
  104.   WEND
  105.   DisplayMsg "Game Over"
  106.  
  107. DATA 9, 10, 2, 3, 0
  108.  
  109. BadMode:
  110.   vmode = FALSE
  111.  
  112.  
  113. FUNCTION CheckPath (i, IBound, IStep, j, JBound, JStep, Opponent)
  114.  
  115.   done = FALSE
  116.   WHILE (i <> IBound OR j <> JBound) AND NOT done
  117.     IF GG(i, j).player = GBoard THEN
  118.       count = 0
  119.       done = TRUE
  120.     ELSEIF GG(i, j).player = Opponent THEN
  121.       count = count + 1
  122.       i = i + IStep
  123.       j = j + JStep
  124.       IF (i < 1 OR i > 8) OR (j < 1 OR j > 8) THEN
  125.         count = 0
  126.         done = TRUE
  127.       END IF
  128.     ELSE
  129.       done = TRUE
  130.     END IF
  131.   WEND
  132.   CheckPath = count
  133.    
  134.  
  135. SUB ComputerMove
  136.   BestMove = -99
  137.   FOR row = 1 TO 8
  138.     FOR col = 1 TO 8
  139.       IF GG(row, col).nTake > 0 THEN
  140.         IF GS.dLevel = "Novice" THEN
  141.           value = GG(row, col).nTake + GW(row, col)
  142.         ELSE
  143.           value = GG(row, col).nTake + GW(row, col)
  144.           SELECT CASE row
  145.             CASE 1
  146.               IF col < 5 THEN value = value + ABS(10 * GG(1, 1).player = COMP)
  147.               IF col > 4 THEN value = value + ABS(10 * GG(1, 8).player = COMP)
  148.             CASE 2
  149.               IF GG(1, col).player <> COMP THEN value = value + 5 * (GG(1, col).player = HUMAN)
  150.               IF col > 1 AND GG(1, col - 1).player <> COMP THEN value = value + 5 * (GG(1, col - 1).player = HUMAN)
  151.               IF col < 8 AND GG(1, col + 1).player <> COMP THEN value = value + 5 * (GG(1, col + 1).player = HUMAN)
  152.             CASE 7
  153.               IF GG(8, col).player <> COMP THEN value = value + 5 * (GG(8, col).player = HUMAN)
  154.               IF col > 1 AND GG(8, col - 1).player <> COMP THEN value = value + 5 * (GG(8, col - 1).player = HUMAN)
  155.               IF col < 8 AND GG(8, col + 1).player <> COMP THEN value = value + 5 * (GG(8, col + 1).player = HUMAN)
  156.             CASE 8
  157.               IF col < 5 THEN value = value + ABS(10 * GG(8, 1).player = COMP)
  158.               IF col > 4 THEN value = value + ABS(10 * GG(8, 8).player = COMP)
  159.           END SELECT
  160.           SELECT CASE col
  161.             CASE 1
  162.               IF row < 5 THEN value = value + ABS(10 * GG(1, 1).player = COMP)
  163.               IF row > 4 THEN value = value + ABS(10 * GG(8, 1).player = COMP)
  164.             CASE 2
  165.               IF GG(row, 1).player <> COMP THEN value = value + 5 * (GG(row, 1).player = HUMAN)
  166.               IF row > 1 AND GG(row - 1, 1).player <> COMP THEN value = value + 5 * (GG(row - 1, 1).player = HUMAN)
  167.               IF row < 8 AND GG(row + 1, 1).player <> COMP THEN value = value + 5 * (GG(row + 1, 1).player = HUMAN)
  168.             CASE 7
  169.               IF GG(row, 8).player <> COMP THEN value = value + 5 * (GG(row, 8).player = HUMAN)
  170.               IF row > 1 AND GG(row - 1, 8).player <> COMP THEN value = value + 5 * (GG(row - 1, 8).player = HUMAN)
  171.               IF row < 8 AND GG(row + 1, 8).player <> COMP THEN value = value + 5 * (GG(row + 1, 8).player = HUMAN)
  172.             CASE 8
  173.               IF row < 5 THEN value = value + ABS(10 * GG(1, 8).player = COMP)
  174.               IF row > 4 THEN value = value + ABS(10 * GG(8, 8).player = COMP)
  175.           END SELECT
  176.         END IF
  177.         IF value > BestMove THEN
  178.           BestMove = value
  179.           bestrow = row
  180.           bestcol = col
  181.         END IF
  182.       END IF
  183.     NEXT col
  184.   NEXT row
  185.  
  186.   TakeBlocks bestrow, bestcol, COMP
  187.   GS.stat = HUMAN
  188.  
  189.  
  190. SUB DisplayHelp
  191.  
  192.   DIM a$(1 TO 18)
  193.  
  194.   a$(1) = "The object of Reversi is to finish the game with more of your red"
  195.   a$(2) = "circles on the board than the computer has of blue (Monochrome"
  196.   a$(3) = "monitors will show red as white and blue as black)."
  197.   a$(4) = ""
  198.   a$(5) = "1) You and the computer play by the same rules."
  199.   a$(6) = "2) To make a legal move, at least one of the computer's circles"
  200.   a$(7) = "   must lie in a horizontal, vertical, or diagonal line between"
  201.   a$(8) = "   one of your existing circles and the square where you want to"
  202.   a$(9) = "   move.  Use the arrow keys to position the cursor on the square"
  203.   a$(10) = "   and hit Enter or the Space Bar."
  204.   a$(11) = "3) You can choose Pass from the game controls menu on your first"
  205.   a$(12) = "   move to force the computer to play first."
  206.   a$(13) = "4) After your first move, you cannot pass if you can make a legal"
  207.   a$(14) = "   move."
  208.   a$(15) = "5) If you cannot make a legal move, you must choose Pass"
  209.   a$(16) = "6) When neither you nor the computer can make a legal move, the"
  210.   a$(17) = "   game is over."
  211.   a$(18) = "7) The one with the most circles wins."
  212.  
  213.   LINE (0, 0)-(640, 480), BG, BF
  214.   LINE (39, 15)-(590, 450), 0, B
  215.   IF GBoard = 85 THEN
  216.     PAINT (200, 200), CHR$(85), 0
  217.   ELSE
  218.     PAINT (200, 200), GBoard, 0
  219.   END IF
  220.   LINE (590, 25)-(600, 460), 0, BF
  221.   LINE (50, 450)-(600, 460), 0, BF
  222.  
  223.   LOCATE 2, 35: PRINT "REVERSI HELP"
  224.   FOR i = 1 TO 18
  225.     LOCATE 3 + i, 7
  226.     PRINT a$(i)
  227.   NEXT i
  228.   LOCATE 23, 25: PRINT "- Press any key to continue -"
  229.   SLEEP: a$ = INKEY$
  230.   DrawGameBoard
  231.   DrawCursor GS.curRow, GS.curCol
  232.  
  233.  
  234. SUB DisplayMsg (a$)
  235.  
  236.   slen = LEN(a$)
  237.   LX = (640 - 8 * (slen + 8)) / 2
  238.   LINE (LX - 1, 420)-(640 - LX, 447), 0, B
  239.   IF GBoard = 85 THEN
  240.     PAINT (LX + 10, 430), CHR$(85), 0
  241.   ELSE
  242.     PAINT (LX + 10, 430), GBoard, 0
  243.   END IF
  244.   LOCATE 23, (80 - slen) / 2
  245.   PRINT a$;
  246.   GS.mDisplay = TRUE
  247.  
  248.  
  249. SUB DrawCursor (row, col)
  250.   IF GG(row, col).nTake > 0 THEN
  251.     CIRCLE (GG(row, col).cx, GG(row, col).cy), 15, HUMAN
  252.     CIRCLE (GG(row, col).cx, GG(row, col).cy), 14, HUMAN
  253.   ELSE
  254.     lc = 0
  255.     IF GG(row, col).player = 0 THEN lc = 7
  256.     LINE (GG(row, col).cx, GG(row, col).cy - 15)-(GG(row, col).cx, GG(row, col).cy + 15), lc
  257.     LINE (GG(row, col).cx - 1, GG(row, col).cy - 15)-(GG(row, col).cx - 1, GG(row, col).cy + 15), lc
  258.     LINE (GG(row, col).cx + 15, GG(row, col).cy)-(GG(row, col).cx - 15, GG(row, col).cy), lc
  259.   END IF
  260.  
  261. SUB DrawGameBoard
  262.  
  263.   LINE (0, 0)-(640, 480), BG, BF
  264.   LINE (239, 15)-(400, 40), 0, B
  265.   LINE (39, 260)-(231, 390), 0, B
  266.   LINE (39, 70)-(231, 220), 0, B
  267.   LINE (269, 70)-(591, 390), 0, B
  268.  
  269.   IF GBoard = 85 THEN                  'If b&w
  270.     PAINT (300, 25), CHR$(85), 0
  271.     PAINT (150, 350), CHR$(85), 0
  272.     PAINT (150, 124), CHR$(85), 0
  273.     PAINT (450, 225), CHR$(85), 0
  274.   ELSE
  275.     PAINT (300, 25), GBoard, 0
  276.     PAINT (150, 350), GBoard, 0
  277.     PAINT (150, 124), GBoard, 0
  278.     PAINT (450, 225), GBoard, 0
  279.   END IF
  280.   LINE (400, 25)-(410, 50), 0, BF
  281.   LINE (250, 40)-(410, 50), 0, BF
  282.   LINE (231, 80)-(240, 230), 0, BF
  283.   LINE (50, 220)-(240, 230), 0, BF
  284.   LINE (590, 80)-(600, 400), 0, BF
  285.   LINE (280, 390)-(600, 400), 0, BF
  286.   LINE (231, 270)-(240, 400), 0, BF
  287.   LINE (50, 390)-(240, 400), 0, BF
  288.  
  289.   FOR i = 0 TO 8
  290.     LINE (270, 70 + i * 40)-(590, 70 + i * 40), 0
  291.     LINE (270 + i * 40, 70)-(270 + i * 40, 390), 0
  292.     LINE (269 + i * 40, 70)-(269 + i * 40, 390), 0
  293.   NEXT i
  294.  
  295.   LOCATE 2, 35: PRINT "R E V E R S I"
  296.  
  297.   LOCATE 5, 11: PRINT "Game Controls"
  298.   LOCATE 7, 7: PRINT "S = Start New Game"
  299.   LOCATE 8, 7: PRINT "P = Pass Turn"
  300.   LOCATE 9, 7: PRINT "D = Set Difficulty"
  301.   LOCATE 10, 7: PRINT "H = Display Help"
  302.   LOCATE 11, 7: PRINT "Q = Quit"
  303.   LOCATE 15, 12: PRINT "Game Status"
  304.   LOCATE 17, 7: PRINT "Your Score:      "; GS.rScore; ""
  305.   LOCATE 18, 7: PRINT "Computer Score:  "; GS.bScore
  306.   LOCATE 20, 7: PRINT "Difficulty:   "; GS.dLevel
  307.  
  308.   FOR row = 1 TO 8
  309.     FOR col = 1 TO 8
  310.       IF GG(row, col).player <> GBoard THEN
  311.         DrawGamePiece row, col, GG(row, col).player
  312.       END IF
  313.     NEXT col
  314.   NEXT row
  315.  
  316.  
  317. SUB DrawGamePiece (row, col, GpColor)
  318.  
  319.   IF GBoard = 85 THEN
  320.     LINE (232 + col * 40, 33 + row * 40)-(267 + col * 40, 67 + row * 40), 7, BF
  321.     IF GpColor <> GBoard THEN
  322.       CIRCLE (GG(row, col).cx, GG(row, col).cy), 15, 0
  323.       PAINT (GG(row, col).cx, GG(row, col).cy), GpColor, 0
  324.     END IF
  325.     PAINT (235 + col * 40, 35 + row * 40), CHR$(85), 0
  326.   ELSE
  327.     CIRCLE (GG(row, col).cx, GG(row, col).cy), 15, GpColor
  328.     CIRCLE (GG(row, col).cx, GG(row, col).cy), 14, GpColor
  329.     PAINT (GG(row, col).cx, GG(row, col).cy), GpColor, GpColor
  330.   END IF
  331.  
  332.  
  333. SUB GameOver
  334.   Scorediff = GS.rScore - GS.bScore
  335.   IF Scorediff = 0 THEN
  336.     DisplayMsg "Tie Game"
  337.   ELSEIF Scorediff < 0 THEN
  338.     DisplayMsg "You lost by"
  339.     PRINT ABS(Scorediff)
  340.   ELSE
  341.     DisplayMsg "You won by"
  342.     PRINT Scorediff
  343.   END IF
  344.   DO
  345.     GS.stat = ASC(RIGHT$(INKEY$, 1))
  346.   LOOP UNTIL GS.stat = QUIT OR GS.stat = START
  347.   LINE (0, 420)-(640, 447), BG, BF
  348.  
  349. SUB InitGame
  350.   SELECT CASE smode
  351.     CASE 9:
  352.       HUMAN = 4
  353.       COMP = 1
  354.       BG = 3
  355.       GBoard = 8
  356.     CASE ELSE:
  357.       HUMAN = 7
  358.       COMP = 0
  359.       BG = 7
  360.       IF smode = 10 THEN
  361.         GBoard = 1
  362.       ELSE
  363.         GBoard = 85
  364.       END IF
  365.  
  366.   WINDOW SCREEN (640, 480)-(0, 0)
  367.   GS.curCol = 5
  368.   GS.curRow = 3
  369.   GS.stat = FMOVE
  370.   GS.bScore = 2
  371.   GS.rScore = 2
  372.   GS.mDisplay = FALSE
  373.  
  374.   FOR row = 1 TO 8
  375.     FOR col = 1 TO 8
  376.       GG(row, col).player = GBoard
  377.       GG(row, col).nTake = 0
  378.       GG(row, col).cx = 270 + (col - .5) * 40
  379.       GG(row, col).cy = 70 + (row - .5) * 40
  380.       GW(row, col) = 2
  381.     NEXT col
  382.   NEXT row
  383.   GW(1, 1) = 99
  384.   GW(1, 8) = 99
  385.   GW(8, 1) = 99
  386.   GW(8, 8) = 99
  387.   FOR i = 3 TO 6
  388.     FOR j = 1 TO 8 STEP 7
  389.       GW(i, j) = 5
  390.       GW(j, i) = 5
  391.     NEXT j
  392.   NEXT i
  393.   GG(4, 4).player = HUMAN
  394.   GG(5, 4).player = COMP
  395.   GG(4, 5).player = COMP
  396.   GG(5, 5).player = HUMAN
  397.  
  398. SUB TakeBlocks (row, col, player)
  399.  
  400.   GG(row, col).player = player
  401.   DrawGamePiece row, col, player
  402.  
  403.   FOR i = 1 TO GP(row, col, 1)
  404.     GG(row, col - i).player = player
  405.     DrawGamePiece row, col - i, player
  406.   NEXT i
  407.   FOR i = 1 TO GP(row, col, 2)
  408.     GG(row, col + i).player = player
  409.     DrawGamePiece row, col + i, player
  410.   NEXT i
  411.   FOR i = 1 TO GP(row, col, 3)
  412.     GG(row - i, col).player = player
  413.     DrawGamePiece row - i, col, player
  414.   NEXT i
  415.   FOR i = 1 TO GP(row, col, 4)
  416.     GG(row + i, col).player = player
  417.     DrawGamePiece row + i, col, player
  418.   NEXT i
  419.   FOR i = 1 TO GP(row, col, 5)
  420.     GG(row - i, col - i).player = player
  421.     DrawGamePiece row - i, col - i, player
  422.   NEXT i
  423.   FOR i = 1 TO GP(row, col, 6)
  424.     GG(row + i, col + i).player = player
  425.     DrawGamePiece row + i, col + i, player
  426.   NEXT i
  427.   FOR i = 1 TO GP(row, col, 7)
  428.     GG(row - i, col + i).player = player
  429.     DrawGamePiece row - i, col + i, player
  430.   NEXT i
  431.   FOR i = 1 TO GP(row, col, 8)
  432.     GG(row + i, col - i).player = player
  433.     DrawGamePiece row + i, col - i, player
  434.   NEXT i
  435.  
  436.   IF player = HUMAN THEN
  437.     GS.rScore = GS.rScore + GG(row, col).nTake + 1
  438.     GS.bScore = GS.bScore - GG(row, col).nTake
  439.   ELSE
  440.     GS.bScore = GS.bScore + GG(row, col).nTake + 1
  441.     GS.rScore = GS.rScore - GG(row, col).nTake
  442.   END IF
  443.  
  444.   LOCATE 17, 7: PRINT "Your Score:      "; GS.rScore
  445.   LOCATE 18, 7: PRINT "Computer Score:  "; GS.bScore
  446.  
  447.  
  448. SUB UserMove
  449.  
  450.   DrawCursor GS.curRow, GS.curCol
  451.   DO
  452.     DO
  453.       a$ = INKEY$
  454.     LOOP UNTIL a$ <> ""
  455.     move = ASC(RIGHT$(a$, 1))
  456.     IF GS.mDisplay THEN
  457.       LINE (0, 420)-(640, 447), BG, BF
  458.       GS.mDisplay = FALSE
  459.     END IF
  460.     SELECT CASE move
  461.       CASE 71 TO 81:
  462.         DrawGamePiece GS.curRow, GS.curCol, GG(GS.curRow, GS.curCol).player
  463.         IF move < 74 THEN
  464.           IF GS.curRow = BBLOCK THEN
  465.             GS.curRow = EBLOCK
  466.           ELSE
  467.             GS.curRow = GS.curRow - 1
  468.           END IF
  469.         ELSEIF move > 78 THEN
  470.           IF GS.curRow = EBLOCK THEN
  471.             GS.curRow = BBLOCK
  472.           ELSE
  473.             GS.curRow = GS.curRow + 1
  474.           END IF
  475.         END IF
  476.         IF move = 71 OR move = 75 OR move = 79 THEN
  477.           IF GS.curCol = BBLOCK THEN
  478.             GS.curCol = EBLOCK
  479.           ELSE
  480.             GS.curCol = GS.curCol - 1
  481.           END IF
  482.         ELSEIF move = 73 OR move = 77 OR move = 81 THEN
  483.           IF GS.curCol = EBLOCK THEN
  484.             GS.curCol = BBLOCK
  485.           ELSE
  486.             GS.curCol = GS.curCol + 1
  487.           END IF
  488.         END IF
  489.         DrawCursor GS.curRow, GS.curCol
  490.       CASE START:
  491.         GS.stat = START
  492.       CASE PASS:
  493.         IF GS.stat = FMOVE THEN
  494.           DisplayMsg "You passed.  Computer will make first move."
  495.           GS.stat = COMP
  496.         ELSE
  497.           DisplayMsg "You can only pass on your first turn."
  498.         END IF
  499.       CASE HELP:
  500.         DisplayHelp
  501.       CASE DIFF:
  502.         IF GS.dLevel = "Novice" THEN
  503.           GS.dLevel = "Expert"
  504.         ELSE
  505.           GS.dLevel = "Novice"
  506.         END IF
  507.         LOCATE 20, 7
  508.         PRINT "Difficulty:   "; GS.dLevel;
  509.       CASE ENTER, SPACE:
  510.         IF GG(GS.curRow, GS.curCol).nTake > 0 THEN
  511.           TakeBlocks GS.curRow, GS.curCol, HUMAN
  512.           GS.stat = COMP
  513.         ELSE
  514.           DisplayMsg "Invalid move.  Move to a space where the cursor is a circle."
  515.         END IF
  516.       CASE QUIT:
  517.         GS.stat = QUIT
  518.     END SELECT
  519.   LOOP UNTIL GS.stat <> HUMAN AND GS.stat <> FMOVE
  520.  
  521.  
  522. FUNCTION ValidMove (Opponent)
  523.  
  524.   ValidMove = FALSE
  525.   ERASE GP
  526.   FOR row = 1 TO 8
  527.     FOR col = 1 TO 8
  528.       GG(row, col).nTake = 0
  529.  
  530.       IF GG(row, col).player = GBoard THEN
  531.         IF col > 2 THEN
  532.           GP(row, col, 1) = CheckPath(row, row, 0, col - 1, 0, -1, Opponent)
  533.           GG(row, col).nTake = GG(row, col).nTake + GP(row, col, 1)
  534.         END IF
  535.         IF col < 7 THEN
  536.           GP(row, col, 2) = CheckPath(row, row, 0, col + 1, 9, 1, Opponent)
  537.           GG(row, col).nTake = GG(row, col).nTake + GP(row, col, 2)
  538.         END IF
  539.         IF row > 2 THEN
  540.           GP(row, col, 3) = CheckPath(row - 1, 0, -1, col, col, 0, Opponent)
  541.           GG(row, col).nTake = GG(row, col).nTake + GP(row, col, 3)
  542.         END IF
  543.         IF row < 7 THEN
  544.           GP(row, col, 4) = CheckPath(row + 1, 9, 1, col, col, 0, Opponent)
  545.           GG(row, col).nTake = GG(row, col).nTake + GP(row, col, 4)
  546.         END IF
  547.         IF col > 2 AND row > 2 THEN
  548.           GP(row, col, 5) = CheckPath(row - 1, 0, -1, col - 1, 0, -1, Opponent)
  549.           GG(row, col).nTake = GG(row, col).nTake + GP(row, col, 5)
  550.         END IF
  551.         IF col < 7 AND row < 7 THEN
  552.           GP(row, col, 6) = CheckPath(row + 1, 9, 1, col + 1, 9, 1, Opponent)
  553.           GG(row, col).nTake = GG(row, col).nTake + GP(row, col, 6)
  554.         END IF
  555.         IF col < 7 AND row > 2 THEN
  556.           GP(row, col, 7) = CheckPath(row - 1, 0, -1, col + 1, 9, 1, Opponent)
  557.           GG(row, col).nTake = GG(row, col).nTake + GP(row, col, 7)
  558.         END IF
  559.         IF col > 2 AND row < 7 THEN
  560.           GP(row, col, 8) = CheckPath(row + 1, 9, 1, col - 1, 0, -1, Opponent)
  561.           GG(row, col).nTake = GG(row, col).nTake + GP(row, col, 8)
  562.         END IF
  563.         IF GG(row, col).nTake > 0 THEN ValidMove = TRUE
  564.       END IF
  565.     NEXT col
  566.   NEXT row
  567.  
  568.  
  569.  

4
I know you can just avoid 0-argument functions but the above code works in QBASIC.

5
Programs / Re: Scheme (LISP) interpreter
« on: October 15, 2018, 10:31:50 pm »
Looks like QB64 still interprets 0-placed recursive functions incorrectly.  The version I posted triggers the recursion bug but it is easy to change the code so as not to use zero-place functions (e.g. make depth a parameter or add a dummy parameter).  STxAxTIC's modified version has this modification already but has the read code modified so it reads from a line of input so you can't split your expressions across lines.

6
Code: QB64: [Select]
  1. X = 5
  2.  
  3. IF X = 0 THEN F = 1 ELSE PRINT "*": X = X - 1: F = F
  4.  

Expected behavior: prints five stars, then 1.
Actual behaviour: prints a single star, then a 0.




7
QB64 Discussion / Re: CD Access
« on: October 15, 2018, 09:38:48 pm »
Hi. The following sentences are my estimation. If there really is a better way, of course I would also be very interested in how.

This is probably only possible with use an some external library because the audio CD format uses its own data format. They are basically WAV files but are not readable because CD-DA has one BYTE size of 14 bits, which is not compatible with the standard (8 bites per byte). With such a structure, the OPEN statement is computed, so CD-DA without special software is directly not accessible to QB64.
CDDA is 16-bit Linear PCM sampled at 44,100 Hz. (source: Wikipedia) (but there is no WAV header).  However, you still can't read it with ordinary file OPEN .  https://superuser.com/questions/1302319/why-you-cant-just-dd-cd-audio-like-an-ordinary-data-cd

8
QB64 Discussion / Re: Really got to implement source code printing
« on: October 07, 2018, 03:32:20 am »
For dot matrix printers, just save as LPT1 and it should print your text directly to the printer (assuming the printer is actually connected directly to the parallel port).  The editors Notepad++ and Emacs let you print out a syntax-highlighted version of your source code.  For Emacs this is PostScript format (which can be passed directly to a PostScript laser printer or to CUPS), for Notepad++ this uses the Windows printer driver.

Looks like the EPSON dot matrix printers had bold but only in draft mode, but in NLQ mode there is underline and italics. I remember WordPad (write.exe) could also print using the printer's text fonts on Windows if you select the appropriate font.  LPRINT also worked for text mode even in Win 2000 NTVDM on the Epson EX800.

https://files.support.epson.com/pdf/ex800_/ex800_u1.pdf

We already have LPRINT on Windows in QB64, which seems to print to the default Windows Printer.  Not sure if it's there on Linux and Mac.

9
Programs / Blackjack game (unfortunately variable names compressed)
« on: October 06, 2018, 09:21:08 pm »
Code: QB64: [Select]
  1. DECLARE SUB N (Y!)
  2. DIM SHARED A(1 TO 52), B(0 TO 16, 1 TO 16), C(0 TO 16)
  3. DIM SHARED D(0 TO 16), E(1 TO 16)
  4. F = 1000
  5. G = 0
  6. FOR I = 0 TO 16
  7. C(I) = 0
  8. FOR J = 1 TO 16
  9. B(I, J) = 0
  10. E(J) = 0
  11. PRINT "Your money: "; F
  12. E(1) = -1
  13. WHILE E(1) < 0 AND E(1) <= 1000
  14. INPUT "Wager"; E(1)
  15. IF E(1) < 0 THEN PRINT "Bet must be nonnegative."
  16. IF E(1) > 1000 THEN PRINT "Max bet $1000."
  17. H = 1
  18. K = 1
  19. N 0
  20. N 0
  21. N 1
  22. N 1
  23. O
  24. PRINT "Dealer Upcard: "; R$(B(0, 1))
  25. PRINT "Your hand:"; R(B(1, 1)); R(B(1, 2))
  26.  
  27. IF B(0, 1) = 11 THEN
  28. 1 INPUT "Would you like insurance"; X$
  29. X$ = UCASE$(LTRIM$(RTRIM$(X$)))
  30. CASE "Y", "YES", "AYE", "YUP", "YEAH", "OUI", "JA", "SI"
  31. L = .5 * E(1)
  32. CASE "N", "NAY", "NOPE", "NO", "NEIN", "NYET", "NON"
  33. L = 0
  34. IF D(0) = 21 THEN
  35. PRINT "Dealer Blackjack."
  36. IF D(1) <> 21 THEN F = F - E(1)
  37. IF L > 0 THEN
  38. PRINT "You get "; L * 2; "from insurance"
  39. F = F + L * 2
  40. L = 0
  41. ELSEIF D(1) = 21 THEN
  42. IF L > 0 THEN
  43. PRINT "You lose the insurance bet"
  44. F = F - L
  45. L = 0
  46. PRINT "Blackjack!"
  47. F = F + E(1) * 1.5
  48. ELSEIF L > 0 THEN
  49. PRINT "You lose the insurance bet"
  50. F = F - L
  51. L = 0
  52. DO WHILE H <= K
  53. 2 LINE INPUT "Your move:"; X$
  54. X$ = LTRIM$(RTRIM$(UCASE$(X$)))
  55. CASE "HIT", "H"
  56. N H
  57. O
  58. IF D(H) >= 21 THEN H = H + 1
  59. CASE "STAND", "S"
  60. H = H + 1
  61. CASE "DOUBLE", "D"
  62. E(H) = E(H) * 2
  63. N H
  64. O
  65. H = H + 1
  66. CASE "SPLIT", "P"
  67. IF (P(B(H, 1)) <> P(B(H, 2))) OR (C(H) <> 2) THEN
  68. PRINT "You cannot split."
  69. B(K + 1, 1) = B(H, 2)
  70. C(K + 1) = 1
  71. N K + 1
  72. B(H, 2) = 0
  73. C(H) = 1
  74. N H
  75. K = K + 1
  76. E(K) = E(H)
  77. O
  78. CASE "QUIT", "Q", "BYE", "ADIOS"
  79. PRINT "Invalid Selection"
  80. PRINT "Dealer Upcard: "; R$(B(0, 1))
  81. FOR I = 1 TO K
  82. PRINT "Hand"; I; ": ";
  83. FOR J = 1 TO C(I)
  84. PRINT R(B(I, J));
  85. IF H = I THEN PRINT "<- Current hand ";
  86. PRINT "(Sum ="; D(I); ")"
  87. PRINT "Dealer's hand:"; R$(B(0, 1)); R$(B(0, 2));
  88. 3 O
  89. IF D(0) < 17 THEN
  90. T = TIMER + .5
  91. N 0
  92. PRINT R$(B(0, C(0)));
  93. FOR I = 1 TO K
  94. IF D(I) > 21 THEN
  95. PRINT "Bust on Y"; I
  96. F = F - E(I)
  97. ELSEIF D(0) > 21 THEN
  98. PRINT "Dealer bust: win on Y"; I
  99. F = F + E(I)
  100. ELSEIF D(I) > D(0) THEN
  101. PRINT "Win on Y"; I
  102. F = F + E(I)
  103. ELSEIF D(I) < D(0) THEN
  104. PRINT "Lose on Y"; I
  105. F = F - E(I)
  106. PRINT "Push on Y"; I
  107.  
  108. SUB M
  109. FOR I = 1 TO 52
  110. A(I) = I
  111. J = 52
  112. K = INT(J * RND(1)) + 1
  113. SWAP A(K), A(J)
  114. J = J - 1
  115. LOOP WHILE J > 1
  116.  
  117. SUB N (Y)
  118. C(Y) = C(Y) + 1
  119. B(Y, C(Y)) = Q
  120.  
  121. SUB O
  122. FOR I = 0 TO K + 1
  123. T = 0
  124. S = 0
  125. FOR J = 1 TO C(I)
  126. X = P(B(I, J))
  127. S = S + X
  128. IF X = 11 THEN T = T + 1
  129. DO WHILE (S > 21 AND T > 0)
  130. S = S - 10
  131. T = T - 1
  132. D(I) = S
  133.  
  134. FUNCTION P (W)
  135. V = (W MOD 13) + 1
  136. P = 11
  137. CASE 2 TO 10
  138. P = V
  139. CASE 11 TO 13
  140. P = 10
  141.  
  142. IF G = 52 THEN M: G = 0
  143. G = G + 1
  144. Q = A(G)
  145.  
  146. FUNCTION R$ (W)
  147. SUIT = CHR$(((W - 1) \ 13) + 3)
  148. V = 1 + (W MOD 13)
  149. R$ = "A" + SUIT + " "
  150. CASE 2 TO 10
  151. R$ = LTRIM$(STR$(V)) + SUIT + " "
  152. CASE 11
  153. R$ = "J" + SUIT + " "
  154. CASE 12
  155. R$ = "Q" + SUIT + " "
  156. CASE 13
  157. R$ = "K" + SUIT + " "
  158.  
  159.  

10
Programs / Reversi / Othello Game (play against computer AI)
« on: October 06, 2018, 09:18:20 pm »
Mouse code is for QBASIC and uses CALL ABSOLUTE to call interrupt 33 and put the results in global variables named AX, BX, CX, DX.  Should still work in QB64; otherwise alter it to use CALL ITERRUPT or QB64 mouse codes.  When this was on the [abandoned, outdated and now likely malicious qb64 dot net website - don’t go there] forum there was a bug in QB64 that caused it not to compile the constants.  I think I had already put alternative mouse routines for QB64 or FreeBASIC.

Code: QB64: [Select]
  1. DECLARE FUNCTION AlphaBeta% (player%, board%(), achievable%, cutoff%, ply%)
  2. DECLARE FUNCTION FinalValue% (player%, board%())
  3. DECLARE FUNCTION WeightedSquares% (player%, board%())
  4. DECLARE FUNCTION MaximizeDifference% (player%, board%())
  5. DECLARE FUNCTION CountDifference% (player%, board%())
  6. DECLARE SUB MakeMove (move%, player%, board%())
  7. DECLARE SUB InitBoard ()
  8. DECLARE FUNCTION LegalP% (move%, player%, board%())
  9. DECLARE FUNCTION WouldFlip% (move%, player%, board%(), dir%)
  10. DECLARE FUNCTION FindBracketingPiece% (square%, player%, board%(), dir%)
  11. DECLARE FUNCTION NextToPlay% (board%(), PreviousPlayer%)
  12. DECLARE FUNCTION AnyLegalMove% (player%, board%())
  13. DECLARE FUNCTION Opponent% (player%)
  14. DECLARE SUB MakeFlips (move%, player%, board%(), dir%)
  15. DEFINT A-Z
  16. DECLARE SUB Mouse (ax AS INTEGER)
  17. DECLARE FUNCTION GetMove% ()
  18. DECLARE FUNCTION Colour (i)
  19. DECLARE SUB ShowBd ()
  20. DIM SHARED board(100) AS INTEGER
  21. DIM SHARED AllDirections(8) AS INTEGER
  22. DIM SHARED weights(100) AS INTEGER
  23. CLEAR , , 9999
  24. FOR i = 1 TO 8
  25.   READ AllDirections(i)
  26. DATA -11, -10, -9, -1, 1, 9, 10, 11
  27.  
  28. FOR i = 0 TO 99
  29.   READ weights(i)
  30. DATA 0,0,0,0,0,0,0,0,0,0
  31. DATA 0,120,-20,20,5,5,20,-20,120,0
  32. DATA 0,-20,-0,-5,-5,-5,-5,-40,-20,0
  33. DATA 0,20,-5,15,3,3,15,-5,20,0
  34. DATA 0,5,-5,3,3,3,3,-5,5,0
  35. DATA 0,5,-5,3,3,3,3,-5,5,0
  36. DATA 0,20,-5,15,3,3,15,-5,20,0
  37. DATA 0,-20,-0,-5,-5,-5,-5,-40,-20,0
  38. DATA 0,120,-20,20,5,5,20,-20,120,0
  39. DATA 0,0,0,0,0,0,0,0,0,0
  40.  
  41. CONST ScreenWidth = 640
  42. CONST ScreenHeight = 480
  43. CONST SquareWidth = ScreenHeight / 8
  44. CONST tlx = (ScreenWidth - ScreenHeight) / 2
  45. CONST tly = 0
  46. CONST brx = ScreenWidth - (ScreenWidth - ScreenHeight) / 2
  47. CONST bry = ScreenHeight
  48. CONST PieceRadius = SquareWidth / 2 - 5
  49. CONST EMPTY = 0
  50. CONST BLACK = 1
  51. CONST WHITE = 2
  52. CONST OUTER = 3
  53. CONST WinningValue = 32767
  54. CONST LosingValue = -32767
  55. CONST nply = 5
  56.  
  57. DIM SHARED bestm(nply) AS INTEGER
  58. ax = 0
  59. bx = 0
  60. cx = 0
  61. dx = 0
  62.  
  63.  
  64.  
  65. CALL InitBoard
  66. CALL Mouse(0)
  67. CALL Mouse(1)
  68. player = BLACK
  69. human = BLACK
  70. computer = Opponent(human)
  71.   CALL ShowBd
  72.   IF player = human THEN
  73.     n = GetMove
  74.     IF LegalP(n, player, board()) THEN
  75.       CALL MakeMove(n, player, board())
  76.       player = NextToPlay(board(), player)
  77.     END IF
  78.   END IF
  79.   CALL ShowBd
  80.   IF player = computer THEN
  81.     n = AlphaBeta(player, board(), LosingValue, WinningValue, nply)
  82.     move = bestm(nply)
  83.     CALL MakeMove(move, player, board())
  84.     player = NextToPlay(board(), player)
  85.   END IF
  86. LOOP UNTIL player = 0
  87.  
  88. FUNCTION AlphaBeta (player, board(), achievable, cutoff, ply)
  89.   DIM board2(100)
  90.   FOR i = 0 TO 99
  91.     board2(i) = board(i)
  92.   NEXT
  93.   IF ply = 0 THEN
  94.     AlphaBeta = WeightedSquares(player, board())
  95.   END IF
  96.   nlegal = 0
  97.   FOR move = 0 TO 99
  98.     IF LegalP(move, player, board()) THEN
  99.       nlegal = nlegal + 1
  100.       CALL MakeMove(move, player, board2())
  101.       value = -AlphaBeta(Opponent(player), board2(), -cutoff, -achievable, ply - 1)
  102.       IF value > achievable THEN
  103.         achievable = value
  104.         bestmove = move
  105.       END IF
  106.     END IF
  107.   NEXT
  108.   IF nlegal = 0 THEN
  109.     IF AnyLegalMove(Opponent(player), board()) THEN
  110.       AlphaBeta = -AlphaBeta(Opponent(player), board(), -cutoff, -achievable, ply - 1)
  111.     ELSE
  112.       AlphaBeta = FinalValue(player, board())
  113.     END IF
  114.   END IF
  115.   bestm(ply) = bestmove
  116.  
  117. FUNCTION AnyLegalMove (player, board())
  118.   FOR i = 0 TO 99
  119.     IF LegalP(i, player, board()) THEN AnyLegalMove = -1: EXIT FUNCTION
  120.   NEXT
  121.  
  122. FUNCTION Colour (i)
  123.   IF i = BLACK THEN
  124.     Colour = 0
  125.   ELSE
  126.     Colour = 15
  127.   END IF
  128.  
  129. FUNCTION CountDifference (player, board())
  130.   c = 0
  131.   FOR y = 1 TO 8
  132.     FOR x = 1 TO 8
  133.       IF board(10 * y + x) = player THEN c = c + 1
  134.       IF board(10 * y + x) = Opponent(player) THEN c = c - 1
  135.     NEXT
  136.   NEXT
  137.   CountDifference = c
  138.  
  139. FUNCTION FinalValue (player, board())
  140.   SELECT CASE SGN(CountDifference(player, board()))
  141.     CASE -1
  142.       FinalValue = LosingValue
  143.     CASE 0
  144.       FinalValue = 0
  145.     CASE 1
  146.       FinalValue = WinningValue
  147.  
  148. FUNCTION FindBracketingPiece (square, player, board(), dir)
  149.   IF board(square) = player THEN
  150.     FindBracketingPiece = square
  151.   ELSEIF board(square) = Opponent(player) THEN
  152.     FindBracketingPiece = FindBracketingPiece(square + dir, player, board(), dir)
  153.   END IF
  154.  
  155. FUNCTION GetMove
  156.   DO
  157.     CALL Mouse(3)
  158.     IF bx AND 1 THEN
  159.       y = (dx - tly) \ SquareWidth + 1
  160.       x = (cx - tlx) \ SquareWidth + 1
  161.     END IF
  162.     IF 1 <= y AND y <= 8 AND 1 <= x AND x <= 8 THEN EXIT DO
  163.   LOOP
  164.   GetMove = 10 * y + x
  165.  
  166. SUB InitBoard
  167.   FOR i = 0 TO 9
  168.     board(i) = OUTER
  169.     board(90 + i) = OUTER
  170.     board(i * 10) = OUTER
  171.     board(i * 10 + 9) = OUTER
  172.   NEXT
  173.   board(44) = 1
  174.   board(45) = 2
  175.   board(54) = 2
  176.   board(55) = 1
  177.  
  178. FUNCTION LegalP (move, player, board())
  179.   IF board(move) <> EMPTY THEN LegalP = 0: EXIT FUNCTION
  180.   FOR i = 1 TO 8
  181.     x = WouldFlip(move, player, board(), AllDirections(i))
  182.     IF x THEN LegalP = -1: EXIT FUNCTION
  183.   NEXT
  184.  
  185. SUB MakeFlips (move, player, board(), dir)
  186.   bracketer = WouldFlip(move, player, board(), dir)
  187.   IF bracketer THEN
  188.     FOR c = move + dir TO bracketer STEP dir
  189.       board(c) = player
  190.     NEXT
  191.   END IF
  192.  
  193. SUB MakeMove (move, player, board())
  194.   board(move) = player
  195.   FOR i = 1 TO 8
  196.     CALL MakeFlips(move, player, board(), AllDirections(i))
  197.   NEXT
  198.  
  199. FUNCTION MaximizeDifference (player, board())
  200.   DIM board2(100)
  201.   best = -9999
  202.   FOR y = 1 TO 8
  203.     FOR x = 1 TO 8
  204.       move = 10 * y + x
  205.       IF LegalP(move, player, board()) THEN
  206.         FOR i = 0 TO 99
  207.           board2(i) = board(i)
  208.         NEXT
  209.         CALL MakeMove(move, player, board2())
  210.         score = WeightedSquares(player, board2())
  211.         IF score > best THEN best = score: bestmove = move
  212.       END IF
  213.     NEXT
  214.   NEXT
  215.   MaximizeDifference = bestmove
  216.  
  217. SUB Mouse (ax AS INTEGER)
  218.  
  219.   ml$ = "" ' -=<( Mouse Code )>=-
  220.   ml$ = ml$ + CHR$(&H55) ' push bp               ; preserve BP register
  221.   ml$ = ml$ + CHR$(&H89) + CHR$(&HE5) ' mov  bp, sp           ; copy SP to BP
  222.   ml$ = ml$ + CHR$(&HB8) + CHR$(ax) + CHR$(&H0) '   mov  ax, #          ;   copy SUBFUNCTION to AX
  223.   ml$ = ml$ + CHR$(&HCD) + CHR$(&H33) '   int  33             ;   call mouse interrupt
  224.   ml$ = ml$ + CHR$(&H53) '   push bx             ;   preserve BX (again)
  225.   ml$ = ml$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6) '   mov  bx, [bp+6]     ;   copy location of dx (last variable) to BX
  226.   ml$ = ml$ + CHR$(&H89) + CHR$(&H17) '   mov  [bx], dx       ;   copy DX to dx location in BX
  227.   ml$ = ml$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H8) '   mov  bx, [bp+8]     ;   copy location of cx to BX
  228.   ml$ = ml$ + CHR$(&H89) + CHR$(&HF) '   mov  [bx], cx       ;   copy CX to cx location in BX
  229.   ml$ = ml$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&HC) '   mov  bx, [bp+C]     ;   copy location of ax to BX
  230.   ml$ = ml$ + CHR$(&H89) + CHR$(&HF7) '   mov  [bx], ax       ;   copy AX to ax location in BX
  231.   ml$ = ml$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&HA) '   mov  bx, [bp+A]     ;   copy location of bx to BX
  232.   ml$ = ml$ + CHR$(&H58) '   pop  ax             ;   restore int 33's BX value to AX
  233.   ml$ = ml$ + CHR$(&H89) + CHR$(&H7) '   mov  [bx], ax       ;   copy AX to bx location in BX
  234.   ml$ = ml$ + CHR$(&H5D) ' pop  bp               ; restore BP
  235.   ml$ = ml$ + CHR$(&HCA) + CHR$(&H8) + CHR$(&H0) ' retf 8                ; Return Far and skip 8 bytes of variables
  236.   DEF SEG = SSEG(ml$) ' Set current segment this machine code segment
  237.   offset% = SADD(ml$) ' Set offset to this machine code location
  238.   CALL absolute(ax, bx, cx, dx, offset%) ' The actual call to this machine code
  239.   DEF SEG ' Restore the default segment
  240.  
  241.  
  242. FUNCTION NextToPlay (board(), PreviousPlayer)
  243.   opp = Opponent(PreviousPlayer)
  244.   IF AnyLegalMove(opp, board()) THEN NextToPlay = opp: EXIT FUNCTION
  245.   IF AnyLegalMove(PreviousPlayer, board()) THEN NextToPlay = PreviousPlayer
  246.  
  247. FUNCTION Opponent (player)
  248.   IF player = WHITE THEN Opponent = BLACK
  249.   IF player = BLACK THEN Opponent = WHITE
  250.  
  251. SUB ShowBd
  252.   LINE (tlx, tly)-(brx, bry), 8, BF
  253.   FOR i = 0 TO 8
  254.     LINE (tlx + SquareWidth * i, tly)-(tlx + SquareWidth * i, bry)
  255.     LINE (tlx, tly + SquareWidth * i)-(brx, tly + SquareWidth * i)
  256.   NEXT
  257.   FOR y = 1 TO 8
  258.     FOR x = 1 TO 8
  259.       IF board(10 * y + x) <> EMPTY THEN
  260.         CIRCLE (tlx + SquareWidth * x - SquareWidth / 2, tly + SquareWidth * y - SquareWidth / 2), PieceRadius, Colour(board(10 * y + x))
  261.         PAINT (tlx + SquareWidth * x - SquareWidth / 2, tly + SquareWidth * y - SquareWidth / 2), Colour(board(10 * y + x))
  262.       END IF
  263.     NEXT
  264.   NEXT
  265.  
  266. FUNCTION WeightedSquares (player, board())
  267.   opp = Opponent(player)
  268.   sum = 0
  269.   FOR i = 0 TO 99
  270.     IF board(i) = player THEN sum = sum + weights(i)
  271.     IF board(i) = opp THEN sum = sum - weights(i)
  272.   NEXT
  273.   WeightedSquares = sum
  274.  
  275. FUNCTION WouldFlip (move, player, board(), dir)
  276.   c = move + dir
  277.   IF board(c) <> Opponent(player) THEN WouldFlip = 0: EXIT FUNCTION
  278.   WouldFlip = FindBracketingPiece(c + dir, player, board(), dir)
  279.  
  280.  

11
Programs / Scheme (LISP) interpreter
« on: October 06, 2018, 09:14:42 pm »

Code: QB64: [Select]
  1. DEFINT A-Z
  2. declare function readobj()
  3. declare function readtoken()
  4. declare function strtoatom(s$)
  5. declare function cons(car,cdr)
  6. declare function readlist()
  7. declare sub printobj(id)
  8. declare function evalobj(id, env)
  9. declare function apply(f, args)
  10. declare function lookup(anum, env)
  11. declare function lvals(id,env)
  12. declare sub defvar(var,val,env)
  13. declare sub setvar(id,val,env)
  14. declare function mkprimop(id)
  15.  
  16. DIM SHARED depth AS INTEGER,bufpos AS INTEGER, state AS INTEGER
  17. DIM SHARED anext, hptr
  18. DIM SHARED atom$(1024),heap(2048, 2)
  19.  
  20. CONST TRUE = -1
  21. CONST FALSE = 0
  22. CONST TNIL = 0
  23. CONST TCONS = 2
  24. CONST TNUM = 3
  25. CONST TSYM = 4
  26. CONST TPROC = 5
  27. CONST TPPROC = 6
  28. CONST TOKNIL = 0
  29. CONST TOKERR = 1
  30. CONST TOKOPEN = 2
  31. CONST TOKCLOSE = 3
  32. CONST TOKQUOTE = 4
  33. CONST TOKDOT = 5
  34.  
  35.  
  36. CONST PPLUS = 1
  37. CONST PTIMES = 3
  38. CONST PCONS = 4
  39. CONST PCAR = 5
  40. CONST PCDR = 6
  41. CONST PEQUAL = 7
  42. CONST PNOT = 8
  43. CONST PEQ = 9
  44. CONST PSETCAR = 10
  45. CONST PSETCDR = 11
  46. CONST PAPPLY = 12
  47. CONST PLIST = 13
  48. CONST PREAD = 14
  49.  
  50. hptr = 10: bufpos = 1
  51. vars = TNIL
  52. vals = TNIL
  53. frame = CONS(vars,vals)
  54. env = CONS(frame,TNIL)
  55.  
  56. CALL DEFVAR(STRTOATOM("+"),mkprimop(PPLUS), env)
  57. CALL DEFVAR(STRTOATOM("*"),mkprimop(PTIMES), env )
  58. CALL DEFVAR(STRTOATOM("CONS"),mkprimop(PCONS), env)
  59. CALL DEFVAR(STRTOATOM("CAR"),mkprimop(PCAR), env )
  60. CALL DEFVAR(STRTOATOM("CDR"),mkprimop(PCDR), env)
  61. CALL DEFVAR(STRTOATOM("="),mkprimop(PEQUAL),env)
  62. CALL DEFVAR(STRTOATOM("NOT"),mkprimop(PNOT),env)
  63. CALL DEFVAR(STRTOATOM("EQ?"),mkprimop(PEQ),env)
  64. CALL DEFVAR(STRTOATOM("EQV?"),mkprimop(PEQ),env)
  65. CALL DEFVAR(STRTOATOM("T"),STRTOATOM("T"),env) ' true
  66. CALL DEFVAR(STRTOATOM("SET-CAR!"),mkprimop(PSETCAR),env)
  67. CALL DEFVAR(STRTOATOM("SET-CDR!"),mkprimop(PSETCDR),env)
  68. CALL DEFVAR(STRTOATOM("APPLY"),mkprimop(PAPPLY),env)
  69. CALL DEFVAR(STRTOATOM("LIST"),mkprimop(PLIST),env)
  70. CALL DEFVAR(STRTOATOM("READ"),mkprimop(PREAD), env)
  71.  
  72.     s = READOBJ()
  73.     SELECT CASE s
  74.     CASE TOKCLOSE
  75.     ' unmatched closed parenthesis
  76.     CASE TOKDOT
  77.     PRINT  "dot used outside list"
  78.     CASE TOKERR
  79.     PRINT "[Error]"
  80.     CASE ELSE
  81.     CALL PRINTOBJ(EVALOBJ(s,env))
  82.     END SELECT
  83.     PRINT
  84.  
  85.  
  86. SUB PRINTOBJ(id)
  87.  
  88.     IF id = TOKERR THEN PRINT "[Error]" : EXIT SUB
  89.     SELECT CASE heap(id,0)
  90.     CASE TNIL
  91.         PRINT "()";
  92.     CASE TCONS
  93.         PRINT "(";
  94. 1       CALL PRINTOBJ(heap(id,1))
  95.         PRINT " ";
  96.         cdr = heap(id,2)
  97.         IF heap(cdr,0) = TCONS THEN
  98.             id = cdr: GOTO 1
  99.         ELSEIF heap(cdr,0) = TNIL THEN
  100.             PRINT ")";
  101.         ELSE
  102.             PRINT ".";  
  103.             CALL PRINTOBJ(cdr)
  104.             PRINT ")";
  105.         END IF
  106.     CASE TNUM
  107.         PRINT heap(id,1);
  108.     CASE TSYM
  109.         PRINT atom$(heap(id,1));
  110.     CASE TPROC, TPPROC
  111.         PRINT "[Procedure]"
  112.     END SELECT
  113.  
  114. FUNCTION READTOKEN()
  115.    
  116. 1    bufend = LEN(buf)
  117.     WHILE bufpos < bufend AND INSTR(" "+CHR$(9),MID$(buf,bufpos,1))
  118.         bufpos = bufpos + 1
  119.     WEND
  120.     c$ = MID$(buf,bufpos,1)
  121.     IF INSTR(":;",c$) THEN
  122.         IF c$ = ":" THEN
  123.             bufpos = bufpos + 1
  124.             IF bufpos <= bufend THEN
  125.                 SELECT CASE MID$(buf,bufpos,1)
  126.                 CASE "q" ' quit
  127.                     SYSTEM
  128.                 CASE ELSE
  129.                         READTOKEN = TOKERR
  130.                         EXIT FUNCTION
  131.                 END SELECT
  132.             END IF
  133.         END IF
  134.         bufpos = bufend + 1
  135.     END IF
  136.     IF bufpos > bufend THEN
  137.         IF depth = 0 THEN PRINT "]=> ";
  138.         LINE INPUT buf
  139.         bufend = LEN(buf)
  140.         bufpos = 1
  141.         GOTO 1
  142.     END IF
  143.     SELECT CASE c$
  144.     CASE "("
  145.         bufpos = bufpos + 1
  146.         READTOKEN = TOKOPEN
  147.     CASE ")"
  148.         bufpos = bufpos + 1
  149.         READTOKEN = TOKCLOSE
  150.     CASE "'"
  151.         bufpos = bufpos+1
  152.         READTOKEN = TOKQUOTE
  153.     CASE "."
  154.         bufpos = bufpos + 1
  155.         READTOKEN = TOKDOT
  156.     CASE ELSE
  157.         strbeg = bufpos
  158.         bufpos = bufpos +1
  159.         DO WHILE bufpos <= bufend
  160.             c$ = MID$(buf,bufpos,1)
  161.             IF c$ = " " OR c$ = "." OR c$ = "(" OR c$ = ")" THEN EXIT DO
  162.             bufpos = bufpos + 1
  163.         LOOP
  164.         READTOKEN = STRTOATOM(MID$(buf,strbeg,bufpos - strbeg))
  165.     END SELECT
  166.  
  167. FUNCTION STRTOATOM(s$)
  168.     l = LEN(s$)
  169.     c$ = LEFT$(s$,1)
  170.     IF (c$ = "-" AND l >= 2) OR (c$ >= "0" AND c$ <= "9") THEN
  171.         v = 0
  172.         IF c$ = "-" THEN neg = 1: idx = 2 ELSE neg = 0: idx = 1
  173.         FOR idx = idx TO l
  174.             c$ = MID$(s$,idx,1)
  175.             IF (c$ >= "0" AND c$ <= "9") THEN
  176.                 v = v*10 + (ASC(c$)-ASC("0"))
  177.             ELSE
  178.                 EXIT FOR
  179.             END IF
  180.         NEXT
  181.         IF idx = l + 1 THEN
  182.             IF neg THEN v = -v
  183.             p = ALLOC()
  184.             HEAP(p,0) = TNUM
  185.             HEAP(p,1) = v
  186.             STRTOATOM = p: EXIT FUNCTION
  187.         END IF
  188.     END IF
  189.     IF UCASE$(s$) = "NIL" THEN STRTOATOM=TOKNIL: EXIT FUNCTION
  190.     FOR i = 0 TO anext-1
  191.         IF ATOM$(i) = UCASE$(s$) THEN found = TRUE : exit for
  192.     NEXT
  193.     IF not found then ATOM$(anext) = UCASE$(s$) : anext = anext + 1
  194.     p = ALLOC(): HEAP(p,0) = TSYM: HEAP(p,1) = i
  195.     STRTOATOM = p
  196.  
  197. FUNCTION READOBJ()
  198.     tok = READTOKEN()
  199.     SELECT CASE tok
  200.     CASE TOKOPEN
  201.     depth = depth + 1
  202.     s = READLIST()
  203.     depth = depth - 1
  204.     READOBJ = s
  205.     CASE TOKQUOTE
  206.     depth = depth + 1
  207.     tok = READOBJ()
  208.     depth = depth - 1
  209.     SELECT CASE tok
  210.     CASE TOKCLOSE
  211.     PRINT "warning: quote before close parenthesis"
  212.     READOBJ = TOK
  213.     CASE TOKDOT
  214.     PRINT "warning: quote before dot"
  215.     READOBJ = TOK
  216.     CASE ELSE
  217.     s = CONS(STRTOATOM("QUOTE"),CONS(tok,0))
  218.     READOBJ = s
  219.     END SELECT
  220.     CASE ELSE
  221.     READOBJ = tok
  222.     END SELECT
  223.  
  224. FUNCTION CONS(car,cdr)
  225.     p = ALLOC()
  226.     heap(p,0) = TCONS
  227.     heap(p,1) = car
  228.     heap(p,2) = cdr
  229.     cons = p
  230.  
  231. FUNCTION ALLOC()
  232.     ALLOC = hptr
  233.     hptr = hptr + 1
  234.  
  235. FUNCTION READLIST()
  236.     SH = READOBJ()
  237.     SELECT CASE SH
  238.     CASE TOKERR
  239.         READLIST = TOKERR
  240.     CASE TOKCLOSE
  241.         READLIST = 0
  242.     CASE TOKDOT
  243.         SH = READOBJ()
  244.         SELECT CASE SH
  245.         CASE TOKERR, TOKDOT, TOKCLOSE
  246.             READLIST = TOKERR
  247.         CASE ELSE
  248.             ST = READLIST()
  249.             IF ST THEN READLIST = TOKERR ELSE READLIST = SH
  250.         END SELECT
  251.     CASE ELSE
  252.         ST = READLIST()
  253.         IF ST = TOKERR THEN READLIST = TOKERR ELSE READLIST = CONS(SH,ST)
  254.     END SELECT
  255.  
  256. FUNCTION EVALOBJ(id, env)
  257. 1   SELECT CASE heap(id,0)
  258.     CASE TNIL, TNUM ' self-evaluating
  259.         EVALOBJ = id
  260.     CASE TSYM
  261.         EVALOBJ = LOOKUP(heap(id,1),env)
  262.     CASE TCONS
  263.         o = heap(id,1)
  264.         t = heap(o,0)
  265.         IF t = TSYM THEN
  266.         a$ = atom$(heap(o,1)) ' symbol name of car(id)
  267.         SELECT CASE a$
  268.         CASE "QUOTE"
  269.             EVALOBJ = heap(heap(id,2),1)
  270.         CASE "SET!"
  271.             vid = heap(heap(id,2),1) 'cadr
  272.             aval = heap(heap(heap(id,2),2),1) 'caddr
  273.             CALL setvar(vid, evalobj(aval, env),env)
  274.         CASE "DEFINE"
  275.             vid = heap(heap(id,2),1)
  276.             aval = heap(heap(heap(id,2),2),1)
  277.             CALL setvar(vid, evalobj(aval,env),env)
  278.         CASE "IF"
  279.             ' (if pred ic ia)
  280.             pred = heap(heap(id,2),1) 'predicate = cadr
  281.             ic = heap(heap(heap(id,2),2),1) ' caddr
  282.             ia = heap(heap(heap(heap(id,2),2),2),1) ' cadddr
  283.             IF EVALOBJ(pred,env) THEN
  284.                 ' return EVALOBJ(ic,env)
  285.                 id = ic: GOTO 1
  286.             ELSE
  287.                 ' return EVALOBJ(ia,env)
  288.                 id = ia : GOTO 1
  289.             END IF
  290.         CASE "LAMBDA"
  291.             p = ALLOC()
  292.             heap(p,0) = TPROC
  293.             heap(p,1) = heap(heap(id,2),1) ' cadr = args
  294.             heap(p,2) = CONS(heap(heap(id,2),2),env) 'caddr = body
  295.             EVALOBJ = p
  296.         CASE "BEGIN"
  297.         seq = heap(id,2)
  298.         DO WHILE heap(seq,2)
  299.         t = heap(seq,1)
  300.         t = evalobj(t,env) 'ignore result
  301.         seq = heap(seq,2)
  302.         LOOP
  303.         id = heap(seq,1): GOTO 1
  304.         CASE "AND"
  305.         seq = heap(id,2)
  306.         DO WHILE heap(seq,2)
  307.         t = heap(seq,1)
  308.         t = evalobj(t,env)
  309.         IF t = 0 THEN evalobj = 0: EXIT FUNCTION
  310.         seq = heap(seq,2)
  311.         LOOP
  312.         id = heap(seq,1): GOTO 1
  313.         CASE "OR"
  314.         seq = heap(id,2)
  315.         DO WHILE heap(seq,2)
  316.         t = heap(seq,1)
  317.         t = evalobj(t,env)
  318.         IF t THEN evalobj = t: EXIT FUNCTION
  319.         seq = heap(seq,2)
  320.         LOOP
  321.         id = heap(seq,1): GOTO 1
  322.         CASE "COND"
  323.         clauses = heap(id,2)
  324.         WHILE clauses
  325.         clause = heap(clauses, 1)
  326.         pred = heap(clause, 1)
  327.         IF EVALOBJ(pred,env) THEN
  328.            seq = heap(clause, 2)
  329.            DO WHILE heap(seq,2)
  330.             t = heap(seq,1)
  331.             t = evalobj(t,env) 'ignore result
  332.             seq = heap(seq,2)
  333.            LOOP
  334.            id = heap(seq,1): GOTO 1
  335.         END IF
  336.         clauses = heap(clauses,2)
  337.         WEND
  338.         CASE ELSE
  339.             args = heap(id,2)
  340.             proc = EVALOBJ(o,env)
  341.             EVALOBJ = apply(proc,lvals(args,env))
  342.         END SELECT
  343.         ELSE
  344.             args = heap(id,2)
  345.             proc = EVALOBJ(o, env)
  346.             EVALOBJ = apply(proc,lvals(args,env))
  347.         END IF
  348.     CASE ELSE
  349.         PRINT "Unhandled expression type: "; a$
  350.         EVALOBJ = id
  351.     END SELECT
  352.  
  353. FUNCTION lvals(id,env)
  354.    IF heap(id,0) = TCONS THEN
  355.      car = heap(id,1)
  356.      ecar = EVALOBJ(car,env)
  357.      head = CONS(ecar,0)
  358.      l = heap(id,2) : prev = head
  359.      WHILE l
  360.          car = heap(l,1)
  361.          ecar = EVALOBJ(car,env)
  362.          new = CONS(ecar,0)
  363.          heap(prev,2) = new
  364.          prev = new
  365.          l = heap(l,2)
  366.      WEND
  367.      lvals = head
  368.    ELSE
  369.      lvals = 0
  370.    END IF
  371.  
  372. FUNCTION apply(id,args)
  373.     IF heap(id,0) = TPROC THEN
  374.     params = heap(id,1)
  375.     body = heap(heap(id,2),1)
  376.     procenv = heap(heap(id,2),2)
  377.     env = CONS(CONS(params,args),procenv)
  378.     DO WHILE heap(body,2)
  379.     t = heap(body,1)
  380.     t = evalobj(t,env) 'ignore result
  381.     body = heap(body,2)
  382.     LOOP
  383.     t = heap(body,1)
  384.     apply = evalobj(t,env)
  385.     ELSEIF heap(id,0) = TPPROC THEN
  386.     SELECT CASE heap(id,1)
  387.     CASE PPLUS
  388.         sum = 0
  389.         a = args
  390.         WHILE a
  391.             sum = sum + heap(heap(a,1),1)
  392.             a = heap(a,2)
  393.         WEND
  394.         p = ALLOC()
  395.         heap(p,0) = TNUM
  396.         heap(p,1) = sum
  397.         apply = p
  398.     CASE PTIMES
  399.         prod = 1
  400.         a = args
  401.         WHILE a
  402.             prod = prod * heap(heap(a,1),1)
  403.             a = heap(a,2)
  404.         WEND
  405.         p = ALLOC()
  406.         heap(p,0) = TNUM
  407.         heap(p,1) = prod
  408.         apply = p
  409.     CASE PCONS
  410.         apply = CONS(heap(args,1), heap(heap(args,2),1))
  411.     CASE PCAR
  412.         apply = heap(heap(args,1),1)
  413.     CASE PCDR
  414.         apply = heap(heap(args,1),2)
  415.     CASE PEQUAL
  416.         IF args = TNIL THEN apply = STRTOATOM("T"): EXIT FUNCTION
  417.         f = heap(heap(args,1),1)
  418.         a = heap(args,2)
  419.         DO WHILE a
  420.             IF heap(heap(a,1),1) <> f THEN apply = TNIL : EXIT FUNCTION
  421.             a = heap(a,2)
  422.         LOOP
  423.         apply = STRTOATOM("T"): EXIT FUNCTION
  424.     CASE PNOT
  425.         IF heap(args,1) THEN apply = TNIL ELSE apply = STRTOATOM("T")
  426.     CASE PEQ
  427.         arg1 = heap(args,1)
  428.         arg2 = heap(heap(args,2),1)
  429.         IF heap(arg1,0) <> heap(arg2,0) THEN apply = TNIL: EXIT FUNCTION
  430.         SELECT CASE heap(arg1,0)
  431.         CASE TNUM, TPROC, TPPROC, TSYM
  432.             IF heap(arg1,1) = heap(arg2,1) THEN apply = STRTOATOM("T")
  433.         CASE TCONS, TNIL
  434.             IF arg1 = arg2 THEN apply = STRTOATOM("T")
  435.         END SELECT
  436.     CASE PSETCAR
  437.         arg1 = heap(args,1)
  438.         arg2 = heap(heap(args,2),1)
  439.         heap(arg1,1) = arg2
  440.     CASE PSETCDR
  441.         arg1 = heap(args,1)
  442.         arg2 = heap(heap(args,2),1)
  443.         heap(arg2,2) = arg2
  444.     CASE PAPPLY
  445.         arg1 = heap(args,1)
  446.         arg2 = heap(heap(args,2),1)
  447.         apply = apply(arg1,arg2)
  448.     CASE PLIST
  449.         apply = args
  450.     CASE PREAD
  451.         apply = readobj()
  452.     END SELECT
  453.     ELSE
  454.     PRINT "Bad application -- not a function"
  455.     apply = TOKERR
  456.     END IF
  457.  
  458. FUNCTION lookup(anum,env)
  459.     ' env is a list of (vars . vals) frames
  460.     ' where: vars is a list of symbols
  461.     '        vals is a list of their values
  462.     e = env
  463.     DO
  464.     frame = heap(e,1) ' get the first frame
  465.  
  466.     vars = heap(frame,1) ' vars is car
  467.  
  468.     vals = heap(frame,2) ' vals is cdr
  469.  
  470.     WHILE vars ' while vars left to check
  471.         IF heap(heap(vars, 1),1) = anum THEN 'atom number of car(vars) = anum
  472.             lookup = heap(vals,1) ' car(vals)
  473.             EXIT FUNCTION
  474.         END IF
  475.         vars = heap(vars,2) 'cdr(vars)
  476.         vals = heap(vals,2) 'cdr(vals)
  477.     WEND
  478.     e = heap(e,2) ' cdr(e)
  479.     LOOP WHILE e
  480.     PRINT "Unbound variable: "; ATOM$(anum): lookup = TOKERR
  481.  
  482. SUB setvar(id, value, env)
  483.     anum = heap(id,1)
  484.     e = env
  485.     DO
  486.         frame = heap(e,1)
  487.         vars = heap(frame,1)
  488.         vals = heap(frame,2)
  489.         WHILE vars
  490.             IF heap(heap(vars,1),1) = anum THEN
  491.                 heap(vals,1) = value : EXIT SUB
  492.             END IF
  493.             vars = heap(vars,2): vals = heap(vals,2)
  494.         WEND
  495.         e = heap(e,2)
  496.     LOOP WHILE e
  497.     CALL defvar(id, value, env)
  498.  
  499. SUB defvar(id, value, env)
  500.     anum = heap(id,1)
  501.     frame = heap(env,1)
  502.     vars = heap(frame,1)
  503.     vals = heap(frame,2)
  504.     WHILE vars
  505.         IF heap(heap(vars,1),1) = anum THEN
  506.             heap(vals,1) = value: EXIT SUB
  507.         END IF
  508.         vars = heap(vars,2): vals = heap(vals,2)
  509.     WEND
  510.     vars = heap(frame,1)
  511.     vals = heap(frame,2)
  512.     heap(frame,1) = CONS(id, vars)
  513.     heap(frame,2) = CONS(value, vals)
  514.  
  515. FUNCTION mkprimop(id)
  516.  p = alloc()
  517.  heap(p,0) = TPPROC
  518.  heap(p,1) = id
  519.  mkprimop = p
  520.  

Pages: [1]