Author Topic: Smart Snake  (Read 9143 times)

0 Members and 1 Guest are viewing this topic.

This topic contains a post which is marked as Best Answer. Press here if you would like to see it.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Smart Snake
« on: March 15, 2020, 01:39:16 pm »
This snake drives on auto-pilot:

Code: QB64: [Select]
  1. _TITLE "Snake AI-1" 'b+ 2020-03-14
  2. CONST sq = 20, sqs = 20, xmax = 400, ymax = 400
  3. SCREEN _NEWIMAGE(xmax, ymax, 32)
  4. _DELAY .25
  5. DIM X(xmax + 100), Y(ymax + 100)
  6. hx = 10: hy = 10: ax = 15: ay = 15: top = 0: X(top) = hx: Y(top) = hy 'initialize
  7.     _TITLE STR$(top + 1)
  8.     LINE (0, 0)-(xmax, ymax), &HFF006600, BF 'clear garden
  9.  
  10.     '>>>>>>>>>>>       SNAKE BRAIN    <<<<<<<<<<<<<<<
  11.     IF hx = 0 AND hy = 19 THEN
  12.         hy = hy - 1
  13.     ELSEIF hx MOD 2 = 0 AND hy <> 0 AND hy <> 19 THEN
  14.         hy = hy - 1
  15.     ELSEIF hx MOD 2 = 0 AND hy = 0 AND hy <> 19 THEN
  16.         hx = hx + 1
  17.     ELSEIF hx MOD 2 = 1 AND hx <> 19 AND hy < 18 THEN
  18.         hy = hy + 1
  19.     ELSEIF hx MOD 2 = 1 AND hx <> 19 AND hy = 18 THEN
  20.         hx = hx + 1
  21.     ELSEIF hx = 19 AND hy = 19 THEN
  22.         hx = hx - 1
  23.     ELSEIF hy = 19 AND hx <> 0 THEN
  24.         hx = hx - 1
  25.     ELSEIF hx MOD 2 = 1 AND hy = 0 AND hy <> 19 THEN
  26.         hy = hy + 1
  27.     ELSEIF hx = 19 AND hy < 19 THEN
  28.         hy = hy + 1
  29.     END IF
  30.     FOR i = 0 TO top - 1
  31.         X(i) = X(i + 1): Y(i) = Y(i + 1)
  32.     NEXT
  33.     X(top) = hx: Y(top) = hy
  34.  
  35.     'apple
  36.     IF (ax = hx AND ay = hy) THEN 'snake eats apple, get new apple watch it's not where snake is
  37.         top = top + 1
  38.         X(top) = hx: Y(top) = hy
  39.         DO 'check new apple
  40.             ax = INT(RND * sqs): ay = INT(RND * sqs): good = -1
  41.             FOR i = 0 TO top - 1
  42.                 IF ax = X(i) AND ay = Y(i) THEN good = 0: EXIT FOR
  43.             NEXT
  44.         LOOP UNTIL good
  45.     END IF
  46.     LINE (ax * sq, ay * sq)-STEP(sq - 2, sq - 2), _RGB32(255, 100, 255), BF
  47.  
  48.     'snake
  49.     FOR i = 0 TO top
  50.         IF i = top THEN
  51.             c~& = &HFF000000
  52.         ELSE
  53.             SELECT CASE (top - i) MOD 4
  54.                 CASE 0: c~& = &HFF000088
  55.                 CASE 1: c~& = &HFF880000
  56.                 CASE 2: c~& = &HFFBB8800
  57.                 CASE 3: c~& = &HFF008888
  58.             END SELECT
  59.         END IF
  60.         LINE (X(i) * sq, Y(i) * sq)-STEP(sq - 2, sq - 2), c~&, BF
  61.     NEXT
  62.     _DISPLAY
  63.     _LIMIT 10
  64.  
  65.  

It's smart because it will never crash into a wall, or itself and will (eventually) always get the fruit and grow to fill the garden BUT!
it's about the dumbest smart snake you could ask for.

Can anyone make it smarter? ie get to food faster without crashing into itself when it gets longer.

Oh also does anyone know why this runs to like 487 fruits eaten and not <= 400 that should fill garden with snake segments?

PS I mean theoretically this program should hang when there is no longer a place to put the fruit because the snake has filled the garden 400 squares by my calculations, so how is it going past that point before hanging?
smart snake ai-1.PNG
* smart snake ai-1.PNG (Filesize: 5.08 KB, Dimensions: 402x428, Views: 229)
« Last Edit: March 15, 2020, 02:04:20 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Smart Snake
« Reply #1 on: March 15, 2020, 03:09:16 pm »
Here is what I mean: at the end, it finally hangs at, in this case 473 fruits consumed.

Cool optical illusion too!

 
Smart snake hang at end.PNG

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Smart Snake
« Reply #2 on: March 17, 2020, 01:01:29 am »
The mystery of the extra boxes is solved:
Code: QB64: [Select]
  1. _TITLE "Snake AI-1_1" 'b+ 2020-03-16
  2. '2020-03-14 Snake AI-1 first post
  3. '2020-03-16  Snake AI-1.1 there must be overlap of the snake somewhere!
  4. ' Found! :  White box in square is duplicate segment created
  5. ' as eat fruit and deleted when reaches tail end.
  6.  
  7. CONST sq = 20, sqs = 20, xmax = 400, ymax = 400
  8. SCREEN _NEWIMAGE(xmax, ymax, 32)
  9. _DELAY .25
  10. DIM X(xmax + 100), Y(ymax + 100), overlap(19, 19) AS INTEGER
  11. hx = 10: hy = 10: ax = 15: ay = 15: top = 0: X(top) = hx: Y(top) = hy 'initialize
  12.     _TITLE STR$(top + 1)
  13.     LINE (0, 0)-(xmax, ymax), &HFF006600, BF 'clear garden
  14.  
  15.     '>>>>>>>>>>>       SNAKE BRAIN    <<<<<<<<<<<<<<<
  16.     IF hx = 0 AND hy = 19 THEN
  17.         hy = hy - 1
  18.     ELSEIF hx MOD 2 = 0 AND hy <> 0 AND hy <> 19 THEN
  19.         hy = hy - 1
  20.     ELSEIF hx MOD 2 = 0 AND hy = 0 AND hy <> 19 THEN
  21.         hx = hx + 1
  22.     ELSEIF hx MOD 2 = 1 AND hx <> 19 AND hy < 18 THEN
  23.         hy = hy + 1
  24.     ELSEIF hx MOD 2 = 1 AND hx <> 19 AND hy = 18 THEN
  25.         hx = hx + 1
  26.     ELSEIF hx = 19 AND hy = 19 THEN
  27.         hx = hx - 1
  28.     ELSEIF hy = 19 AND hx <> 0 THEN
  29.         hx = hx - 1
  30.     ELSEIF hx MOD 2 = 1 AND hy = 0 AND hy <> 19 THEN
  31.         hy = hy + 1
  32.     ELSEIF hx = 19 AND hy < 19 THEN
  33.         hy = hy + 1
  34.     END IF
  35.     FOR i = 0 TO top - 1
  36.         X(i) = X(i + 1): Y(i) = Y(i + 1)
  37.     NEXT
  38.     X(top) = hx: Y(top) = hy
  39.     'apple
  40.     IF (ax = hx AND ay = hy) THEN 'snake eats apple, get new apple watch it's not where snake is
  41.         top = top + 1
  42.         X(top) = hx: Y(top) = hy
  43.         DO 'check new apple
  44.             ax = INT(RND * sqs): ay = INT(RND * sqs): good = -1
  45.             FOR i = 0 TO top - 1
  46.                 IF ax = X(i) AND ay = Y(i) THEN good = 0: EXIT FOR
  47.             NEXT
  48.         LOOP UNTIL good
  49.     END IF
  50.     LINE (ax * sq, ay * sq)-STEP(sq - 2, sq - 2), _RGB32(255, 100, 255), BF
  51.  
  52.     'snake
  53.     ERASE overlap
  54.     FOR i = 0 TO top
  55.         IF i = top THEN
  56.             c~& = &HFF000000
  57.         ELSE
  58.             SELECT CASE (top - i) MOD 4
  59.                 CASE 0: c~& = &HFF000088
  60.                 CASE 1: c~& = &HFF880000
  61.                 CASE 2: c~& = &HFFBB8800
  62.                 CASE 3: c~& = &HFF008888
  63.             END SELECT
  64.         END IF
  65.         overlap(X(i), Y(i)) = overlap(X(i), Y(i)) + 1
  66.         LINE (X(i) * sq, Y(i) * sq)-STEP(sq - 2, sq - 2), c~&, BF
  67.         IF overlap(X(i), Y(i)) > 1 THEN LINE (X(i) * sq + .25 * sq, Y(i) * sq + .25 * sq)-STEP(.5 * sq - 2, .5 * sq - 2), &HFFFFFFFF, BF
  68.     NEXT
  69.     _DISPLAY
  70.     IF top < 300 THEN _LIMIT 400 ELSE _LIMIT 20
  71.  
  72.  

 
snake ai-1_1.PNG


Fascinating!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Smart Snake
« Reply #3 on: March 17, 2020, 01:36:10 am »
Fixed :
Code: QB64: [Select]
  1. _TITLE "Snake AI-1_2" 'b+ 2020-03-17
  2. '2020-03-14 Snake AI-1 first post
  3. '2020-03-16  Snake AI-1_1 there must be overlap of the snake somewhere! Aha!
  4. '2020-03-17 Snake AI-1_2 fix the duplicate segment problem
  5. ' Now a new mystery, an occasional flashing duplicate box
  6.  
  7. CONST sq = 20, sqs = 20, xmax = 400, ymax = 400
  8. SCREEN _NEWIMAGE(xmax, ymax, 32)
  9. _DELAY .25
  10. DIM X(xmax + 100), Y(ymax + 100), overlap(19, 19) AS INTEGER
  11. hx = 10: hy = 10: ax = 15: ay = 15: top = 0: X(top) = hx: Y(top) = hy 'initialize
  12.     _TITLE STR$(top + 1)
  13.     LINE (0, 0)-(xmax, ymax), &HFF006600, BF 'clear garden
  14.  
  15.     '>>>>>>>>>>>       SNAKE BRAIN    <<<<<<<<<<<<<<<
  16.     IF hx = 0 AND hy = 19 THEN
  17.         hy = hy - 1
  18.     ELSEIF hx MOD 2 = 0 AND hy <> 0 AND hy <> 19 THEN
  19.         hy = hy - 1
  20.     ELSEIF hx MOD 2 = 0 AND hy = 0 AND hy <> 19 THEN
  21.         hx = hx + 1
  22.     ELSEIF hx MOD 2 = 1 AND hx <> 19 AND hy < 18 THEN
  23.         hy = hy + 1
  24.     ELSEIF hx MOD 2 = 1 AND hx <> 19 AND hy = 18 THEN
  25.         hx = hx + 1
  26.     ELSEIF hx = 19 AND hy = 19 THEN
  27.         hx = hx - 1
  28.     ELSEIF hy = 19 AND hx <> 0 THEN
  29.         hx = hx - 1
  30.     ELSEIF hx MOD 2 = 1 AND hy = 0 AND hy <> 19 THEN
  31.         hy = hy + 1
  32.     ELSEIF hx = 19 AND hy < 19 THEN
  33.         hy = hy + 1
  34.     END IF
  35.     lastx = X(0): last(Y) = Y(0)
  36.     FOR i = 0 TO top - 1
  37.         X(i) = X(i + 1): Y(i) = Y(i + 1)
  38.     NEXT
  39.     X(top) = hx: Y(top) = hy
  40.  
  41.     'apple
  42.     IF (ax = hx AND ay = hy) THEN 'snake eats apple, get new apple watch it's not where snake is
  43.         top = top + 1
  44.         FOR i = top TO 1 STEP -1
  45.             X(i) = X(i - 1): Y(i) = Y(i - 1)
  46.         NEXT
  47.         X(0) = lastx: Y(0) = lasty
  48.         'X(top) = hx: Y(top) = hy
  49.         DO 'check new apple
  50.             ax = INT(RND * sqs): ay = INT(RND * sqs): good = -1
  51.             FOR i = 0 TO top
  52.                 IF ax = X(i) AND ay = Y(i) THEN good = 0: EXIT FOR
  53.             NEXT
  54.             IF ax = lastx AND ay = lasty THEN good = 0
  55.         LOOP UNTIL good
  56.     END IF
  57.  
  58.     'snake
  59.     ERASE overlap
  60.     FOR i = 0 TO top
  61.         IF i = top THEN
  62.             c~& = &HFF000000
  63.         ELSE
  64.             SELECT CASE (top - i) MOD 4
  65.                 CASE 0: c~& = &HFF000088
  66.                 CASE 1: c~& = &HFF880000
  67.                 CASE 2: c~& = &HFFBB8800
  68.                 CASE 3: c~& = &HFF008888
  69.             END SELECT
  70.         END IF
  71.         overlap(X(i), Y(i)) = overlap(X(i), Y(i)) + 1
  72.         LINE (X(i) * sq, Y(i) * sq)-STEP(sq - 2, sq - 2), c~&, BF
  73.         IF overlap(X(i), Y(i)) > 1 THEN LINE (X(i) * sq + .25 * sq, Y(i) * sq + .25 * sq)-STEP(.5 * sq - 2, .5 * sq - 2), &HFFFFFFFF, BF
  74.     NEXT
  75.     LINE (ax * sq, ay * sq)-STEP(sq - 2, sq - 2), _RGB32(255, 100, 255), BF
  76.     _DISPLAY
  77.     IF top < 330 THEN _LIMIT 400 ELSE _LIMIT 20
  78.  
  79.  

 
snake ai-1_2 fixed except.PNG


Fixed except we have a new mystery, the occasional flashing duplicate box?

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Smart Snake
« Reply #4 on: March 17, 2020, 10:07:02 pm »
Reworked code and fixed all signs of duplicate segments, you can now toggle between human pilot and AI called Snake Brain, can also toggle pauses and speed or slow snake independently for human and AI. Now ready to plug-in different brains for snake, oh designer coloring too.

Code: QB64: [Select]
  1. _TITLE "Snake AI-1_3 wRules" 'b+ 2020-03-17
  2. '2020-03-14 Snake AI-1 first post
  3. '2020-03-16  Snake AI-1_1 there must be overlap of the snake somewhere! Aha!
  4. '2020-03-17 Snake AI-1_2 fix the duplicate segment problem
  5. ' Now a new mystery, an ocassional flashing duplicate box
  6. '2020-03-17 Install standard snake rules for testing brain evolving
  7. ' First setup XY type and rename and convert variables using XY type.
  8. ' 2nd Make snake brain and whole game only dependent sqrsX, sqrsY and sq for screen size
  9. ' Got it!!! the code ends with hangup head next to fruit with 99 (1 cell less that whole board)
  10. ' cells of snake length, no new place can be found for fruit, perfect finish and no duplicate cells! PLUS
  11. ' now can turn on a dime go up one colume and down the next in 2 key press.
  12. ' Now add autoPilot on -1 / off 0 toggle control, OK snake rules tested when human pilots snake.
  13. ' Help screen & independent speeds for human or AI.
  14.  
  15. 'snakepit constraints   Snake Brain currently needs sqrsX to be even
  16. CONST sq = 20, sqrsX = 20, sqrsY = 20, xmax = sq * sqrsX, ymax = sq * sqrsY
  17. SCREEN _NEWIMAGE(800, 600, 32)
  18. _DELAY .25
  19.  
  20. 'teach UDV
  21. TYPE XY
  22.     X AS INTEGER
  23.     Y AS INTEGER
  24.  
  25. 'shared for screenUpdate
  26. DIM SHARED fruit AS XY, snake(1 TO sqrsX * sqrsY) AS XY, sLen AS INTEGER '< sLen = length of snake
  27. DIM SHARED overlap(sqrsX, sqrsY) AS INTEGER, pal(sqrsX * sqrsY) AS _UNSIGNED LONG, head AS XY
  28. 'other data needed for program
  29. DIM autoPilot AS INTEGER, dx AS INTEGER, dy AS INTEGER, hSpeed, aSpeed
  30.  
  31. help
  32. hSpeed = 3: aSpeed = 20
  33. restart: 'reinitialize
  34. r = .3 + RND * .7: g = r * .5 + RND * .3 - .15: b = .5 * r + RND * .3 - .15
  35. FOR i = 1 TO sqrsX * sqrsY
  36.     pal(i) = _RGB32(84 + 64 * SIN(r + i / 2), 84 + 64 * SIN(g + i / 2), 104 * SIN(b + i / 2))
  37. head.X = sqrsX / 2 - 2: head.Y = sqrsY / 2 - 2
  38. fruit.X = sqrsX / 2 + 2: fruit.Y = sqrsY / 2 + 2
  39. sLen = 1
  40. snake(sLen).X = head.X: snake(sLen).Y = head.Y
  41. autoPilot = 1
  42. dx = 0: dy = 1
  43.     _TITLE STR$(sLen)
  44.     LINE (0, 0)-(xmax, ymax), &HFF884422, BF 'clear snakepit
  45.     IF sLen = sqrsX * sqrsY - 1 THEN screenUpdate: EXIT DO
  46.     key$ = INKEY$
  47.     IF key$ = "q" OR key$ = CHR$(27) THEN '                                           here is quit
  48.         END '
  49.     ELSEIF key$ = "a" THEN '                                                      toggle autoPilot
  50.         autoPilot = 1 - autoPilot
  51.         IF autoPilot = 0 THEN 'try to handover to human without immdeiate body crash
  52.             dx = 0: IF head.X MOD 2 THEN dy = 1 ELSE dy = -1
  53.         END IF
  54.     ELSEIF key$ = "p" THEN '                                                                 pause
  55.         _KEYCLEAR
  56.         WHILE INKEY$ <> "p": _LIMIT 60: WEND
  57.     ELSEIF key$ = "s" THEN
  58.         IF autoPilot AND aSpeed + 5 < 400 THEN aSpeed = aSpeed + 5
  59.         IF autoPilot = 0 AND hSpeed + .5 < 10 THEN hSpeed = hSpeed + .5
  60.     ELSEIF key$ = "-" THEN
  61.         IF autoPilot AND aSpeed - 5 > 0 THEN aSpeed = aSpeed - 5
  62.         IF autoPilot = 0 AND hSpeed - .5 > 1 THEN hSpeed = hSpeed - .5
  63.     END IF '                                                                                      '
  64.     IF autoPilot THEN '                                                 who is piloting the snake?
  65.  
  66.         ' PLUG-IN YOUR Snake Brain AI here
  67.         '===========================================================================  AI Auto Pilot
  68.         snakeBrain
  69.         '=========================================================================================
  70.  
  71.     ELSE ' '=======================================================================  human control
  72.         IF key$ = CHR$(0) + CHR$(72) THEN '                                               up arrow
  73.             dx = 0: dy = -1
  74.         ELSEIF key$ = CHR$(0) + CHR$(80) THEN '                                         down arrow
  75.             dx = 0: dy = 1
  76.         ELSEIF key$ = CHR$(0) + CHR$(77) THEN '                                        right arrow
  77.             dx = 1: dy = 0
  78.         ELSEIF key$ = CHR$(0) + CHR$(75) THEN '                                         left arrow
  79.             dx = -1: dy = 0
  80.         END IF
  81.         head.X = head.X + dx: head.Y = head.Y + dy
  82.     END IF
  83.  
  84.     '                                                                  check snake head with Rules:
  85.     ' 1. Snakepit boundary check, snake hits wall, dies.
  86.     IF head.X < 0 OR head.X > sqrsX - 1 OR head.Y < 0 OR head.Y > sqrsY - 1 THEN
  87.         _TITLE _TRIM$(STR$(sLen)) + " Wall Crash": screenUpdate: EXIT DO
  88.     END IF
  89.  
  90.     ' 2. Snake eats body part, dies. This should kill snake if turn its head back on itself.
  91.     FOR i = 1 TO sLen 'start 1 up from tail segment about to be dropped
  92.         IF head.X = snake(i).X AND head.Y = snake(i).Y THEN
  93.             _TITLE _TRIM$(STR$(sLen)) + " Body Crash": screenUpdate: EXIT DO
  94.         END IF
  95.     NEXT
  96.  
  97.     ' 3. Eats Fruit and grows or just move every segment up 1 space.
  98.     IF (fruit.X = head.X AND fruit.Y = head.Y) THEN '                              snake eats apple
  99.         sLen = sLen + 1
  100.         snake(sLen).X = head.X: snake(sLen).Y = head.Y ' assimilate fruit into head for new segment
  101.         DO 'check new apple
  102.             fruit.X = INT(RND * sqrsX): fruit.Y = INT(RND * sqrsY): good = -1
  103.             FOR i = 1 TO sLen
  104.                 IF fruit.X = snake(i).X AND fruit.Y = snake(i).Y THEN good = 0: EXIT FOR
  105.             NEXT
  106.         LOOP UNTIL good
  107.     ELSE
  108.         FOR i = 1 TO sLen '                                                     move the snake data
  109.             snake(i).X = snake(i + 1).X: snake(i).Y = snake(i + 1).Y
  110.         NEXT
  111.         snake(sLen).X = head.X: snake(sLen).Y = head.Y
  112.     END IF
  113.  
  114.     screenUpdate
  115.  
  116.     IF autoPilot THEN
  117.         'IF sLen < 80 THEN _LIMIT 40 ELSE _LIMIT 10
  118.         _LIMIT aSpeed
  119.     ELSE
  120.         _LIMIT hSpeed
  121.     END IF
  122.  
  123. GOTO restart:
  124.  
  125. SUB screenUpdate ' draw snake and fruit, overlap code debugger
  126.     DIM c~&, i AS INTEGER
  127.  
  128.     ERASE overlap
  129.     FOR i = 1 TO sLen
  130.         IF i = sLen THEN c~& = &HFF000000 ELSE c~& = pal(sLen - i)
  131.  
  132.         'overlap helps debug duplicate square drawing which indicates a flawed code
  133.         overlap(snake(i).X, snake(i).Y) = overlap(snake(i).X, snake(i).Y) + 1
  134.  
  135.         LINE (snake(i).X * sq, snake(i).Y * sq)-STEP(sq - 2, sq - 2), c~&, BF
  136.         IF overlap(snake(i).X, snake(i).Y) > 1 THEN
  137.             LINE (snake(i).X * sq + .25 * sq, snake(i).Y * sq + .25 * sq)_
  138.             -STEP(.5 * sq - 2, .5 * sq - 2), &HFFFFFFFF, BF
  139.         END IF
  140.     NEXT
  141.     LINE (fruit.X * sq, fruit.Y * sq)-STEP(sq - 2, sq - 2), _RGB32(255, 100, 255), BF
  142.     _DISPLAY
  143.  
  144. SUB snakeBrain '>>>>>>>>>>   B+  SNAKE BRAIN  needs sqrsX to be even number  <<<<<<<<<<<<<<<
  145.     IF head.X = 0 AND head.Y = sqrsY - 1 THEN
  146.         head.Y = head.Y - 1
  147.     ELSEIF head.X MOD 2 = 0 AND head.Y <> 0 AND head.Y <> sqrsY - 1 THEN
  148.         head.Y = head.Y - 1
  149.     ELSEIF head.X MOD 2 = 0 AND head.Y = 0 AND head.Y <> sqrsY - 1 THEN
  150.         head.X = head.X + 1
  151.     ELSEIF head.X MOD 2 = 1 AND head.X <> sqrsX - 1 AND head.Y = sqrsY - 2 THEN
  152.         head.X = head.X + 1
  153.     ELSEIF head.X MOD 2 = 1 AND head.X <> sqrsX - 1 AND head.Y < sqrsY - 1 THEN
  154.         head.Y = head.Y + 1
  155.     ELSEIF head.X = sqrsX - 1 AND head.Y = sqrsY - 1 THEN
  156.         head.X = head.X - 1
  157.     ELSEIF head.Y = sqrsY - 1 AND head.X <> 0 THEN
  158.         head.X = head.X - 1
  159.     ELSEIF head.X MOD 2 = 1 AND head.Y = 0 AND head.Y <> sqrsY - 1 THEN
  160.         head.Y = head.Y + 1
  161.     ELSEIF head.X = sqrsX - 1 AND head.Y < sqrsY - 1 THEN
  162.         head.Y = head.Y + 1
  163.     END IF
  164.  
  165. SUB help
  166.     _PRINTSTRING (600, 20), "Keys:"
  167.     _PRINTSTRING (600, 40), "p toggles pause on/off"
  168.     _PRINTSTRING (600, 60), "a toggles autoPilot"
  169.     _PRINTSTRING (600, 100), "arrows control snake"
  170.     _PRINTSTRING (600, 80), "q or esc quits"
  171.     _PRINTSTRING (600, 120), "s increases speed"
  172.     _PRINTSTRING (600, 140), "- decreases speed"
  173.  

 
Snake ai-1_3.PNG
« Last Edit: March 17, 2020, 10:19:38 pm by bplus »

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Smart Snake
« Reply #5 on: March 18, 2020, 02:05:57 am »
Good work, bplus. I personally like the new color of snake. Color of the snake in previous post was irritating to me (IDK why :) ).
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Smart Snake
« Reply #6 on: March 18, 2020, 11:37:43 am »
Thanks Ashish, yeah snake coloring more natural I think.

You know I was hoping to get a little challenge going, Who can build the best snake AI or driver to plug into the game?

Now I wonder if anyone (including myself) can build a driver that can load up on fruit faster and fill the board in fewer steps on average. Because the fruit is placed randomly there will be better and worse runs but all need to get all the fruit eaten without crashing into wall (simple with AI that knows borders) or crashing the snake into it's own body including turning the head 180 degrees back onto it's body. This gets harder as snake gets longer. For humans the hardest part is not turning snake back on itself, IMHO, but for AI getting the fruit without running into another part of the body afterwards is where brains are needed.

So the object is to fill the board with snake until all but one board cell is snake (that starts new game).

Your Snake AI is allowed to know these things:
1. The Boundaries of the snake pit (I no longer call it a garden).
    for x between 0 and sqrsX-1, for y between 0 and sqrsY - 1
    BTW sqrsX is cells across and sqrsY is cells down.
2. Where the fruit is, fruit(x, y)
3. The listing of it's length and body segments, snake(i).(x, y), snake length = sLen
4. Track it's direction, I call dx and dy, the change on the x-axis = dx and the change on y-axis = dy.
    These are always just -1, 0, 1 and if ABS(dx) = 1 then dy = 0 and vice versa.
    ?hmm... use STATIC your own dx, dy in the SnakeBrain SUB (my demo is going strictly by board locations at
     present).
5. Oh! Most important of all, know where it's head is at! head(x, y)
Snake input is all above as SHARED and AI output just says where the head goes next by altering that value in the AI.

Now I realize my tester has to handle the case when both head x, y are 0 (a full stop) or both have a value other than 0 (s.t. the head starts heading diagonally).

My goal here was to create an AI tester, not so much a game with a pretty snake that's just icing ;-))

Update: here is the checks on the head change after the AI changes it in the Snake Brain plug-in code. The code will reset head(x, y) back if there is a problem with the head(x, y) returned from snake brain.

Code: QB64: [Select]
  1. _TITLE "Snake AI-1_4 fix tester" 'b+ 2020-03-18
  2. '2020-03-14 Snake AI-1 first post
  3. '2020-03-16  Snake AI-1_1 there must be overlap of the snake somewhere! Aha!
  4. '2020-03-17 Snake AI-1_2 fix the duplicate segment problem
  5. ' Now a new mystery, an ocassional flashing duplicate box
  6. '2020-03-17 Install standard snake rules for testing brain evolving
  7. ' First setup XY type and rename and convert variables using XY type.
  8. ' 2nd Make snake brain and whole game only dependent sqrsX, sqrsY and sq for screen size
  9. ' Got it!!! the code ends with hangup head next to fruit with 99 (1 cell less that whole board)
  10. ' cells of snake length, no new place can be found for fruit, perfect finish and no duplicate
  11. ' cells! PLUS now can turn on a dime go up one colume and down the next in 2 key press.
  12. ' Now add autoPilot on -1 / off 0 toggle control, OK snake rules tested when human pilots snake.
  13. ' Help screen & independent speeds for human or AI.
  14.  
  15. '2020-03-18  "Snake AI-1_4 fix tester" The AI tester needs to save Head(x, y) in case the AI
  16. ' does not change the head(x, y) or tries to move it diagonally.
  17.  
  18. 'snakepit constraints   Snake Brain currently needs sqrsX to be even
  19. CONST sq = 20, sqrsX = 20, sqrsY = 20, xmax = sq * sqrsX, ymax = sq * sqrsY
  20. SCREEN _NEWIMAGE(800, 600, 32)
  21. _DELAY .25
  22.  
  23. 'teach UDV
  24. TYPE XY
  25.     X AS INTEGER
  26.     Y AS INTEGER
  27.  
  28. 'shared for screenUpdate
  29. DIM SHARED fruit AS XY, snake(1 TO sqrsX * sqrsY) AS XY, sLen AS INTEGER '< sLen = length of snake
  30. DIM SHARED overlap(sqrsX, sqrsY) AS INTEGER, pal(sqrsX * sqrsY) AS _UNSIGNED LONG, head AS XY
  31. 'other data needed for program
  32. DIM autoPilot AS INTEGER, dx AS INTEGER, dy AS INTEGER, hSpeed, aSpeed
  33. DIM saveHead AS XY
  34.  
  35. help
  36. hSpeed = 3: aSpeed = 20
  37.  
  38. restart: 'reinitialize
  39. r = .3 + RND * .7: g = r * .5 + RND * .3 - .15: b = .5 * r + RND * .3 - .15
  40. FOR i = 1 TO sqrsX * sqrsY
  41.     pal(i) = _RGB32(84 + 64 * SIN(r + i / 2), 84 + 64 * SIN(g + i / 2), 104 * SIN(b + i / 2))
  42. head.X = sqrsX / 2 - 2: head.Y = sqrsY / 2 - 2
  43. fruit.X = sqrsX / 2 + 2: fruit.Y = sqrsY / 2 + 2
  44. sLen = 1
  45. snake(sLen).X = head.X: snake(sLen).Y = head.Y
  46. autoPilot = 1
  47. dx = 0: dy = 1
  48.     _TITLE STR$(sLen)
  49.     LINE (0, 0)-(xmax, ymax), &HFF884422, BF 'clear snakepit
  50.     IF sLen = sqrsX * sqrsY - 1 THEN screenUpdate: EXIT DO
  51.     KEY$ = INKEY$
  52.     IF KEY$ = "q" OR KEY$ = CHR$(27) THEN '                                           here is quit
  53.         END '
  54.     ELSEIF KEY$ = "a" THEN '                                                      toggle autoPilot
  55.         autoPilot = 1 - autoPilot
  56.         IF autoPilot = 0 THEN 'try to handover to human without immdeiate body crash
  57.             dx = 0: IF head.X MOD 2 THEN dy = 1 ELSE dy = -1
  58.         END IF
  59.     ELSEIF KEY$ = "p" THEN '                                                                 pause
  60.         _KEYCLEAR
  61.         WHILE INKEY$ <> "p": _LIMIT 60: WEND
  62.     ELSEIF KEY$ = "s" THEN
  63.         IF autoPilot AND aSpeed + 5 < 400 THEN aSpeed = aSpeed + 5
  64.         IF autoPilot = 0 AND hSpeed + .5 < 10 THEN hSpeed = hSpeed + .5
  65.     ELSEIF KEY$ = "-" THEN
  66.         IF autoPilot AND aSpeed - 5 > 0 THEN aSpeed = aSpeed - 5
  67.         IF autoPilot = 0 AND hSpeed - .5 > 1 THEN hSpeed = hSpeed - .5
  68.     END IF '                                                                                      '
  69.     IF autoPilot THEN '                                                 who is piloting the snake?
  70.  
  71.         saveHead.X = head.X: saveHead.Y = head.Y
  72.         tryAgain:
  73.         head.X = saveHead.X: head.Y = saveHead.Y
  74.         ' PLUG-IN YOUR Snake Brain AI here
  75.         '===========================================================================  AI Auto Pilot
  76.         snakeBrain
  77.         '=========================================================================================
  78.  
  79.         'check changes to head (x, y)
  80.         IF ABS(saveHead.X - head.X) = 0 THEN 'must have diffence in y's
  81.             IF ABS(saveHead.Y - head.Y) <> 1 THEN GOTO tryAgain
  82.         ELSEIF ABS(saveHead.Y - head.Y) = 0 THEN
  83.             IF ABS(saveHead.X - head.X) <> 1 THEN GOTO tryAgain
  84.         ELSE ' must have a difference of 0 in either x or y but not both
  85.             GOTO tryAgain
  86.         END IF
  87.  
  88.     ELSE ' '=======================================================================  human control
  89.         IF KEY$ = CHR$(0) + CHR$(72) THEN '                                               up arrow
  90.             dx = 0: dy = -1
  91.         ELSEIF KEY$ = CHR$(0) + CHR$(80) THEN '                                         down arrow
  92.             dx = 0: dy = 1
  93.         ELSEIF KEY$ = CHR$(0) + CHR$(77) THEN '                                        right arrow
  94.             dx = 1: dy = 0
  95.         ELSEIF KEY$ = CHR$(0) + CHR$(75) THEN '                                         left arrow
  96.             dx = -1: dy = 0
  97.         END IF
  98.         head.X = head.X + dx: head.Y = head.Y + dy
  99.     END IF
  100.  
  101.     '                                                                  check snake head with Rules:
  102.     ' 1. Snakepit boundary check, snake hits wall, dies.
  103.     IF head.X < 0 OR head.X > sqrsX - 1 OR head.Y < 0 OR head.Y > sqrsY - 1 THEN
  104.         _TITLE _TRIM$(STR$(sLen)) + " Wall Crash": screenUpdate: EXIT DO
  105.     END IF
  106.  
  107.     ' 2. Snake eats body part, dies. This should kill snake if turn its head back on itself.
  108.     FOR i = 1 TO sLen 'start 1 up from tail segment about to be dropped
  109.         IF head.X = snake(i).X AND head.Y = snake(i).Y THEN
  110.             _TITLE _TRIM$(STR$(sLen)) + " Body Crash": screenUpdate: EXIT DO
  111.         END IF
  112.     NEXT
  113.  
  114.     ' 3. Eats Fruit and grows or just move every segment up 1 space.
  115.     IF (fruit.X = head.X AND fruit.Y = head.Y) THEN '                              snake eats apple
  116.         sLen = sLen + 1
  117.         snake(sLen).X = head.X: snake(sLen).Y = head.Y ' assimilate fruit into head for new segment
  118.         DO 'check new apple
  119.             fruit.X = INT(RND * sqrsX): fruit.Y = INT(RND * sqrsY): good = -1
  120.             FOR i = 1 TO sLen
  121.                 IF fruit.X = snake(i).X AND fruit.Y = snake(i).Y THEN good = 0: EXIT FOR
  122.             NEXT
  123.         LOOP UNTIL good
  124.     ELSE
  125.         FOR i = 1 TO sLen '                                                     move the snake data
  126.             snake(i).X = snake(i + 1).X: snake(i).Y = snake(i + 1).Y
  127.         NEXT
  128.         snake(sLen).X = head.X: snake(sLen).Y = head.Y
  129.     END IF
  130.  
  131.     screenUpdate
  132.  
  133.     IF autoPilot THEN
  134.         'IF sLen < 80 THEN _LIMIT 40 ELSE _LIMIT 10
  135.         _LIMIT aSpeed
  136.     ELSE
  137.         _LIMIT hSpeed
  138.     END IF
  139.  
  140. GOTO restart:
  141.  
  142. SUB screenUpdate ' draw snake and fruit, overlap code debugger
  143.     DIM c~&, i AS INTEGER
  144.  
  145.     ERASE overlap
  146.     FOR i = 1 TO sLen
  147.         IF i = sLen THEN c~& = &HFF000000 ELSE c~& = pal(sLen - i)
  148.  
  149.         'overlap helps debug duplicate square drawing which indicates a flawed code
  150.         overlap(snake(i).X, snake(i).Y) = overlap(snake(i).X, snake(i).Y) + 1
  151.  
  152.         LINE (snake(i).X * sq, snake(i).Y * sq)-STEP(sq - 2, sq - 2), c~&, BF
  153.         IF overlap(snake(i).X, snake(i).Y) > 1 THEN
  154.             LINE (snake(i).X * sq + .25 * sq, snake(i).Y * sq + .25 * sq)_
  155.             -STEP(.5 * sq - 2, .5 * sq - 2), &HFFFFFFFF, BF
  156.         END IF
  157.     NEXT
  158.     LINE (fruit.X * sq, fruit.Y * sq)-STEP(sq - 2, sq - 2), _RGB32(255, 100, 255), BF
  159.     _DISPLAY
  160.  
  161. SUB snakeBrain '>>>>>>>>>>   B+  SNAKE BRAIN  needs sqrsX to be even number  <<<<<<<<<<<<<<<
  162.     IF head.X = 0 AND head.Y = sqrsY - 1 THEN
  163.         head.Y = head.Y - 1
  164.     ELSEIF head.X MOD 2 = 0 AND head.Y <> 0 AND head.Y <> sqrsY - 1 THEN
  165.         head.Y = head.Y - 1
  166.     ELSEIF head.X MOD 2 = 0 AND head.Y = 0 AND head.Y <> sqrsY - 1 THEN
  167.         head.X = head.X + 1
  168.     ELSEIF head.X MOD 2 = 1 AND head.X <> sqrsX - 1 AND head.Y = sqrsY - 2 THEN
  169.         head.X = head.X + 1
  170.     ELSEIF head.X MOD 2 = 1 AND head.X <> sqrsX - 1 AND head.Y < sqrsY - 1 THEN
  171.         head.Y = head.Y + 1
  172.     ELSEIF head.X = sqrsX - 1 AND head.Y = sqrsY - 1 THEN
  173.         head.X = head.X - 1
  174.     ELSEIF head.Y = sqrsY - 1 AND head.X <> 0 THEN
  175.         head.X = head.X - 1
  176.     ELSEIF head.X MOD 2 = 1 AND head.Y = 0 AND head.Y <> sqrsY - 1 THEN
  177.         head.Y = head.Y + 1
  178.     ELSEIF head.X = sqrsX - 1 AND head.Y < sqrsY - 1 THEN
  179.         head.Y = head.Y + 1
  180.     END IF
  181.  
  182. SUB help
  183.     _PRINTSTRING (600, 20), "Keys:"
  184.     _PRINTSTRING (600, 40), "p toggles pause on/off"
  185.     _PRINTSTRING (600, 60), "a toggles autoPilot"
  186.     _PRINTSTRING (600, 100), "arrows control snake"
  187.     _PRINTSTRING (600, 80), "q or esc quits"
  188.     _PRINTSTRING (600, 120), "s increases speed"
  189.     _PRINTSTRING (600, 140), "- decreases speed"
  190.  
  191.  


Update: the more I think about it, the more the Snake Brain needs access to or shared dx and dy. So I have to change the tester again to save those too before call to SnakeBrain plug-in driver... after lunch and errands, I will update again, sorry.

Update 2 (1 hour later): and the more I think about it the AI is likely to return the same change to head over and over and we get stuck in a loop so we might have to end with error message.
« Last Edit: March 18, 2020, 05:24:33 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Smart Snake
« Reply #7 on: March 18, 2020, 11:27:19 pm »
Got it! If there is an error in AI the control of snake is turned over to human with a beep to signal the switch.

I switched dx, dy to change AS XY (type) and now like the human control, the AI only changes the change.X, change.Y values, then the code takes over to update the head and check the rules for crashes, eats or just plain moves.

I had to rewrite the SnakeBrain SUB with these changes and cause an immediate exit if sqrsX (number of square on x-axis) is odd because at present it depends on an even amount of columns. It throws an error and made for excellent way to check the change checker part of the code. Did some more formal commenting of all the code and maybe now it is should be ready to try some brain transplants.

Code: QB64: [Select]
  1. _TITLE "Snake AI-1_5 SHARE change AS XY" 'b+ 2020-03-18
  2. '2020-03-14 Snake AI-1 first post
  3. '2020-03-16  Snake AI-1_1 there must be overlap of the snake somewhere! Aha!
  4. '2020-03-17 Snake AI-1_2 fix the duplicate segment problem
  5. ' Now a new mystery, an ocassional flashing duplicate box
  6. '2020-03-17 Install standard snake rules for testing brain evolving
  7. ' First setup XY type and rename and convert variables using XY type.
  8. ' 2nd Make snake brain and whole game only dependent sqrsX, sqrsY and sq for screen size
  9. ' Got it!!! the code ends with hangup head next to fruit with 99 (1 cell less that whole board)
  10. ' cells of snake length, no new place can be found for fruit, perfect finish and no duplicate
  11. ' cells! PLUS now can turn on a dime go up one colume and down the next in 2 key press.
  12. ' Now add autoPilot on -1 / off 0 toggle control, OK snake rules tested when human pilots snake.
  13. ' Help screen & independent speeds for human or AI.
  14. '2020-03-18  "Snake AI-1_4 fix tester" The AI tester needs to save Head(x, y) in case the AI
  15. ' does not change the head(x, y) or tries to move it diagonally.
  16.  
  17. '2020-03-18 Snake AI-1_5 SHARE change AS XY
  18. ' DIM SHARE change AS XY or change.x, change.y replaces variables called dx, dy.
  19. ' I decided to switch over to human control if AI fails to return a proper change.
  20. ' AI must leave change.x, change.y ready for human to take over control which means my changing
  21. ' the code for toggling the autopilot and adding change.x, change.y updates in my snakeBrain SUB.
  22. ' Rewrite SnakeBrain using only change.X and change.Y now. A BEEP will indicate an AI error and
  23. ' signal control returned to human. This noted in Key Help part of screen.
  24.  
  25. '  Snakepit Dimensions: square size = sq, sqrsX = # of squares along x-axis and sqrsY squares down.
  26. CONST sq = 20, sqrsX = 20, sqrsY = 20, xmax = sq * sqrsX, ymax = sq * sqrsY
  27. SCREEN _NEWIMAGE(800, 600, 32)
  28. _DELAY .25
  29.  
  30. ' Usually used to give a point on 2D board a single name that has an X dimension and a Y dimension.
  31. TYPE XY
  32.     X AS INTEGER
  33.     Y AS INTEGER
  34.  
  35. '   SHARED variables for any version of SnakeBrain SUB to act as autoPilot for snake snake.
  36. DIM SHARED change AS XY '                            directs the head direction through AI or Human
  37. DIM SHARED head AS XY '                           leads the way of the snake(body) through snakepit
  38. DIM SHARED sLen AS INTEGER '                                                        length of snake
  39. DIM SHARED snake(1 TO sqrsX * sqrsY) AS XY '                   whole snake, head is at index = sLen
  40. DIM SHARED fruit AS XY '     as snake eats fruit it grows, object is to grow snake to fill snakepit
  41.  
  42. '   SHARED for screenUpdate
  43. DIM SHARED pal(sqrsX * sqrsY) AS _UNSIGNED LONG '                                  for snake colors
  44.  
  45. 'other data needed for program
  46. DIM autoPilot AS INTEGER, hSpeed, aSpeed, saveChange AS XY
  47.  
  48. help '                                                                                     Key Menu
  49. hSpeed = 3: aSpeed = 20 '                     autopilot speed is independent of human control speed
  50.  
  51. restart: '                                                                             reinitialize
  52. r = .3 + RND * .7: g = r * .5 + RND * .3 - .15: b = .5 * r + RND * .3 - .15 '    rnd pal color vars
  53. FOR i = 1 TO sqrsX * sqrsY '                               enough colors for snake to fill snakepit
  54.     pal(i) = _RGB32(84 + 64 * SIN(r + i / 2), 84 + 64 * SIN(g + i / 2), 104 * SIN(b + i / 2))
  55. head.X = sqrsX / 2 - 3: head.Y = sqrsY / 2 - 3 '                                         head start
  56. fruit.X = sqrsX / 2 + 2: fruit.Y = sqrsY / 2 + 2 '                                      first fruit
  57. sLen = 1 '                                                           for starters snake is all head
  58. snake(sLen).X = head.X: snake(sLen).Y = head.Y '                         head is always at sLen end
  59. autoPilot = 1 '                                                              start snake body count
  60. change.X = 0: change.Y = 1 '                      head snake down board, Y direction of first fruit
  61.     _TITLE STR$(sLen)
  62.     LINE (0, 0)-(xmax, ymax), &HFF884422, BF '                                       clear snakepit
  63.     IF sLen = sqrsX * sqrsY - 1 THEN screenUpdate: EXIT DO '             game is won! start another
  64.     KEY$ = INKEY$
  65.     IF KEY$ = "q" OR KEY$ = CHR$(27) THEN '                                            here is quit
  66.         END '
  67.     ELSEIF KEY$ = "a" THEN '                                                       toggle autoPilot
  68.         autoPilot = 1 - autoPilot '   it is now up to AI to keep change updated for human take over
  69.     ELSEIF KEY$ = "p" THEN '                               pause toggle p starts pause p ends pause
  70.         _KEYCLEAR: WHILE INKEY$ <> "p": _LIMIT 60: WEND
  71.     ELSEIF KEY$ = "s" THEN
  72.         IF autoPilot AND aSpeed + 5 < 400 THEN aSpeed = aSpeed + 5 ' max autopilot speed is 400 !!!
  73.         IF autoPilot = 0 AND hSpeed + .5 < 10 THEN hSpeed = hSpeed + .5 '     max human speed is 10
  74.     ELSEIF KEY$ = "-" THEN
  75.         IF autoPilot AND aSpeed - 5 > 0 THEN aSpeed = aSpeed - 5
  76.         IF autoPilot = 0 AND hSpeed - .5 > 1 THEN hSpeed = hSpeed - .5
  77.     END IF '                                                                                      '
  78.  
  79.     IF autoPilot THEN '                                                 who is piloting the snake?
  80.  
  81.         saveChange.X = change.X: saveChange.Y = change.Y '   if AI screws up then human takes over
  82.  
  83.         ' PLUG-IN YOUR Snake Brain AI here
  84.         '=========================================================================== AI Auto Pilot
  85.         snakeBrain
  86.         '=========================================================================================
  87.  
  88.         'check changes
  89.         IF ABS(change.X) = 0 THEN '                                      must have diffence in y's
  90.             IF ABS(change.Y) <> 1 THEN autoPilot = 0 '                       error switch to human
  91.         ELSEIF ABS(change.Y) = 0 THEN
  92.             IF ABS(change.X) <> 1 THEN autoPilot = 0 '                       error switch to human
  93.         ELSE '                           must have a 0 in either change.x or change.y but not both
  94.             autoPilot = 0 '                                                  error switch to human
  95.         END IF
  96.         IF autoPilot = 0 THEN '              switching control over to human restore change values
  97.             change.X = saveChange.X: change.Y = saveChange.Y: BEEP '                   alert human
  98.         END IF
  99.  
  100.     ELSE '  =======================================================================  human control
  101.         IF KEY$ = CHR$(0) + CHR$(72) THEN '                                               up arrow
  102.             change.X = 0: change.Y = -1
  103.         ELSEIF KEY$ = CHR$(0) + CHR$(80) THEN '                                         down arrow
  104.             change.X = 0: change.Y = 1
  105.         ELSEIF KEY$ = CHR$(0) + CHR$(77) THEN '                                        right arrow
  106.             change.X = 1: change.Y = 0
  107.         ELSEIF KEY$ = CHR$(0) + CHR$(75) THEN '                                         left arrow
  108.             change.X = -1: change.Y = 0
  109.         END IF
  110.  
  111.     END IF
  112.     head.X = head.X + change.X: head.Y = head.Y + change.Y '            OK human or AI have spoken
  113.  
  114.     '   ============================  check snake head with Rules: ===============================
  115.  
  116.     ' 1. Snakepit boundary check, snake hits wall, dies.
  117.     IF head.X < 0 OR head.X > sqrsX - 1 OR head.Y < 0 OR head.Y > sqrsY - 1 THEN
  118.         _TITLE _TRIM$(STR$(sLen)) + " Wall Crash": screenUpdate: EXIT DO
  119.     END IF
  120.  
  121.     ' 2. Snake eats body part, dies. This should kill snake if turn its head back on itself.
  122.     FOR i = 1 TO sLen '                                              did head just crash into body?
  123.         IF head.X = snake(i).X AND head.Y = snake(i).Y THEN
  124.             _TITLE _TRIM$(STR$(sLen)) + " Body Crash": screenUpdate: EXIT DO '                 yes!
  125.         END IF
  126.     NEXT '                                                                                       no
  127.  
  128.     ' 3. Eats Fruit and grows or just move every segment up 1 space.
  129.     IF (fruit.X = head.X AND fruit.Y = head.Y) THEN '                              snake eats fruit
  130.         sLen = sLen + 1
  131.         snake(sLen).X = head.X: snake(sLen).Y = head.Y ' assimilate fruit into head for new segment
  132.         DO 'check new apple
  133.             fruit.X = INT(RND * sqrsX): fruit.Y = INT(RND * sqrsY): good = -1
  134.             FOR i = 1 TO sLen
  135.                 IF fruit.X = snake(i).X AND fruit.Y = snake(i).Y THEN good = 0: EXIT FOR
  136.             NEXT
  137.         LOOP UNTIL good
  138.     ELSE
  139.         FOR i = 1 TO sLen '                            move the snake data down 1 dropping off last
  140.             snake(i).X = snake(i + 1).X: snake(i).Y = snake(i + 1).Y
  141.         NEXT
  142.         snake(sLen).X = head.X: snake(sLen).Y = head.Y '               and adding new head position
  143.     END IF
  144.  
  145.     screenUpdate '                                                     on with the show this is it!
  146.     IF autoPilot THEN _LIMIT aSpeed ELSE _LIMIT hSpeed ' independent speed control for human and AI
  147. _DELAY 3 '                                                                   win or loose, go again
  148. GOTO restart:
  149.  
  150. SUB screenUpdate ' draw snake and fruit, overlap code debugger
  151.     DIM c~&, i AS INTEGER, overlap(sqrsX, sqrsY) AS INTEGER
  152.     FOR i = 1 TO sLen
  153.         IF i = sLen THEN c~& = &HFF000000 ELSE c~& = pal(sLen - i)
  154.  
  155.         '                overlap helps debug duplicate square drawing which indicates a flawed code
  156.         overlap(snake(i).X, snake(i).Y) = overlap(snake(i).X, snake(i).Y) + 1
  157.  
  158.         LINE (snake(i).X * sq, snake(i).Y * sq)-STEP(sq - 2, sq - 2), c~&, BF
  159.         IF overlap(snake(i).X, snake(i).Y) > 1 THEN ' show visually where code flaws effect display
  160.             LINE (snake(i).X * sq + .25 * sq, snake(i).Y * sq + .25 * sq)_
  161.             -STEP(.5 * sq - 2, .5 * sq - 2), &HFFFFFFFF, BF
  162.         END IF
  163.     NEXT
  164.     LINE (fruit.X * sq, fruit.Y * sq)-STEP(sq - 2, sq - 2), _RGB32(255, 100, 255), BF
  165.     _DISPLAY
  166.  
  167. SUB snakeBrain '>>>>>>>>>>   B+  SNAKE BRAIN  needs sqrsX to be even number  <<<<<<<<<<<<<<<
  168.  
  169.     IF sqrsX MOD 2 = 1 THEN change.X = 0: change.Y = 0: EXIT SUB 'throw error for code check to
  170.     '                                                      discover and switch to human control
  171.  
  172.     IF head.X = 0 AND head.Y = sqrsY - 1 THEN
  173.         change.X = 0: change.Y = -1
  174.     ELSEIF head.X MOD 2 = 0 AND head.Y <> 0 AND head.Y <> sqrsY - 1 THEN
  175.         change.X = 0: change.Y = -1
  176.     ELSEIF head.X MOD 2 = 0 AND head.Y = 0 AND head.Y <> sqrsY - 1 THEN
  177.         change.X = 1: change.Y = 0
  178.     ELSEIF head.X MOD 2 = 1 AND head.X <> sqrsX - 1 AND head.Y = sqrsY - 2 THEN
  179.         change.X = 1: change.Y = 0
  180.     ELSEIF head.X MOD 2 = 1 AND head.X <> sqrsX - 1 AND head.Y < sqrsY - 1 THEN
  181.         change.X = 0: change.Y = 1
  182.     ELSEIF head.X = sqrsX - 1 AND head.Y = sqrsY - 1 THEN
  183.         change.X = -1: change.Y = 0
  184.     ELSEIF head.Y = sqrsY - 1 AND head.X <> 0 THEN
  185.         change.X = -1: change.Y = 0
  186.     ELSEIF head.X MOD 2 = 1 AND head.Y = 0 AND head.Y <> sqrsY - 1 THEN
  187.         change.X = 0: change.Y = 1
  188.     ELSEIF head.X = sqrsX - 1 AND head.Y < sqrsY - 1 THEN
  189.         change.X = 0: change.Y = 1
  190.     END IF
  191.  
  192. SUB help
  193.     _PRINTSTRING (610, 20), "Keys:"
  194.     _PRINTSTRING (610, 40), "p toggles pause on/off"
  195.     _PRINTSTRING (610, 60), "a toggles autoPilot"
  196.     _PRINTSTRING (610, 100), "arrows control snake"
  197.     _PRINTSTRING (610, 80), "q or esc quits"
  198.     _PRINTSTRING (610, 120), "s increases speed"
  199.     _PRINTSTRING (610, 140), "- decreases speed"
  200.     _PRINTSTRING (610, 200), "A BEEP means AI error,"
  201.     _PRINTSTRING (610, 216), "human put in control."
  202.  
  203.  


Too bad I can't have 2 best Answers but the information provided in reply above is going to start a manual.

« Last Edit: March 18, 2020, 11:33:18 pm by bplus »

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Smart Snake
« Reply #8 on: March 19, 2020, 12:30:21 pm »
@bplus
I attepmt to create my AI for the snake. Well, it does not fill the whole tile for now but it does grow faster than yours.
The best score which I saw it making was 49 on my system. I know it can do even better if I give more time to it.
The code of AI is crazy. It is fun to see how it makes its decision. Sometime, it just get stuck in an infinite loop and snake start
to follow a circular path.

Code: QB64: [Select]
  1. 'Ashish MOD
  2. 'Sorry bplus, but modified your a code a little. ;)
  3.  
  4. 'debuging, if there is AI error, then prints the change value along with state of AI SUB
  5. DIM SHARED state$ 'for debuging
  6.  
  7. _TITLE "Snake AI-1_5 SHARE change AS XY" 'b+ 2020-03-18
  8. '2020-03-14 Snake AI-1 first post
  9. '2020-03-16  Snake AI-1_1 there must be overlap of the snake somewhere! Aha!
  10. '2020-03-17 Snake AI-1_2 fix the duplicate segment problem
  11. ' Now a new mystery, an ocassional flashing duplicate box
  12. '2020-03-17 Install standard snake rules for testing brain evolving
  13. ' First setup XY type and rename and convert variables using XY type.
  14. ' 2nd Make snake brain and whole game only dependent sqrsX, sqrsY and sq for screen size
  15. ' Got it!!! the code ends with hangup head next to fruit with 99 (1 cell less that whole board)
  16. ' cells of snake length, no new place can be found for fruit, perfect finish and no duplicate
  17. ' cells! PLUS now can turn on a dime go up one colume and down the next in 2 key press.
  18. ' Now add autoPilot on -1 / off 0 toggle control, OK snake rules tested when human pilots snake.
  19. ' Help screen & independent speeds for human or AI.
  20. '2020-03-18  "Snake AI-1_4 fix tester" The AI tester needs to save Head(x, y) in case the AI
  21. ' does not change the head(x, y) or tries to move it diagonally.
  22.  
  23. '2020-03-18 Snake AI-1_5 SHARE change AS XY
  24. ' DIM SHARE change AS XY or change.x, change.y replaces variables called dx, dy.
  25. ' I decided to switch over to human control if AI fails to return a proper change.
  26. ' AI must leave change.x, change.y ready for human to take over control which means my changing
  27. ' the code for toggling the autopilot and adding change.x, change.y updates in my snakeBrain SUB.
  28. ' Rewrite SnakeBrain using only change.X and change.Y now. A BEEP will indicate an AI error and
  29. ' signal control returned to human. This noted in Key Help part of screen.
  30.  
  31. '################ MOD by Ashish ######################
  32. 'Added my own AI. It took 3 hours xD
  33.  
  34. '  Snakepit Dimensions: square size = sq, sqrsX = # of squares along x-axis and sqrsY squares down.
  35. CONST sq = 20, sqrsX = 20, sqrsY = 20, xmax = sq * sqrsX, ymax = sq * sqrsY
  36. SCREEN _NEWIMAGE(800, 600, 32)
  37. _DELAY .25
  38.  
  39. ' Usually used to give a point on 2D board a single name that has an X dimension and a Y dimension.
  40. TYPE XY
  41.     X AS INTEGER
  42.     Y AS INTEGER
  43.  
  44. '   SHARED variables for any version of SnakeBrain SUB to act as autoPilot for snake snake.
  45. DIM SHARED change AS XY '                            directs the head direction through AI or Human
  46. DIM SHARED head AS XY '                           leads the way of the snake(body) through snakepit
  47. DIM SHARED sLen AS INTEGER '                                                        length of snake
  48. DIM SHARED snake(1 TO sqrsX * sqrsY) AS XY '                   whole snake, head is at index = sLen
  49. DIM SHARED fruit AS XY '     as snake eats fruit it grows, object is to grow snake to fill snakepit
  50.  
  51. '   SHARED for screenUpdate
  52. DIM SHARED pal(sqrsX * sqrsY) AS _UNSIGNED LONG '                                  for snake colors
  53. 'other data needed for program
  54. DIM autoPilot AS INTEGER, hSpeed, aSpeed, saveChange AS XY
  55.  
  56. help '                                                                                     Key Menu
  57. hSpeed = 3: aSpeed = 20 '                     autopilot speed is independent of human control speed
  58.  
  59. restart: '                                                                             reinitialize
  60. r = .3 + RND * .7: g = r * .5 + RND * .3 - .15: b = .5 * r + RND * .3 - .15 '    rnd pal color vars
  61. FOR i = 1 TO sqrsX * sqrsY '                               enough colors for snake to fill snakepit
  62.     pal(i) = _RGB32(84 + 64 * SIN(r + i / 2), 84 + 64 * SIN(g + i / 2), 104 * SIN(b + i / 2))
  63. head.X = sqrsX / 2 - 3: head.Y = sqrsY / 2 - 3 '                                         head start
  64. fruit.X = sqrsX / 2 + 2: fruit.Y = sqrsY / 2 + 2 '                                      first fruit
  65. sLen = 1 '                                                           for starters snake is all head
  66. snake(sLen).X = head.X: snake(sLen).Y = head.Y '                         head is always at sLen end
  67. autoPilot = 1 '                                                              start snake body count
  68. change.X = 0: change.Y = 1 '                      head snake down board, Y direction of first fruit
  69.     _TITLE STR$(sLen)
  70.     LINE (0, 0)-(xmax, ymax), &HFF884422, BF '                                       clear snakepit
  71.     IF sLen = sqrsX * sqrsY - 1 THEN screenUpdate: EXIT DO '             game is won! start another
  72.     KEY$ = INKEY$
  73.     IF KEY$ = "q" OR KEY$ = CHR$(27) THEN '                                            here is quit
  74.         END '
  75.     ELSEIF KEY$ = "a" THEN '                                                       toggle autoPilot
  76.         autoPilot = 1 - autoPilot '   it is now up to AI to keep change updated for human take over
  77.     ELSEIF KEY$ = "p" THEN '                               pause toggle p starts pause p ends pause
  78.         _KEYCLEAR: WHILE INKEY$ <> "p": _LIMIT 60: WEND
  79.     ELSEIF KEY$ = "s" THEN
  80.         IF autoPilot AND aSpeed + 5 < 400 THEN aSpeed = aSpeed + 5 ' max autopilot speed is 400 !!!
  81.         IF autoPilot = 0 AND hSpeed + .5 < 10 THEN hSpeed = hSpeed + .5 '     max human speed is 10
  82.     ELSEIF KEY$ = "-" THEN
  83.         IF autoPilot AND aSpeed - 5 > 0 THEN aSpeed = aSpeed - 5
  84.         IF autoPilot = 0 AND hSpeed - .5 > 1 THEN hSpeed = hSpeed - .5
  85.     END IF '                                                                                      '
  86.  
  87.     IF autoPilot THEN '                                                 who is piloting the snake?
  88.  
  89.         saveChange.X = change.X: saveChange.Y = change.Y '   if AI screws up then human takes over
  90.  
  91.         ' PLUG-IN YOUR Snake Brain AI here
  92.         '=========================================================================== AI Auto Pilot
  93.         snakeBrain
  94.         '=========================================================================================
  95.  
  96.         'check changes
  97.         IF ABS(change.X) = 0 THEN '                                      must have diffence in y's
  98.             IF ABS(change.Y) <> 1 THEN autoPilot = 0 '                       error switch to human
  99.         ELSEIF ABS(change.Y) = 0 THEN
  100.             IF ABS(change.X) <> 1 THEN autoPilot = 0 '                       error switch to human
  101.         ELSE '                           must have a 0 in either change.x or change.y but not both
  102.             autoPilot = 0 '                                                  error switch to human
  103.         END IF
  104.         'DEBUG
  105.         IF autoPilot = 0 THEN
  106.             _ECHO STR$(change.X) + "," + STR$(change.Y)
  107.             _ECHO state$
  108.             SLEEP
  109.         END IF
  110.         IF autoPilot = 0 THEN '              switching control over to human restore change values
  111.             change.X = saveChange.X: change.Y = saveChange.Y: BEEP '                   alert human
  112.         END IF
  113.  
  114.     ELSE '  =======================================================================  human control
  115.         IF KEY$ = CHR$(0) + CHR$(72) THEN '                                               up arrow
  116.             change.X = 0: change.Y = -1
  117.         ELSEIF KEY$ = CHR$(0) + CHR$(80) THEN '                                         down arrow
  118.             change.X = 0: change.Y = 1
  119.         ELSEIF KEY$ = CHR$(0) + CHR$(77) THEN '                                        right arrow
  120.             change.X = 1: change.Y = 0
  121.         ELSEIF KEY$ = CHR$(0) + CHR$(75) THEN '                                         left arrow
  122.             change.X = -1: change.Y = 0
  123.         END IF
  124.  
  125.     END IF
  126.     head.X = head.X + change.X: head.Y = head.Y + change.Y '            OK human or AI have spoken
  127.  
  128.     '   ============================  check snake head with Rules: ===============================
  129.  
  130.     ' 1. Snakepit boundary check, snake hits wall, dies.
  131.     IF head.X < 0 OR head.X > sqrsX - 1 OR head.Y < 0 OR head.Y > sqrsY - 1 THEN
  132.         _TITLE _TRIM$(STR$(sLen)) + " Wall Crash": screenUpdate: EXIT DO
  133.     END IF
  134.  
  135.     ' 2. Snake eats body part, dies. This should kill snake if turn its head back on itself.
  136.     FOR i = 1 TO sLen '                                              did head just crash into body?
  137.         IF head.X = snake(i).X AND head.Y = snake(i).Y THEN
  138.             _TITLE _TRIM$(STR$(sLen)) + " Body Crash": screenUpdate: EXIT DO '                 yes!
  139.         END IF
  140.     NEXT '                                                                                       no
  141.  
  142.     ' 3. Eats Fruit and grows or just move every segment up 1 space.
  143.     IF (fruit.X = head.X AND fruit.Y = head.Y) THEN '                              snake eats fruit
  144.         sLen = sLen + 1
  145.         snake(sLen).X = head.X: snake(sLen).Y = head.Y ' assimilate fruit into head for new segment
  146.         DO 'check new apple
  147.             fruit.X = INT(RND * sqrsX): fruit.Y = INT(RND * sqrsY): good = -1
  148.             FOR i = 1 TO sLen
  149.                 IF fruit.X = snake(i).X AND fruit.Y = snake(i).Y THEN good = 0: EXIT FOR
  150.             NEXT
  151.         LOOP UNTIL good
  152.     ELSE
  153.         FOR i = 1 TO sLen '                            move the snake data down 1 dropping off last
  154.             snake(i).X = snake(i + 1).X: snake(i).Y = snake(i + 1).Y
  155.         NEXT
  156.         snake(sLen).X = head.X: snake(sLen).Y = head.Y '               and adding new head position
  157.     END IF
  158.  
  159.     screenUpdate '                                                     on with the show this is it!
  160.     IF autoPilot THEN _LIMIT aSpeed ELSE _LIMIT hSpeed ' independent speed control for human and AI
  161. _DELAY 3 '                                                                   win or loose, go again
  162. GOTO restart:
  163.  
  164. SUB screenUpdate ' draw snake and fruit, overlap code debugger
  165.     DIM c~&, i AS INTEGER, overlap(sqrsX, sqrsY) AS INTEGER
  166.     FOR i = 1 TO sLen
  167.         IF i = sLen THEN c~& = &HFF000000 ELSE c~& = pal(sLen - i)
  168.  
  169.         '                overlap helps debug duplicate square drawing which indicates a flawed code
  170.         overlap(snake(i).X, snake(i).Y) = overlap(snake(i).X, snake(i).Y) + 1
  171.  
  172.         LINE (snake(i).X * sq, snake(i).Y * sq)-STEP(sq - 2, sq - 2), c~&, BF
  173.         IF overlap(snake(i).X, snake(i).Y) > 1 THEN ' show visually where code flaws effect display
  174.             LINE (snake(i).X * sq + .25 * sq, snake(i).Y * sq + .25 * sq)_
  175.             -STEP(.5 * sq - 2, .5 * sq - 2), &HFFFFFFFF, BF
  176.         END IF
  177.     NEXT
  178.     LINE (fruit.X * sq, fruit.Y * sq)-STEP(sq - 2, sq - 2), _RGB32(255, 100, 255), BF
  179.     _DISPLAY
  180.  
  181. SUB snakeBrain '>>>>>>>>>>   B+  SNAKE BRAIN  needs sqrsX to be even number  <<<<<<<<<<<<<<<
  182.  
  183.     'IF sqrsX MOD 2 = 1 THEN change.X = 0: change.Y = 0: EXIT SUB 'throw error for code check to
  184.     ''                                                      discover and switch to human control
  185.  
  186.     'IF head.X = 0 AND head.Y = sqrsY - 1 THEN
  187.     '    change.X = 0: change.Y = -1
  188.     'ELSEIF head.X MOD 2 = 0 AND head.Y <> 0 AND head.Y <> sqrsY - 1 THEN
  189.     '    change.X = 0: change.Y = -1
  190.     'ELSEIF head.X MOD 2 = 0 AND head.Y = 0 AND head.Y <> sqrsY - 1 THEN
  191.     '    change.X = 1: change.Y = 0
  192.     'ELSEIF head.X MOD 2 = 1 AND head.X <> sqrsX - 1 AND head.Y = sqrsY - 2 THEN
  193.     '    change.X = 1: change.Y = 0
  194.     'ELSEIF head.X MOD 2 = 1 AND head.X <> sqrsX - 1 AND head.Y < sqrsY - 1 THEN
  195.     '    change.X = 0: change.Y = 1
  196.     'ELSEIF head.X = sqrsX - 1 AND head.Y = sqrsY - 1 THEN
  197.     '    change.X = -1: change.Y = 0
  198.     'ELSEIF head.Y = sqrsY - 1 AND head.X <> 0 THEN
  199.     '    change.X = -1: change.Y = 0
  200.     'ELSEIF head.X MOD 2 = 1 AND head.Y = 0 AND head.Y <> sqrsY - 1 THEN
  201.     '    change.X = 0: change.Y = 1
  202.     'ELSEIF head.X = sqrsX - 1 AND head.Y < sqrsY - 1 THEN
  203.     '    change.X = 0: change.Y = 1
  204.     'END IF
  205.     DIM nx, ny, dx, dy 'Ashish AI
  206.     STATIC decided
  207.     dx = fruit.X - head.X
  208.     dy = fruit.Y - head.Y
  209.     nx = snakeBodyExists(1)
  210.     ny = snakeBodyExists(2)
  211.     IF sLen > 1 THEN 'collison at corners of square
  212.         IF head.X = 0 AND head.Y = 0 THEN
  213.             state$ = "corners"
  214.             IF change.X = -1 THEN change.X = 0: change.Y = 1: decided = 0: EXIT SUB
  215.             IF change.Y = -1 THEN change.Y = 0: change.X = 1: decided = 0: EXIT SUB
  216.         ELSEIF head.X = 0 AND head.Y = sqrsY - 1 THEN
  217.             state$ = "corners"
  218.             IF change.X = -1 THEN change.X = 0: change.Y = -1: decided = 0: EXIT SUB
  219.             IF change.Y = 1 THEN change.Y = 0: change.X = 1: decided = 0: decided = 0: EXIT SUB
  220.         ELSEIF head.X = sqrsX - 1 AND head.Y = 0 THEN
  221.             state$ = "corners"
  222.             IF change.X = 1 THEN change.X = 0: change.Y = 1: decided = 0: EXIT SUB
  223.             IF change.Y = -1 THEN change.Y = 0: change.X = -1: decided = 0: EXIT SUB
  224.         ELSEIF head.X = sqrsX - 1 AND head.Y = sqrsY - 1 THEN
  225.             state$ = "corners"
  226.             IF change.X = 1 THEN change.X = 0: change.Y = -1: decided = 0: EXIT SUB
  227.             IF change.Y = 1 THEN change.Y = 0: change.X = -1: decided = 0: EXIT SUB
  228.         END IF
  229.         IF decided = 0 THEN 'collision with walls
  230.             IF head.X = sqrsX - 1 OR head.X = 0 THEN
  231.                 state$ = "walls"
  232.                 IF ny = 0 THEN
  233.                                         IF dy>0 THEN ny = -1 ELSE ny = 1
  234.                                 END IF
  235.                 change.Y = ny * -1: change.X = 0
  236.                 decided = 1
  237.                 EXIT SUB
  238.             ELSEIF head.Y = sqrsY - 1 OR head.Y = 0 THEN
  239.                 state$ = "walls"
  240.                 IF nx = 0 THEN
  241.                                         IF dx>0 THEN nx = -1 ELSE nx = 1
  242.                                 END IF
  243.                 change.X = nx * -1: change.Y = 0
  244.                 decided = 1
  245.                 EXIT SUB
  246.             END IF
  247.         END IF
  248.     END IF
  249.     IF dx = 0 THEN 'when fruit and head in same direction and motion in same axis
  250.         IF change.Y = 0 THEN
  251.             state$ = "linear"
  252.             IF dy > 0 AND ny <> 1 THEN
  253.                 change.Y = 1: change.X = 0: decided = 0: EXIT SUB
  254.             ELSEIF dy < 0 AND ny <> -1 THEN
  255.                 change.Y = -1: change.X = 0: decided = 0: EXIT SUB
  256.             END IF
  257.         END IF
  258.     END IF
  259.     IF dy = 0 THEN
  260.         IF change.X = 0 THEN
  261.             state$ = "linear"
  262.             IF dx > 0 AND nx <> 1 THEN
  263.                 change.X = 1: change.Y = 0: decided = 0: EXIT SUB
  264.             ELSEIF dx < 0 AND nx <> -1 THEN
  265.                 change.X = -1: change.Y = 0: decided = 0: EXIT SUB
  266.             END IF
  267.         END IF
  268.     END IF
  269.  
  270.     state$ = "common"
  271.     'common decision
  272.     IF ABS(dx) < ABS(dy) THEN
  273.         state$ = "common ny=" + STR$(ny)
  274.         IF ny = 0 THEN
  275.             change.X = 0
  276.             IF dy > 0 THEN change.Y = 1 ELSE change.Y = -1
  277.             state$ = "common cy=" + STR$(change.Y)
  278.             EXIT SUB
  279.         END IF
  280.         IF dy > 0 AND ny <> 1 THEN change.Y = 1: change.X = 0
  281.         IF dy < 0 AND ny <> -1 THEN change.Y = -1: change.X = 0
  282.         decided = 0
  283.     ELSE
  284.  
  285.         state$ = "common nx=" + STR$(nx)
  286.         IF nx = 0 THEN
  287.             change.Y = 0
  288.             IF dx > 0 THEN change.X = 1 ELSE change.X = -1
  289.             state$ = "common cx=" + STR$(change.X)
  290.             EXIT SUB
  291.         END IF
  292.         IF dx > 0 AND nx <> 1 THEN change.X = 1: change.Y = 0
  293.         IF dx < 0 AND nx <> -1 THEN change.X = -1: change.Y = 0
  294.         decided = 0
  295.     END IF
  296.  
  297.     state$ = "rand_common"
  298.     IF ABS(dx) = ABS(dy) THEN 'random choice will be made then, rest code is same as above
  299.         IF RND > 0.5 THEN
  300.             state$ = "rand_common ny=" + STR$(ny)
  301.             IF ny = 0 THEN
  302.                 change.X = 0
  303.                 IF dy > 0 THEN change.Y = 1 ELSE change.Y = -1
  304.                 state$ = "rand_common cy=" + STR$(change.Y)
  305.                 EXIT SUB
  306.             END IF
  307.             IF dy > 0 AND ny <> 1 THEN change.Y = 1: change.X = 0
  308.             IF dy < 0 AND ny <> -1 THEN change.Y = -1: change.X = 0
  309.             decided = 0
  310.         ELSE
  311.             state$ = "rand_common nx=" + STR$(nx)
  312.             IF nx = 0 THEN
  313.                 change.Y = 0
  314.                 IF dx > 0 THEN change.X = 1 ELSE change.X = -1
  315.                 state$ = "rand_common cx=" + STR$(change.X)
  316.                 EXIT SUB
  317.             END IF
  318.             IF dx > 0 AND nx <> 1 THEN change.X = 1: change.Y = 0
  319.             IF dx < 0 AND nx <> -1 THEN change.X = -1: change.Y = 0
  320.             decided = 0
  321.         END IF
  322.     END IF
  323.     'END IF
  324.  
  325. FUNCTION snakeBodyExists (which%)
  326.     IF sLen = 1 THEN EXIT FUNCTION
  327.     DIM n
  328.     FOR n = 1 TO sLen - 1
  329.         IF which% = 1 THEN 'x-direction
  330.             IF snake(n).X - head.X > 0 AND snake(n).Y = head.Y THEN snakeBodyExists = 1: EXIT FUNCTION
  331.             IF snake(n).X - head.X < 0 AND snake(n).Y = head.Y THEN snakeBodyExists = -1: EXIT FUNCTION
  332.         ELSEIF which% = 2 THEN 'y-direction
  333.             IF snake(n).Y - head.Y > 0 AND snake(n).X = head.X THEN snakeBodyExists = 1: EXIT FUNCTION
  334.             IF snake(n).Y - head.Y < 0 AND snake(n).X = head.X THEN snakeBodyExists = -1: EXIT FUNCTION
  335.         END IF
  336.     NEXT
  337. SUB help
  338.     _PRINTSTRING (610, 20), "Keys:"
  339.     _PRINTSTRING (610, 40), "p toggles pause on/off"
  340.     _PRINTSTRING (610, 60), "a toggles autoPilot"
  341.     _PRINTSTRING (610, 100), "arrows control snake"
  342.     _PRINTSTRING (610, 80), "q or esc quits"
  343.     _PRINTSTRING (610, 120), "s increases speed"
  344.     _PRINTSTRING (610, 140), "- decreases speed"
  345.     _PRINTSTRING (610, 200), "A BEEP means AI error,"
  346.     _PRINTSTRING (610, 216), "human put in control."
  347.  
  348.  


 
Screenshot_1.png


EDIT : The code is updated, just fixed a minor bug.
« Last Edit: March 19, 2020, 12:53:07 pm by Ashish »
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Smart Snake
« Reply #9 on: March 19, 2020, 01:00:38 pm »
@Ashish this is great, you got the idea of only changing change.X and change.Y in snake brain SUB and yes allowed to make supplemental functions and subs to help make decisions on change. Everything is good as long as you don't mess with any other of the snake game variables of main program.

I see your AI getting stuck in loop going around and around 1 cell above fruit location, I switched to manual grabbed the fruit and then switched back to autoPilot and your code picked right up again, great start!

I am thinking we might need a status report on who / what is current driver, human or AI

Oh! if you keep your SnakeBrain code separate and list the supplemental procedures it uses, we can store other peoples versions of snake brain and maybe evolve better and better AI. ie SnakeBrainByAshish, SnakeBrainByBplus,...
« Last Edit: March 19, 2020, 01:07:53 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Smart Snake
« Reply #10 on: March 19, 2020, 06:35:16 pm »
NOW we have a "SMART" Snake.  Is this a Serpentine from one of the five tribes?  Great job!  This is addicting to watch but crashes all the time, especially when speed increases.
Moving the window also crashes the program.

All these crashes??? Are you using code from Best Answer? Are you toggling key "a" so human has to drive snake?

How can moving window possibly crash snake??? unless you are driving snake and paying attention to dragging window instead of driving. There is "p" for pause that can stop action so you can move the already centered window to where ever you like. Also the "-" key will slow down AI speed or human speed depending what mode you are in.

Wait... are you using this on DOS ;-))
« Last Edit: March 19, 2020, 06:38:50 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Smart Snake
« Reply #11 on: March 19, 2020, 09:56:41 pm »
Hi [banned user],

Thanks for feedback, I don't have Linux let alone Debian version so I have no idea the troubles you guys have.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Smart Snake
« Reply #12 on: March 19, 2020, 10:46:32 pm »
Here is another snake who always gets it's fruit! Not the least bit faster than snakeBrainBplus1 but fancier!
Just leave in autoPilot and watch the show :)

Code: QB64: [Select]
  1. _TITLE "Snake AI-1_6 B+brain#2" 'b+ 2020-03-19
  2. '2020-03-14 Snake AI-1 first post
  3. '2020-03-16  Snake AI-1_1 there must be overlap of the snake somewhere! Aha!
  4. '2020-03-17 Snake AI-1_2 fix the duplicate segment problem
  5. ' Now a new mystery, an ocassional flashing duplicate box
  6. '2020-03-17 Install standard snake rules for testing brain evolving
  7. ' First setup XY type and rename and convert variables using XY type.
  8. ' 2nd Make snake brain and whole game only dependent sqrsX, sqrsY and sq for screen size
  9. ' Got it!!! the code ends with hangup head next to fruit with 99 (1 cell less that whole board)
  10. ' cells of snake length, no new place can be found for fruit, perfect finish and no duplicate
  11. ' cells! PLUS now can turn on a dime go up one colume and down the next in 2 key press.
  12. ' Now add autoPilot on -1 / off 0 toggle control, OK snake rules tested when human pilots snake.
  13. ' Help screen & independent speeds for human or AI.
  14. '2020-03-18  "Snake AI-1_4 fix tester" The AI tester needs to save Head(x, y) in case the AI
  15. ' does not change the head(x, y) or tries to move it diagonally.
  16.  
  17. '2020-03-18 Snake AI-1_5 SHARE change AS XY
  18. ' DIM SHARE change AS XY or change.x, change.y replaces variables called dx, dy.
  19. ' I decided to switch over to human control if AI fails to return a proper change.
  20. ' AI must leave change.x, change.y ready for human to take over control which means my changing
  21. ' the code for toggling the autopilot and adding change.x, change.y updates in my snakeBrain SUB.
  22. ' Rewrite SnakeBrain using only change.X and change.Y now. A BEEP will indicate an AI error and
  23. ' signal control returned to human. This noted in Key Help part of screen.
  24.  
  25. '2020-03-19 Snake AI-1_6 B+brain#2 begin a new snakeBrain sub routine
  26. ' Add a driver report in title bar along with sLen.
  27. ' Oh hey what a fancy snake dance, not the least bit faster than snakeBrainBplus1.
  28.  
  29.  
  30. '  Snakepit Dimensions: square size = sq, sqrsX = # of squares along x-axis and sqrsY squares down.
  31. CONST sq = 20, sqrsX = 17, sqrsY = 16, xmax = sq * sqrsX, ymax = sq * sqrsY
  32. SCREEN _NEWIMAGE(800, 600, 32)
  33. _DELAY .25
  34.  
  35. ' Usually used to give a point on 2D board a single name that has an X dimension and a Y dimension.
  36. TYPE XY
  37.     X AS INTEGER
  38.     Y AS INTEGER
  39.  
  40. '   SHARED variables for any version of SnakeBrain SUB to act as autoPilot for snake snake.
  41. DIM SHARED change AS XY '                            directs the head direction through AI or Human
  42. DIM SHARED head AS XY '                           leads the way of the snake(body) through snakepit
  43. DIM SHARED sLen AS INTEGER '                                                        length of snake
  44. DIM SHARED snake(1 TO sqrsX * sqrsY) AS XY '                   whole snake, head is at index = sLen
  45. DIM SHARED fruit AS XY '     as snake eats fruit it grows, object is to grow snake to fill snakepit
  46.  
  47. DIM SHARED brain2Directions(0 TO sqrsX - 1, 0 TO sqrsY - 1) AS STRING '     for snakeBrainBplus2 AI
  48.  
  49. '   SHARED for screenUpdate
  50. DIM SHARED pal(sqrsX * sqrsY) AS _UNSIGNED LONG '                                  for snake colors
  51.  
  52. 'other data needed for program
  53. DIM autoPilot AS INTEGER, hSpeed, aSpeed, saveChange AS XY, title$
  54.  
  55. help '                                                                                     Key Menu
  56. hSpeed = 3: aSpeed = 20 '                     autopilot speed is independent of human control speed
  57.  
  58.  
  59. loadBrain2Directions '                    load array with directions for each cell for AI to follow
  60.  
  61. restart: '                                                                             reinitialize
  62. r = .3 + RND * .7: g = r * .5 + RND * .3 - .15: b = .5 * r + RND * .3 - .15 '    rnd pal color vars
  63. FOR i = 1 TO sqrsX * sqrsY '                               enough colors for snake to fill snakepit
  64.     pal(i) = _RGB32(84 + 64 * SIN(r + i / 2), 84 + 64 * SIN(g + i / 2), 104 * SIN(b + i / 2))
  65. head.X = sqrsX / 2 - 3: head.Y = sqrsY / 2 - 3 '                                         head start
  66. fruit.X = sqrsX / 2 + 2: fruit.Y = sqrsY / 2 + 2 '                                      first fruit
  67. sLen = 1 '                                                           for starters snake is all head
  68. snake(sLen).X = head.X: snake(sLen).Y = head.Y '                         head is always at sLen end
  69. autoPilot = 1 '                                                              start snake body count
  70. change.X = 0: change.Y = 1 '                      head snake down board, Y direction of first fruit
  71.     IF autoPilot THEN title$ = "AI." ELSE title$ = "human."
  72.     _TITLE STR$(sLen) + " Current driver is " + title$
  73.     LINE (0, 0)-(xmax, ymax), &HFF884422, BF '                                       clear snakepit
  74.     IF sLen = sqrsX * sqrsY - 1 THEN screenUpdate: EXIT DO '             game is won! start another
  75.     KEY$ = INKEY$
  76.     IF KEY$ = "q" OR KEY$ = CHR$(27) THEN '                                            here is quit
  77.         END '
  78.     ELSEIF KEY$ = "a" THEN '                                                       toggle autoPilot
  79.         autoPilot = 1 - autoPilot '   it is now up to AI to keep change updated for human take over
  80.     ELSEIF KEY$ = "p" THEN '                               pause toggle p starts pause p ends pause
  81.         _KEYCLEAR: WHILE INKEY$ <> "p": _LIMIT 60: WEND
  82.     ELSEIF KEY$ = "s" THEN
  83.         IF autoPilot AND aSpeed + 5 < 400 THEN aSpeed = aSpeed + 5 ' max autopilot speed is 400 !!!
  84.         IF autoPilot = 0 AND hSpeed + .5 < 10 THEN hSpeed = hSpeed + .5 '     max human speed is 10
  85.     ELSEIF KEY$ = "-" THEN
  86.         IF autoPilot AND aSpeed - 5 > 0 THEN aSpeed = aSpeed - 5
  87.         IF autoPilot = 0 AND hSpeed - .5 > 1 THEN hSpeed = hSpeed - .5
  88.     END IF '                                                                                      '
  89.  
  90.     IF autoPilot THEN '                                                 who is piloting the snake?
  91.  
  92.         saveChange.X = change.X: saveChange.Y = change.Y '   if AI screws up then human takes over
  93.  
  94.         ' PLUG-IN YOUR Snake Brain AI here
  95.         '=========================================================================== AI Auto Pilot
  96.         snakeBrainBplus2 ' note: snakeBrainBplus1 won't work for this custom sqrsX, sqrsY version.
  97.         '=========================================================================================
  98.  
  99.         'check changes
  100.         IF ABS(change.X) = 0 THEN '                                      must have diffence in y's
  101.             IF ABS(change.Y) <> 1 THEN autoPilot = 0 '                       error switch to human
  102.         ELSEIF ABS(change.Y) = 0 THEN
  103.             IF ABS(change.X) <> 1 THEN autoPilot = 0 '                       error switch to human
  104.         ELSE '                           must have a 0 in either change.x or change.y but not both
  105.             autoPilot = 0 '                                                  error switch to human
  106.         END IF
  107.         IF autoPilot = 0 THEN '              switching control over to human restore change values
  108.             change.X = saveChange.X: change.Y = saveChange.Y: BEEP '                   alert human
  109.         END IF
  110.  
  111.     ELSE '  =======================================================================  human control
  112.         IF KEY$ = CHR$(0) + CHR$(72) THEN '                                               up arrow
  113.             change.X = 0: change.Y = -1
  114.         ELSEIF KEY$ = CHR$(0) + CHR$(80) THEN '                                         down arrow
  115.             change.X = 0: change.Y = 1
  116.         ELSEIF KEY$ = CHR$(0) + CHR$(77) THEN '                                        right arrow
  117.             change.X = 1: change.Y = 0
  118.         ELSEIF KEY$ = CHR$(0) + CHR$(75) THEN '                                         left arrow
  119.             change.X = -1: change.Y = 0
  120.         END IF
  121.  
  122.     END IF
  123.     head.X = head.X + change.X: head.Y = head.Y + change.Y '            OK human or AI have spoken
  124.  
  125.     '   ============================  check snake head with Rules: ===============================
  126.  
  127.     ' 1. Snakepit boundary check, snake hits wall, dies.
  128.     IF head.X < 0 OR head.X > sqrsX - 1 OR head.Y < 0 OR head.Y > sqrsY - 1 THEN
  129.         _TITLE _TRIM$(STR$(sLen)) + " Wall Crash": screenUpdate: EXIT DO
  130.     END IF
  131.  
  132.     ' 2. Snake eats body part, dies. This should kill snake if turn its head back on itself.
  133.     FOR i = 1 TO sLen '                                              did head just crash into body?
  134.         IF head.X = snake(i).X AND head.Y = snake(i).Y THEN
  135.             _TITLE _TRIM$(STR$(sLen)) + " Body Crash": screenUpdate: EXIT DO '                yes!
  136.         END IF
  137.     NEXT '                                                                                      no
  138.  
  139.     ' 3. Eats Fruit and grows or just move every segment up 1 space.
  140.     IF (fruit.X = head.X AND fruit.Y = head.Y) THEN '                             snake eats fruit
  141.         sLen = sLen + 1
  142.         snake(sLen).X = head.X: snake(sLen).Y = head.Y 'assimilate fruit into head for new segment
  143.         DO 'check new apple
  144.             fruit.X = INT(RND * sqrsX): fruit.Y = INT(RND * sqrsY): good = -1
  145.             FOR i = 1 TO sLen
  146.                 IF fruit.X = snake(i).X AND fruit.Y = snake(i).Y THEN good = 0: EXIT FOR
  147.             NEXT
  148.         LOOP UNTIL good
  149.     ELSE
  150.         FOR i = 1 TO sLen '                           move the snake data down 1 dropping off last
  151.             snake(i).X = snake(i + 1).X: snake(i).Y = snake(i + 1).Y
  152.         NEXT
  153.         snake(sLen).X = head.X: snake(sLen).Y = head.Y '              and adding new head position
  154.     END IF
  155.  
  156.     screenUpdate '                                                    on with the show this is it!
  157.     IF autoPilot THEN _LIMIT aSpeed ELSE _LIMIT hSpeed ' ndependent speed control for human and AI
  158. _DELAY 3 '                                                                  win or loose, go again
  159. GOTO restart:
  160.  
  161. SUB screenUpdate ' draw snake and fruit, overlap code debugger
  162.     DIM c~&, i AS INTEGER, overlap(sqrsX, sqrsY) AS INTEGER
  163.     FOR i = 1 TO sLen
  164.         IF i = sLen THEN c~& = &HFF000000 ELSE c~& = pal(sLen - i)
  165.  
  166.         '               overlap helps debug duplicate square drawing which indicates a flawed code
  167.         overlap(snake(i).X, snake(i).Y) = overlap(snake(i).X, snake(i).Y) + 1
  168.  
  169.         LINE (snake(i).X * sq, snake(i).Y * sq)-STEP(sq - 2, sq - 2), c~&, BF
  170.         IF overlap(snake(i).X, snake(i).Y) > 1 THEN 'show visually where code flaws effect display
  171.             LINE (snake(i).X * sq + .25 * sq, snake(i).Y * sq + .25 * sq)_
  172.             -STEP(.5 * sq - 2, .5 * sq - 2), &HFFFFFFFF, BF
  173.         END IF
  174.     NEXT
  175.     LINE (fruit.X * sq, fruit.Y * sq)-STEP(sq - 2, sq - 2), _RGB32(255, 100, 255), BF
  176.     _DISPLAY
  177.  
  178. SUB snakeBrainBplus1 '>>>>>>>>>>   B+  SNAKE BRAIN  needs sqrsX to be even number  <<<<<<<<<<<<<<<
  179.  
  180.     'todo fix this so that when takeover control won't crash into self
  181.  
  182.     IF sqrsX MOD 2 = 1 THEN change.X = 0: change.Y = 0: EXIT SUB 'throw error for code check to
  183.     '                                                      discover and switch to human control
  184.  
  185.     IF head.X = 0 AND head.Y = sqrsY - 1 THEN
  186.         change.X = 0: change.Y = -1
  187.     ELSEIF head.X MOD 2 = 0 AND head.Y <> 0 AND head.Y <> sqrsY - 1 THEN
  188.         change.X = 0: change.Y = -1
  189.     ELSEIF head.X MOD 2 = 0 AND head.Y = 0 AND head.Y <> sqrsY - 1 THEN
  190.         change.X = 1: change.Y = 0
  191.     ELSEIF head.X MOD 2 = 1 AND head.X <> sqrsX - 1 AND head.Y = sqrsY - 2 THEN
  192.         change.X = 1: change.Y = 0
  193.     ELSEIF head.X MOD 2 = 1 AND head.X <> sqrsX - 1 AND head.Y < sqrsY - 1 THEN
  194.         change.X = 0: change.Y = 1
  195.     ELSEIF head.X = sqrsX - 1 AND head.Y = sqrsY - 1 THEN
  196.         change.X = -1: change.Y = 0
  197.     ELSEIF head.Y = sqrsY - 1 AND head.X <> 0 THEN
  198.         change.X = -1: change.Y = 0
  199.     ELSEIF head.X MOD 2 = 1 AND head.Y = 0 AND head.Y <> sqrsY - 1 THEN
  200.         change.X = 0: change.Y = 1
  201.     ELSEIF head.X = sqrsX - 1 AND head.Y < sqrsY - 1 THEN
  202.         change.X = 0: change.Y = 1
  203.     END IF
  204.  
  205. SUB snakeBrainBplus2 ' needs custom sqrsX = 17, sqrsY = 16 and SUB loadBrain2Directions
  206.     DIM direction$
  207.     direction$ = brain2Directions(head.X, head.Y)
  208.     SELECT CASE direction$
  209.         CASE "U": change.X = 0: change.Y = -1
  210.         CASE "D": change.X = 0: change.Y = 1
  211.         CASE "L": change.X = -1: change.Y = 0
  212.         CASE "R": change.X = 1: change.Y = 0
  213.     END SELECT
  214.  
  215. SUB loadBrain2Directions ' for custom snakeBrainBplus2
  216.     DIM x, y, s$
  217.     FOR y = 0 TO sqrsY - 1
  218.         READ s$
  219.         FOR x = 0 TO sqrsX - 1
  220.             brain2Directions(x, y) = MID$(s$, x + 1, 1)
  221.         NEXT
  222.     NEXT
  223.     DATA RRRRRRRRRRRRRRRRD
  224.     DATA UDLLLLLLLLLLLLLLD
  225.     DATA UDRRRRRRRRRRRRDUD
  226.     DATA UDUDLLLLLLLLLLDUD
  227.     DATA UDUDRRRRRRRRDUDUD
  228.     DATA UDUDUDLLLLLLDUDUD
  229.     DATA UDUDUDRRRRDUDUDUD
  230.     DATA UDUDUDUDLLDUDUDUD
  231.     DATA UDUDUDUDRUDUDUDUD
  232.     DATA UDUDUDUDULLUDUDUD
  233.     DATA UDUDUDURRRRUDUDUD
  234.     DATA UDUDUDULLLLLLUDUD
  235.     DATA UDUDURRRRRRRRUDUD
  236.     DATA UDUDULLLLLLLLLLUD
  237.     DATA UDURRRRRRRRRRRRUD
  238.     DATA ULULLLLLLLLLLLLLL
  239.  
  240. SUB help
  241.     _PRINTSTRING (610, 20), "Keys:"
  242.     _PRINTSTRING (610, 40), "p toggles pause on/off"
  243.     _PRINTSTRING (610, 60), "a toggles autoPilot"
  244.     _PRINTSTRING (610, 100), "arrows control snake"
  245.     _PRINTSTRING (610, 80), "q or esc quits"
  246.     _PRINTSTRING (610, 120), "s increases speed"
  247.     _PRINTSTRING (610, 140), "- decreases speed"
  248.     _PRINTSTRING (610, 200), "A BEEP means AI error,"
  249.     _PRINTSTRING (610, 216), "human put in control."
  250.  
  251.  

 
snakeBrainBplus2.PNG

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Smart Snake
« Reply #13 on: March 20, 2020, 04:59:10 am »
@[banned user]
The program do not crash on my machine.

@bplus Its nice. Another Good approach.
 I tried to improve my AI to take better decision by tracking the location of fruit and its body units but the result is worse. Only thing good is that It now never stuck in a loop but it do "body crash". I think I must not post the code. It has now become full of IF...THEN clause. And guess what, now I, myself not able to understand what I wrote (xD).
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Smart Snake
« Reply #14 on: March 20, 2020, 07:39:25 am »
Hi guys
in windows 10 it runs well

in Lubuntu 14 06 on Oracle VirtualBox  it runs just few seconds and then it crashes!
I'm thinking that there is a substantial difference between Windows and Linux version of QB64.

Please can someone  test this code on Mac so we get a whole overview on the 3 platform of QB64 performances.
Programming isn't difficult, only it's  consuming time and coffee