Jump to content
IGNORED

Musings in machine intelligence


Vorticon

Recommended Posts

Matt, I have been using TidBit while working on the gamma iteration of my bugs' evolution, and I found a minor bug:

 

if the following is entered:

CALL CHAR ..
 (91,"0000001818000000", ..
  96,"FFFFFFFFFFFFFFFF", ..
  104,"007E7E7E7E7E7E00", ..
  112,"80433C3C3C7C8204", ..
  120,"7CFEF3BF1FBFFE7C")

 

It gets translated into this:

100 CALL CHAR (91,"0000001818000000", ,"FFFFFFFFFFFFFFFF", ,"007E7E7E7E7E7E00", ,"80433C3C3C7C8204", ,"7CFEF3BF1FBFFE7C")

 

where the character numbers in the subsequent definitions get deleted. This is corrected by placing the commas after the .. continuation.

 

Also a couple of suggestions:

- A clear window button to clear existing code from the input window without having to select and delete as this gets tedious with long programs

- A copy to the clipboard button for the output code for the same reason

 

It's amazing how much clearer the code gets when using structured entry! Really great tool.

  • Like 1
Link to comment
Share on other sites

The long CALL CHAR needs to have the commas at the beginning of the line, like this:

CALL CHAR
(91,"0000001818000000"..
 ,96,"FFFFFFFFFFFFFFFF"..
 ,104,"007E7E7E7E7E7E00"..
 ,112,"80433C3C3C7C8204"..
 ,120,"7CFEF3BF1FBFFE7C")

 

This is because any line starting with a number forces that line to use that line number. This was to allow you to add structured parts to you code and keep line numbers in places too, if you wanted. Every line is trimmed of white space before being examined. I thought the continuation ".." would over-ride the "starts with a number" test, but apparently not.

 

Also a couple of suggestions:

- A clear window button to clear existing code from the input window without having to select and delete as this gets tedious with long programs

- A copy to the clipboard button for the output code for the same reason

 

I'll see what I can do. My website uses a CMS and I have never explored what you can get away with in a post. I'm not sure about the second suggestion though, can Javascript put data on the local clipboard? Seems like that would be a security risk and not allowed.

 

It's amazing how much clearer the code gets when using structured entry! Really great tool.

 

If you look at the original BASIC language as it was designed by John Kemeny and Thomas Kurtz, there are not line numbers, they have looping constructs, and you can use indentation, and it was compiled. Only when BASIC was modified to run as as interpreter did it gain the line numbers and lose the formatting and looping constructs.

 

It does make a *huge* difference as far as program structure and readability. I think BASIC would not have such a bad reputation if somehow it had retained the ability to use structure and the program structure constructs were retained.

 

Thanks for the feedback, I'll see what I can do.

 

Link to comment
Share on other sites

  • 4 weeks later...

So let's fast-forward a few million years... Here's gamma, where now we have a dynamic environment for the bugs, with food cycles and predators. The bugs have 3 genetically transmittable traits, namely speed (1-3), vigilance (1-5 - i.e ability to spot food, other bugs or predators at a distance), and social tendency to flock to other bugs (1-10), and they asexually reproduce at regular cycles if conditions are favorable. The predators on the other hand have fixed attributes of speed and vigilance, and thus allow for a steady environmental pressure on the bugs. Both bugs and predators can die if they run out of energy, which is replenished by eating food or prey. Food for the bugs regenerates at regular cycles (magenta dots). Neither bugs nor predators can cross obstacles (gray squares).

A word about vigilance: both bugs and predators can see with a 100% accuracy anything directly adjoining them. However, the farther out a target or object is, the lower the accuracy because bugs and predators only see along the 8 cardinal direction points. Furthermore, line of sight is implemented, so vision can be further reduced by obstacles or other creatures. The simulation ends when all the bugs die. The simulation revolves around life cycles, where each cycle consists of one pass through each of the bugs and predators. The current cycle is indicated at the bottom left of the simulation area.

Asynchronous multitasking is also implemented, and therefore each creature may be in one of 3 possible phases, thus attempting to simulate simultaneous activity.

There are 19 simulation variables which allow you to control all aspects of the simulation. There are also 3 commands available to you at any time:

 

S: Stop the program

R: Restart a fresh simulation

G: Display a graph of the current genetic composition of the bugs, which will give you an idea of the dominant genes at any stage of the simulation. The relative number of bugs for each genetic trait is shown by a star. Press any key to return to the simulation

 

gamma1

gamma2

gamma3

 

There are really infinite possibilities to play with here, each with an unpredictable outcome. Try the simulation with no predators at all, then add predators to see how this affects the balance and the genetic composition of the bugs. I have not yet been able to find the right combination of factors that yields a stable ecosystem between bugs and predators, and I would be very interested to hear from anybody who does.

 

It is best to run this simulation under Classic 99 in overdrive mode for speed.

 

Below is the formatted source code (which for some mysterious reason has lost all of its indentations...):

 

 

 

 

// GAMMA
// INITIALIZATION
// --------------
RANDOMIZE
DIM ..
 BUG(50,5), ..
 BUGX(50), ..
 BUGY(50), ..
 PRED(10), ..
 PREDX(10), ..
 PREDY(10), ..
 BPHASE(50), ..
 PPHASE(10)

DIM ..
 TARGETX(50), ..
 TARGETY(50), ..
 FLEE_FLAG(50), ..
 PTARGETX(10), ..
 PTARGETY(10), ..
 SPEED(3), ..
 VIG(5), ..
 SOCIAL(10)

DIM ..
 FIELD$(22)

CALL CHAR ..
 (128,"0000001818000000" ..
  ,96,"FFFFFFFFFFFFFFFF" ..
  ,104,"007E7E7E7E7E7E00" ..
  ,112,"80433C3C3C7C8204" ..
  ,120,"7CFEF3BF1FBFFE7C")
 
CALL COLOR(13,14,1,9,13,1,10,15,1,11,5,1,12,9,1)
CALL SCREEN(4)
// SET SYSTEM VARIABLES
NEXT_ID=20 ! TOTAL NUMBER OF BUGS
PRED_NUM=5 ! INITIAL NUMBER OF PREDATORS
FOOD_NUM=70 ! INITIAL NUMBER OF FOOD
OBSTACLE_NUM=10 ! NUMBER OF OBSTACLES
FOOD_REGEN=20 ! NUMBER OF FOOD WIDGETS REGENERATED PER FOOD CYCLE
B_MAX_ENERGY=10 ! MAXIMUM ENERGY LEVEL FOR BUGS
P_MAX_ENERGY=20 ! MAXIMUM ENERGY LEVEL FOR PREDATORS
FOOD_ENERGY=2 ! ENERGY GAIN FROM EATING FOOD FOR BUGS
P_FOOD_ENERGY=6 ! ENERGY GAIN FROM EATING PREY FOR PREDATORS
B_MOVE_ENERGY=1 ! BUGS ENERGY LOSS FROM MOVEMENT
P_MOVE_ENERGY=1 ! PREDATORS ENERGY LOSS FROM MOVEMENT
B_IDLE_ENERGY=0.5 ! BUGS ENERGY LOSS FROM INACTIVITY
P_IDLE_ENERGY=0.75 ! PREDATORS ENERGY LOSS FROM INACTIVITY
HUNT_ENERGY=3 ! ENERGY LOSS FROM HUNTING
REP_ENERGY=3 ! ENERGY LOSS FROM REPRODUCTION
REST_LEVEL=15 ! ENERGY LEVEL AT OR ABOVE WHICH PREDATORS REST
FLEE_MULT=1.5 ! MULTIPLYER FOR FLEE ENERGY LOSS
RCYCLE=0 ! REPRODUCTIVE CYCLE COUNTER
FCYCLE=0 ! FOOD REGENERATION CYCLE COUNTER
REP_CYCLE=5 ! REPRODUCTION OCCURS EVERY REP_CYCLE
FOOD_CYCLE=10 ! FOOD_REGEN FOOD WIDGETS REGENERATED EVERY FOOD_CYCLE
// USER SIMULATION VARIABLES MODIFICATION SCREEN
new_simulation:
CALL CLEAR
DISPLAY AT(1,1)BEEP:"INITIAL SIMULATION VARIABLES"
DISPLAY AT(3,1):"NUMBER OF BUGS:";NEXT_ID
DISPLAY AT(4,1):"NUMBER OF PREDATORS:";PRED_NUM
DISPLAY AT(5,1):"NUMBER OF FOOD WIDGETS:";FOOD_NUM
DISPLAY AT(6,1):"NUMBER OF OBSTACLES:";OBSTACLE_NUM
DISPLAY AT(7,1):"FOOD REGENERATION CYCLE:";FOOD_REGEN
DISPLAY AT(8,1):"BUGS MAX ENERGY:";B_MAX_ENERGY
DISPLAY AT(9,1):"PREDATORS MAX ENERGY:";P_MAX_ENERGY
DISPLAY AT(10,1):"FOOD ENERGY GAIN:";FOOD_ENERGY
DISPLAY AT(11,1):"PREY ENERGY GAIN:";P_FOOD_ENERGY
DISPLAY AT(12,1):"BUGS MOVE COST:";B_MOVE_ENERGY
DISPLAY AT(13,1):"PREDATORS MOVE COST:";P_MOVE_ENERGY
DISPLAY AT(14,1):"BUGS IDLE COST:";B_IDLE_ENERGY
DISPLAY AT(15,1):"PREDATORS IDLE COST:";P_IDLE_ENERGY
DISPLAY AT(16,1):"HUNT ENERGY COST:";HUNT_ENERGY
DISPLAY AT(17,1):"REPRODUCTIVE COST:";REP_ENERGY
DISPLAY AT(18,1):"PREDATORS REST LEVEL:";REST_LEVEL
DISPLAY AT(19,1):"FLEEING COST MULTIPLYER:";FLEE_MULT
DISPLAY AT(20,1):"REPRODUCTIVE CYCLE:";REP_CYCLE
DISPLAY AT(21,1):"FOOD CYCLE:";FOOD_CYCLE
bug_number:
ACCEPT AT(3,17) SIZE(-2) VALIDATE(DIGIT):NEXT_ID
IF NEXT_ID<0 OR NEXT_ID>50 THEN ..
 bug_number
pred_number:
ACCEPT AT(4,22) SIZE(-2) VALIDATE(DIGIT):PRED_NUM
IF PRED_NUM>10 THEN ..
 pred_number
ACCEPT AT(5,25) SIZE(-3) VALIDATE(DIGIT):FOOD_NUM
ACCEPT AT(6,22) SIZE(-3) VALIDATE(DIGIT):OBSTACLE_NUM
ACCEPT AT(7,26) SIZE(-2) VALIDATE(DIGIT):FOOD_REGEN
ACCEPT AT(8,18) SIZE(-2) VALIDATE(DIGIT):B_MAX_ENERGY
ACCEPT AT(9,23) SIZE(-2) VALIDATE(DIGIT)_MAX_ENERGY
ACCEPT AT(10,19) SIZE(-2) VALIDATE(DIGIT):FOOD_ENERGY
ACCEPT AT(11,19) SIZE(-2) VALIDATE(DIGIT)_FOOD_ENERGY
ACCEPT AT(12,17) SIZE(-2) VALIDATE(DIGIT):B_MOVE_ENERGY
ACCEPT AT(13,22) SIZE(-2) VALIDATE(DIGIT)_MOVE_ENERGY
ACCEPT AT(14,17) SIZE(-4) VALIDATE(NUMERIC):B_IDLE_ENERGY
ACCEPT AT(15,22) SIZE(-4) VALIDATE(NUMERIC)_IDLE_ENERGY
ACCEPT AT(16,19) SIZE(-2) VALIDATE(DIGIT):HUNT_ENERGY
ACCEPT AT(17,20) SIZE(-2) VALIDATE(DIGIT):REP_ENERGY
ACCEPT AT(18,23) SIZE(-2) VALIDATE(DIGIT):REST_LEVEL
ACCEPT AT(19,26) SIZE(-4) VALIDATE(NUMERIC):FLEE_MULT
ACCEPT AT(20,21) SIZE(-2) VALIDATE(DIGIT):REP_CYCLE
ACCEPT AT(21,13) SIZE(-2) VALIDATE(DIGIT):FOOD_CYCLE
CALL CLEAR
// SELECT BUGS GENETIC MAKEUP, ENERGY AND REPRODUCTIVE CYCLE
// BUG(ID,0)=SPEED 1-3
// BUG(ID,1)=VIGILANCE 1-5
// BUG(ID,2)=SOCIAL TENDENCY 1-10
// BUG(ID,3)=ENERGY LEVEL 0-B_MAX_ENERGY
// BUG(ID,4)=REPRODUCTIVE CYCLE 0-1
// BUG(ID,5)=ALIVE FLAG (0=DEAD, 1=ALIVE)
FOR ID=0 TO 50 ::
 BPHASE(ID)=1 ::
 FLEE_FLAG(ID)=0 ::
 FOR G=0 TO 5 ::
   BUG(ID,G)=0 ::
 NEXT G ::
NEXT ID
FOR ID=0 TO NEXT_ID-1
 BUG(ID,0)=INT(RND*3)+1 ::
 BUG(ID,1)=INT(RND*5)+1 ::
 BUG(ID,2)=INT(RND*10)+1 ::
 BUG(ID,3)=B_MAX_ENERGY-2 ::
 BUG(ID,5)=1 ::
NEXT ID
// SET ENERGY LEVEL OF PREDATORS
// ENERGY 0-P_MAX_ENERGY
FOR ID=0 TO PRED_NUM-1 ::
 PRED(ID)=P_MAX_ENERGY-5::
 PPHASE(ID)=1 ::
NEXT ID
// DRAW ENVIRONMENT
CALL HCHAR(1,1,96,32) ::
CALL VCHAR(2,1,96,23) ::
CALL VCHAR(2,32,96,23) ::
CALL HCHAR(24,2,96,30) ! DRAW BORDER
FOR I=1 TO OBSTACLE_NUM ::
 CALL PLACE(X,Y) ::
 CALL HCHAR(Y,X,104)::
NEXT I ! PLACE OBSTACLES
FOR I=1 TO FOOD_NUM ::
 CALL PLACE(X,Y) ::
 CALL HCHAR(Y,X,128) ::
NEXT I ! PLACE FOOD WIDGETS
// PLACE BUGS AND PREDATORS ON FIELD
FOR ID=0 TO NEXT_ID-1 ::
 CALL PLACE(X,Y) ::
 BUGX(ID)=X ::
 BUGY(ID)=Y ::
 CALL HCHAR(Y,X,112) ::
NEXT ID
FOR ID=0 TO PRED_NUM-1 ::
 CALL PLACE(X,Y) ::
 PREDX(ID)=X ::
 PREDY(ID)=Y ::
 CALL HCHAR(Y,X,120) ::
NEXT ID
// START OF SIMULATION
RESTART=0
DEAD_FLAG=0 ! INDICATES DEATH OF BUGS EVERY CYCLE
TCYCLE=0 ! TOTAL NUMBER OF ELAPSED CYCLES
new_cycle:
TCYCLE=TCYCLE+1 ::
DISPLAY AT(24,1) SIZE(4):TCYCLE ::
BUG_NUMBER=NEXT_ID-1
IF DEAD_FLAG=1 THEN ..
 GOSUB purge_dead
FOR ID=0 TO BUG_NUMBER
 ON BPHASE(ID) GOSUB ..
   bug_phase_one, ..
bug_phase_two, ..
bug_phase_three
 GOSUB command_check
 IF RESTART=1 THEN ..
   new_simulation
NEXT ID
FOR ID=0 TO PRED_NUM-1
 ON PPHASE(ID) GOSUB ..
   pred_phase_one, ..
pred_phase_two, ..
pred_phase_three, ..
pred_phase_four
 GOSUB command_check
 IF RESTART=1 THEN ..
   new_simulation
NEXT ID
RCYCLE=RCYCLE+1 ::
FCYCLE=FCYCLE+1
IF DEAD_FLAG=0 THEN ..
 check_reproduction
GOSUB purge_dead
check_reproduction:
IF RCYCLE<REP_CYCLE OR NEXT_ID>=51 THEN ..
 check_food
RCYCLE=0
FOR I=0 TO NEXT_ID-1
 IF BUG(I,3)>7 AND FLEE_FLAG(I)=0 THEN ..
BUG(I,4)=1 ::
BPHASE(I)=3
NEXT I
check_food:
IF FCYCLE=FOOD_CYCLE THEN ..
 FCYCLE=0 ::
 GOSUB food_regen

GOTO new_cycle
// PHASE 1: BUGS LOOK AROUND AND PREDATORS SEARCH FOR PREY
bug_phase_one:
 CALL LOOK(BUGX(ID),BUGY(ID),PREDATOR,FOOD,FRIEND,PX,PY,FX,FY,FRX,FRY,BUG(ID,1))
 IF PREDATOR=1 AND BUG(ID,3)>(BUG(ID,0)*FLEE_MULT) THEN ..
   BPHASE(ID)=2 ::
   TARGETX(ID)=PX ::
   TARGETY(ID)=PY ::
   FLEE_FLAG(ID)=1 ::
   RETURN ! PREDATOR DETECTED
 IF FOOD=1 AND BUG(ID,3)<B_MAX_ENERGY THEN ..
   BPHASE(ID)=2 ::
   TARGETX(ID)=FX ::
   TARGETY(ID)=FY ::
   RETURN ! FOOD DETECTED

 IF FRIEND=0 THEN ..
   random_move

 IF BUG(ID,2)>7 THEN ..
select_target

 PROB=INT(RND*10)+1

 IF BUG(ID,2)>4 AND PROB>3 THEN ..
select_target
 IF BUG(ID,2)<4 AND PROB>7 THEN ..
   select_target ..
 ELSE ..
   random_move
 select_target:
 BPHASE(ID)=2 ::
 TARGETX(ID)=FRX ::
 TARGETY(ID)=FRY ::
 BUG(ID,3)=BUG(ID,3)-B_IDLE_ENERGY

 IF BUG(ID,3)<=0 THEN ..
   BUG(ID,5)=0 ::
DEAD_FLAG=1 ::
CALL HCHAR(BUGY(ID),BUGX(ID),32) ::
   RETURN
 random_move:
 FOR I=1 TO BUG(ID,0)
   TX=BUGX(ID) ::
TY=BUGY(ID)
   CALL HCHAR(TY,TX,32) ::
   CALL MOVE(BUGX(ID),BUGY(ID),OBJ)

IF OBJ=120 THEN ..
  BUGX(ID)=TX ::
  BUGY(ID)=TY ::
  DEAD_FLAG=1 ::
  BUG(ID,5)=0 ::
  RETURN
 
IF OBJ=128 THEN ..
  BUG(ID,3)=BUG(ID,3)+FOOD_ENERGY ::
  CALL HCHAR(BUGY(ID),BUGX(ID),112)::
  IF BUG(ID,3)>B_MAX_ENERGY THEN ..
 BUG(ID,3)=B_MAX_ENERGY ::
 RETURN

   IF OBJ=112 THEN ..
  BUGX(ID)=TX ::
  BUGY(ID)=TY
 
   CALL HCHAR(BUGY(ID),BUGX(ID),112)
 
 NEXT I

 BUG(ID,3)=BUG(ID,3)-B_MOVE_ENERGY

 IF BUG(ID,3)<=0 THEN ..
   BUG(ID,5)=0 ::
DEAD_FLAG=1 ::
CALL HCHAR(BUGY(ID),BUGX(ID),32)
 RETURN

pred_phase_one:
 IF PRED(ID)>=REST_LEVEL THEN ..
   PPHASE(ID)=3 ::
RETURN

 CALL SEARCH(PREDX(ID),PREDY(ID),PREY,PRX,PRY)

 IF PREY=1 THEN ..
   target_prey

 FOR I=1 TO 5
   TX=PREDX(ID) ::
TY=PREDY(ID)
   CALL HCHAR(PREDY(ID),PREDX(ID),32) ::
   CALL MOVE(PREDX(ID),PREDY(ID),OBJ)

IF OBJ=120 THEN ..
  PREDX(ID)=TX ::
  PREDY(ID)=TY
 
IF OBJ=112 THEN ..
  GOSUB find_bug ::
  PRED(ID)=PRED(ID)+P_FOOD_ENERGY ::
  IF PRED(ID)>P_MAX_ENERGY THEN ..
 PRED(ID)=P_MAX_ENERGY ::
 CALL HCHAR(PREDY(ID),PREDX(ID),120) ::
 RETURN

CALL HCHAR(PREDY(ID),PREDX(ID),120)

 NEXT I

 PRED(ID)=PRED(ID)-P_MOVE_ENERGY

 IF PRED(ID)<=0 THEN ..
   CALL HCHAR(PREDY(ID),PREDX(ID),32) ::
PPHASE(ID)=4

 RETURN

 target_prey: 
 PTARGETX(ID)=PRX ::
 PTARGETY(ID)=PRY ::
 PPHASE(ID)=2 ::
 PRED(ID)=PRED(ID)-P_IDLE_ENERGY

 IF PRED(ID)<=0 THEN ..
   CALL HCHAR(PREDY(ID),PREDX(ID),32) ::
PPHASE(ID)=4

 RETURN

// PHASE 2: BUGS SEEK FOOD/OTHER BUGS OR FLEE PREDATORS. PREDATORS HUNT DOWN BUGS

bug_phase_two:
 BPHASE(ID)=1

 IF FLEE_FLAG(ID)=1 THEN ..
CALL FLEE(BUGX(ID),BUGY(ID),TARGETX(ID),TARGETY(ID),BUG(ID,0)) ..
 ELSE continue
BUG(ID,3)=BUG(ID,3)-(BUG(ID,0)*FLEE_MULT) ::
FLEE_FLAG(ID)=0 ::
RETURN
 continue:
 FOR I=1 TO BUG(ID,0)
   CALL HCHAR(BUGY(ID),BUGX(ID),32) ::
   TX=BUGX(ID) ::
   TY=BUGY(ID)
   CALL TARGET_MOVE(BUGX(ID),BUGY(ID),TARGETX(ID),TARGETY(ID),OBJ,DX,DY)

IF OBJ=120 THEN ..
  DEAD_FLAG=1 ::
  BUG(ID,5)=0 ::
  CALL HCHAR(BUGY(ID),BUGX(ID),32) ::
  RETURN

IF OBJ=112 THEN ..
  BUGX(ID)=TX ::
  BUGY(ID)=TY
 
   IF OBJ=128 THEN ..
  BUGX(ID)=BUGX(ID)+DX ::
  BUGY(ID)=BUGY(ID)+DY ::
  BUG(ID,3)=BUG(ID,3)+FOOD_ENERGY ::
 
  IF BUG(ID,3)>B_MAX_ENERGY THEN ..
 BUG(ID,3)=B_MAX_ENERGY ::
 GOTO continue1

IF OBJ=32 THEN ..
  BUGX(ID)=BUGX(ID)+DX ::
  BUGY(ID)=BUGY(ID)+DY

 
   CALL HCHAR(BUGY(ID),BUGX(ID),112)

 NEXT I

 continue1:
 CALL HCHAR(BUGY(ID),BUGX(ID),112)
 BUG(ID,3)=BUG(ID,3)-B_MOVE_ENERGY

 IF BUG(ID,3)<=0 THEN ..
BUG(ID,5)=0 ::
DEAD_FLAG=1 ::
CALL HCHAR(BUGY(ID),BUGX(ID),32)

 RETURN

pred_phase_two:
 FOR I=1 TO 5
   TX=PREDX(ID) ::
TY=PREDY(ID)

   CALL HCHAR(PREDY(ID),PREDX(ID),32) ::
   CALL TARGET_MOVE(PREDX(ID),PREDY(ID),PTARGETX(ID),PTARGETY(ID),OBJ,DX,DY)

IF OBJ<>112 THEN ..
  check_obstructions
 
PREDX(ID)=PREDX(ID)+DX ::
PREDY(ID)=PREDY(ID)+DY ::
GOSUB find_bug ::
PRED(ID)=PRED(ID)+P_FOOD_ENERGY ::
GOTO continue3

 check_obstructions:
 IF OBJ<>32 AND OBJ<>128 THEN ..
   continue3

 PTARGETX(ID)=PTARGETX(ID)+DX ::
 PTARGETY(ID)=PTARGETY(ID)+DY ::
 PREDX(ID)=PREDX(ID)+DX ::
 PREDY(ID)=PREDY(ID)+DY

 CALL HCHAR(PREDY(ID),PREDX(ID),120)

 NEXT I

 continue3:
 IF PRED(ID)>P_MAX_ENERGY THEN ..
   PRED(ID)=P_MAX_ENERGY

 PRED(ID)=PRED(ID)-HUNT_ENERGY

 IF PRED(ID)>REST_LEVEL THEN ..
PPHASE(ID)=3

 IF PRED(ID)<=0 THEN ..
   CALL HCHAR(PREDY(ID),PREDX(ID),32) ::
PPHASE(ID)=4 ..
 ELSE ..
   CALL HCHAR(PREDY(ID),PREDX(ID),120) ::
PPHASE(ID)=1

 RETURN
// PHASE 3: BUGS REPRODUCE AND PREDATORS REST
bug_phase_three:
 IF BUG(ID,3)<8 OR NEXT_ID>50 THEN ..
   BUG(ID,4)=0 ::
BPHASE(ID)=1 ::
BUG(ID,3)=BUG(ID,3)-B_IDLE_ENERGY ::
   RETURN

 CALL REPRODUCE(BUGX(ID),BUGY(ID),NX,NY) ::

 IF NX=BUGX(ID) AND NY=BUGY(ID) THEN ..
   BUG(ID,3)=BUG(ID,3)-B_IDLE_ENERGY ::
   RETURN

 BUG(ID,4)=0 ::
 BUG(ID,3)=BUG(ID,3)-REP_ENERGY ::
 CALL HCHAR(NY,NX,112) ::
 BPHASE(ID)=1
 BUGX(NEXT_ID)=NX ::
 BUGY(NEXT_ID)=NY ::
 BUG(NEXT_ID,0)=BUG(ID,0) ::
 BUG(NEXT_ID,1)=BUG(ID,1) ::
 BUG(NEXT_ID,2)=BUG(ID,2)
 BUG(NEXT_ID,3)=8 ::
 BUG(NEXT_ID,4)=0 ::
 BUG(NEXT_ID,5)=1
 BPHASE(NEXT_ID)=1 ::
 NEXT_ID=NEXT_ID+1
 RETURN

pred_phase_three:
 PRED(ID)=PRED(ID)-P_IDLE_ENERGY
 IF PRED(ID)<REST_LEVEL THEN ..
   PPHASE(ID)=1
 RETURN

// PHASE 4: DEAD PREDATOR. NO ACTION
pred_phase_four:
 RETURN
purge_dead:
 ID=0 ::
 DEAD_FLAG=0

 purge_loop:
 IF ID=NEXT_ID-1 AND BUG(ID,5)=0 THEN ..
   NEXT_ID=NEXT_ID-1 ::
IF NEXT_ID=0 THEN ..
  end_simulation ..
ELSE ..
  RETURN

 IF BUG(ID,5)=1 THEN ..
   ID=ID+1 ::
IF ID=NEXT_ID THEN ..
  RETURN ..
ELSE ..
  purge_loop
 
 FOR I=ID+1 TO NEXT_ID-1

FOR J=0 TO 5
  BUG(I-1,J)=BUG(I,J)
NEXT J

BUGX(I-1)=BUGX(I) ::
BUGY(I-1)=BUGY(I) ::
TARGETX(I-1)=TARGETX(I) ::
TARGETY(I-1)=TARGETY(I) ::
FLEE_FLAG(I-1)=FLEE_FLAG(I) ::
BPHASE(I-1)=BPHASE(I)

 NEXT I

 NEXT_ID=NEXT_ID-1 ::

 IF NEXT_ID=0 THEN ..
   end_simulation

 GOTO purge_loop

find_bug:
 FOR Z=0 TO NEXT_ID-1

   IF BUGX(Z)=PREDX(ID) AND BUGY(Z)=PREDY(ID) AND BUG(Z,5)=1 THEN ..
  DEAD_FLAG=1 ::
  BUG(Z,5)=0 ::
  RETURN
 
 NEXT Z

command_check:
 CALL KEY(0,K,S)

 IF K=83 OR K=115 THEN ..
   STOP

 IF K=82 OR K=114 THEN ..
   RESTART=1 ::
RETURN

 IF K<>71 AND K<>103 THEN ..
   RETURN

 FOR I=1 TO 22
   FIELD$(I)=""
 NEXT I

 FOR I=1 TO 3
   SPEED(I)=0
 NEXT I

 FOR I=1 TO 5
   VIG(I)=0
 NEXT I

 FOR I=1 TO 10
   SOCIAL(I)=0
 NEXT I

 FOR Y=2 TO 23
   FOR X=2 TO 31
  CALL GCHAR(Y,X,OBJ)
  IF OBJ=128 OR OBJ=104 THEN ..
 IF X<10 THEN ..
   FIELD$(Y-1)=FIELD$(Y-1)&"0"&STR$(X)&STR$(OBJ) ..
 ELSE ..
   FIELD$(Y-1)=FIELD$(Y-1)&STR$(X)&STR$(OBJ)
NEXT X
FIELD$(Y-1)=FIELD$(Y-1)&"99"
 NEXT Y

 DISPLAY AT(23,2) ERASE ALL:"123	 12345    1234567890"
 DISPLAY AT(24,1):"SPEED  VIGILANCE    SOCIAL"

 FOR I=0 TO NEXT_ID-1
   SPEED(BUG(I,0))=SPEED(BUG(I,0))+1
VIG(BUG(I,1))=VIG(BUG(I,1))+1
SOCIAL(BUG(I,2))=SOCIAL(BUG(I,2))+1
 NEXT I

 FOR I=1 TO 3
   DISPLAY AT(22-INT(SPEED(I)/2),1+I):"*"
 NEXT I

 FOR I=1 TO 5
   DISPLAY AT(22-INT(VIG(I)/2),9+I):"*"
 NEXT I

 FOR I=1 TO 10
   DISPLAY AT(22-INT(SOCIAL(I)/2),18+I):"*"
 NEXT I

 key_loop:
 CALL KEY(0,K,S) ::
 IF S=0 THEN ..
   key_loop
 CALL CLEAR ::
 I=1

 CALL HCHAR(1,1,96,32) ::
 CALL VCHAR(2,1,96,23) ::
 CALL VCHAR(2,32,96,23) ::
 CALL HCHAR(24,2,96,30) ! DRAW BORDER

 FOR Y=2 TO 23
   fetch_next_x:
   X=VAL(SEG$(FIELD$(Y-1),I,2))

IF X=99 THEN ..
  next_line

OBJ=VAL(SEG$(FIELD$(Y-1),I+2,3)) ::
CALL HCHAR(Y,X,OBJ) ::
   I=I+5 ::
GOTO fetch_next_x

 next_line:
 I=1
 NEXT Y

 FOR I=0 TO NEXT_ID-1
   CALL HCHAR(BUGY(I),BUGX(I),112)
 NEXT I

 FOR I=0 TO PRED_NUM-1
   IF PPHASE(I)<4 THEN ..
  CALL HCHAR(PREDY(I),PREDX(I),120)
 NEXT I

 DISPLAY AT(24,1) SIZE(4):TCYCLE

 RETURN

end_simulation:
 DISPLAY AT(10,4) BEEP:"THE COLONY HAS DIED!" ::
 DISPLAY AT(12,4):"RESTART SIMULATION?"
 check_key_loop:
 CALL KEY(0,K,S) ::
 IF S=0 THEN ..
   check_key_loop
 IF K=89 OR K=121 THEN ..
   new_simulation ..
 ELSE ..
   STOP
// DATA FOR LOOK AND SEARCH ROUTINES
look_data:
 DATA -1,-1,-1,1,0,-1,0,1,1,-1,1,1
 DATA -2,-2,-2,2,0,-2,0,2,2,-2,2,2
 DATA -3,-3,-3,3,0,-3,0,3,3,-3,3,3
 DATA -4,-4,-4,4,0,-4,0,4,4,-4,4,4
 DATA -5,-5,-5,5,0,-5,0,5,5,-5,5,5
// FOOD REGENERATION ROUTINE
food_regen:
 FOR I=1 TO FOOD_REGEN ::
   CALL PLACE(X,Y) ::
   CALL HCHAR(Y,X,128) ::
 NEXT I
 RETURN
// RANDOM SCREEN OBJECT PLACEMENT ROUTINE
SUB PLACE(X,Y)
 sub_place_loop:
    X=INT(RND*30)+2 ::
    Y=INT(RND*21)+2
    CALL GCHAR(Y,X,C) ::
    IF C<>32 THEN sub_place_loop

SUBEND
// RANDOM MOVEMENT DIRECTION GENERATION ROUTINE
SUB DIR(CX,CY)
 sub_dir_loop:
    CX=INT(RND*2) ::
    DIR=INT(RND*10)+1 ::
    IF DIR>5 THEN CX=-CX

    CY=INT(RND*2) ::
    DIR=INT(RND*10)+1 ::
    IF DIR>5 THEN CY=-CY

    IF CX=0 AND CY=0 THEN sub_dir_loop

SUBEND
// LOOK AROUND ROUTINE
SUB LOOK(BUGX,BUGY,PREDATOR,FOOD,FRIEND,PX,PY,FX,FY,FRX,FRY,V)
 FOR I=1 TO 6 ::
   BLOCK(I)=0 ::
 NEXT I
 PREDATOR,FOOD,FRIEND=0
 RESTORE look_data
 FOR I=1 TO V
   FOR J=1 TO 6
  READ DX,DY
  IF BLOCK(J)=1 THEN ..
 look_advance
  IF BUGX+DX>0 AND BUGX+DX<33 THEN ..
 X=BUGX+DX
  IF BUGY+DY>0 AND BUGY+DY<25 THEN ..
 Y=BUGY+DY ::
  CALL GCHAR(Y,X,OBJ)
 
  IF OBJ=96 OR OBJ=104 THEN ..
  BLOCK(J)=1 ::
  GOTO look_advance ! SKIP OBSTRUCTIONS
 
  IF OBJ=120 THEN ..
 PREDATOR=1 ::
 PX=X ::
 PY=Y ::
 SUBEXIT ! LOOK FOR PREDATORS
  
  IF OBJ=128 AND FOOD=0 THEN ..
 FOOD=1 ::
 FX=X ::
 FY=Y ::
 GOTO look_advance! LOOK FOR FOOD

  IF OBJ=112 AND FRIEND=0 THEN ..
 FRIEND=1 ::
 BLOCK(J)=1 ::
 FRX=X ::
 FRY=Y ! LOOK FOR OTHER BUGS

look_advance:
NEXT J
 NEXT I

SUBEND
// FLEE ROUTINE
SUB FLEE(BUGX,BUGY,PX,PY,S)
 X=BUGX ::
 Y=BUGY ::
 FOR I=1 TO S
   CALL HCHAR(Y,X,32)
   pick_new_dir:
   CALL DIR(CX,CY)
NX=X+CX ::
NY=Y+CY ::
CALL GCHAR(NY,NX,OBJ)

IF NX<2 OR NX>31 OR NY<2 OR NY>23 OR OBJ=104 THEN ..
  GOTO flee_loop ! AVOID ALL OBSTRUCTIONS

PDIST=INT(SQR((PX-X)^2+(PY-Y)^2)) ::
NDIST=INT(SQR((PX-NX)^2+(PY-NY)^2))

IF NDIST<=PDIST THEN ..
  GOTO pick_new_dir ! AVOID DIRECTIONS TOWARDS PREDATOR

X=NX ::
Y=NY

 flee_loop:
  CALL HCHAR(Y,X,112)

 NEXT I

 BUGX=X ::
 BUGY=Y

SUBEND

// TARGETED MOVEMENT ROUTINE
SUB TARGET_MOVE(ORGX,ORGY,TX,TY,OBJ,DX,DY)
 DX=0 ::
 DY=0

 IF TX-ORGX>0 THEN ..
   DX=1 ::
   GOTO check_y

 IF TX-ORGX<0 THEN ..
   DX=-1

 check_y:
 IF TY-ORGY>0 THEN ..
   DY=1 ::
   GOTO update_pos

 IF TY-ORGY<0 THEN ..
   DY=-1
 update_pos:
 X=ORGX+DX ::
 Y=ORGY+DY ::
 CALL GCHAR(Y,X,OBJ)
 IF OBJ=104 THEN ..
   DX=0 ::
DY=0

SUBEND
// UNTARGETED MOVEMENT ROUTINE
SUB MOVE(ORGX,ORGY,OBJ)
 move_loop:
 CALL DIR(DX,DY) ::
 X=ORGX+DX ::
 Y=ORGY+DY ::
 CALL GCHAR(Y,X,OBJ)

 IF X<2 OR X>31 OR Y<2 OR Y>23 OR OBJ=104 THEN ..
   move_loop

 ORGX=X ::
 ORGY=Y

SUBEND
// PREDATOR SEARCH FOR PREY ROUTINE
SUB SEARCH(PREDX,PREDY,PREY,PRX,PRY)
 FOR I=1 TO 6 ::
   BLOCK(I)=0 ::
 NEXT I 

 PREY=0 ::
 RESTORE look_data

 FOR I=1 TO 5
   FOR J=1 TO 6
  READ DX,DY
  IF BLOCK(J)=1 THEN ..
 search_advance
  IF PREDX+DX>0 AND PREDX+DX<33 THEN ..
 X=PREDX+DX ..
  ELSE ..
 search_advance
  IF PREDY+DY>0 AND PREDY+DY<25 THEN ..
 Y=PREDY+DY ..
  ELSE ..
 search_advance

  CALL GCHAR(Y,X,OBJ)
 
  IF OBJ=96 OR OBJ=104 THEN ..
  BLOCK(J)=1 ::
  GOTO search_advance ! SKIP OBSTRUCTIONS
 
  IF OBJ=112 THEN ..
 PREY=1 ::
 PRX=X ::
 PRY=Y ::
 SUBEXIT ! LOOK FOR PREY

  IF OBJ=120 THEN ..
 BLOCK(J)=1

search_advance:
NEXT J
 NEXT I
SUBEND
// BUG REPRODUCTION ROUTINE
SUB REPRODUCE(X,Y,NX,NY)
 NX=0 ::
 NY=0
 FOR I=X-1 TO X+1
   FOR J=Y-1 TO Y+1
  CALL GCHAR(J,I,OBJ) ::
  IF OBJ=32 OR OBJ=128 THEN ..
 NX=I ::
 NY=J ::
 SUBEXIT
NEXT J
 NEXT I
 IF NX=0 AND NY=0 THEN ..
   NX=X ::
NY=Y
SUBEND


  

  
 
 
  

 

 

 

 

 

 

 

 

And here's the actual XB code after running the source through Matthew180's TidBit utility. I have to say that I very highly recommend TidBit for any non-trivial XB program because formatting the source code immensely enhances readability and reduces errors. Matt, I was wondering if you would consider creating a stand-alone version of TidBit so we are not dependent on having an internet connection all the time.

 

 

100 RANDOMIZE

110 DIM BUG(50,5), BUGX(50), BUGY(50), PRED(10), PREDX(10), PREDY(10), BPHASE(50), PPHASE(10)

120 DIM TARGETX(50), TARGETY(50), FLEE_FLAG(50), PTARGETX(10), PTARGETY(10), SPEED(3), VIG(5), SOCIAL(10)

130 DIM FIELD$(22)

140 CALL CHAR (128,"0000001818000000" ,96,"FFFFFFFFFFFFFFFF" ,104,"007E7E7E7E7E7E00" ,112,"80433C3C3C7C8204" ,120,"7CFEF3BF1FBFFE7C")

150 CALL COLOR(13,14,1,9,13,1,10,15,1,11,5,1,12,9,1)

160 CALL SCREEN(4)

170 NEXT_ID=20 ! TOTAL NUMBER OF BUGS

180 PRED_NUM=5 ! INITIAL NUMBER OF PREDATORS

190 FOOD_NUM=70 ! INITIAL NUMBER OF FOOD

200 OBSTACLE_NUM=10 ! NUMBER OF OBSTACLES

210 FOOD_REGEN=20 ! NUMBER OF FOOD WIDGETS REGENERATED PER FOOD CYCLE

220 B_MAX_ENERGY=10 ! MAXIMUM ENERGY LEVEL FOR BUGS

230 P_MAX_ENERGY=20 ! MAXIMUM ENERGY LEVEL FOR PREDATORS

240 FOOD_ENERGY=2 ! ENERGY GAIN FROM EATING FOOD FOR BUGS

250 P_FOOD_ENERGY=6 ! ENERGY GAIN FROM EATING PREY FOR PREDATORS

260 B_MOVE_ENERGY=1 ! BUGS ENERGY LOSS FROM MOVEMENT

270 P_MOVE_ENERGY=1 ! PREDATORS ENERGY LOSS FROM MOVEMENT

280 B_IDLE_ENERGY=0.5 ! BUGS ENERGY LOSS FROM INACTIVITY

290 P_IDLE_ENERGY=0.75 ! PREDATORS ENERGY LOSS FROM INACTIVITY

300 HUNT_ENERGY=3 ! ENERGY LOSS FROM HUNTING

310 REP_ENERGY=3 ! ENERGY LOSS FROM REPRODUCTION

320 REST_LEVEL=15 ! ENERGY LEVEL AT OR ABOVE WHICH PREDATORS REST

330 FLEE_MULT=1.5 ! MULTIPLYER FOR FLEE ENERGY LOSS

340 RCYCLE=0 ! REPRODUCTIVE CYCLE COUNTER

350 FCYCLE=0 ! FOOD REGENERATION CYCLE COUNTER

360 REP_CYCLE=5 ! REPRODUCTION OCCURS EVERY REP_CYCLE

370 FOOD_CYCLE=10 ! FOOD_REGEN FOOD WIDGETS REGENERATED EVERY FOOD_CYCLE

380 CALL CLEAR

390 DISPLAY AT(1,1)BEEP:"INITIAL SIMULATION VARIABLES"

400 DISPLAY AT(3,1):"NUMBER OF BUGS:";NEXT_ID

410 DISPLAY AT(4,1):"NUMBER OF PREDATORS:";PRED_NUM

420 DISPLAY AT(5,1):"NUMBER OF FOOD WIDGETS:";FOOD_NUM

430 DISPLAY AT(6,1):"NUMBER OF OBSTACLES:";OBSTACLE_NUM

440 DISPLAY AT(7,1):"FOOD REGENERATION CYCLE:";FOOD_REGEN

450 DISPLAY AT(8,1):"BUGS MAX ENERGY:";B_MAX_ENERGY

460 DISPLAY AT(9,1):"PREDATORS MAX ENERGY:";P_MAX_ENERGY

470 DISPLAY AT(10,1):"FOOD ENERGY GAIN:";FOOD_ENERGY

480 DISPLAY AT(11,1):"PREY ENERGY GAIN:";P_FOOD_ENERGY

490 DISPLAY AT(12,1):"BUGS MOVE COST:";B_MOVE_ENERGY

500 DISPLAY AT(13,1):"PREDATORS MOVE COST:";P_MOVE_ENERGY

510 DISPLAY AT(14,1):"BUGS IDLE COST:";B_IDLE_ENERGY

520 DISPLAY AT(15,1):"PREDATORS IDLE COST:";P_IDLE_ENERGY

530 DISPLAY AT(16,1):"HUNT ENERGY COST:";HUNT_ENERGY

540 DISPLAY AT(17,1):"REPRODUCTIVE COST:";REP_ENERGY

550 DISPLAY AT(18,1):"PREDATORS REST LEVEL:";REST_LEVEL

560 DISPLAY AT(19,1):"FLEEING COST MULTIPLYER:";FLEE_MULT

570 DISPLAY AT(20,1):"REPRODUCTIVE CYCLE:";REP_CYCLE

580 DISPLAY AT(21,1):"FOOD CYCLE:";FOOD_CYCLE

590 ACCEPT AT(3,17) SIZE(-2) VALIDATE(DIGIT):NEXT_ID

600 IF NEXT_ID<0 OR NEXT_ID>50 THEN 590

610 ACCEPT AT(4,22) SIZE(-2) VALIDATE(DIGIT):PRED_NUM

620 IF PRED_NUM>10 THEN 610

630 ACCEPT AT(5,25) SIZE(-3) VALIDATE(DIGIT):FOOD_NUM

640 ACCEPT AT(6,22) SIZE(-3) VALIDATE(DIGIT):OBSTACLE_NUM

650 ACCEPT AT(7,26) SIZE(-2) VALIDATE(DIGIT):FOOD_REGEN

660 ACCEPT AT(8,18) SIZE(-2) VALIDATE(DIGIT):B_MAX_ENERGY

670 ACCEPT AT(9,23) SIZE(-2) VALIDATE(DIGIT) :P_MAX_ENERGY

680 ACCEPT AT(10,19) SIZE(-2) VALIDATE(DIGIT):FOOD_ENERGY

690 ACCEPT AT(11,19) SIZE(-2) VALIDATE(DIGIT) :P_FOOD_ENERGY

700 ACCEPT AT(12,17) SIZE(-2) VALIDATE(DIGIT):B_MOVE_ENERGY

710 ACCEPT AT(13,22) SIZE(-2) VALIDATE(DIGIT) :P_MOVE_ENERGY

720 ACCEPT AT(14,17) SIZE(-4) VALIDATE(NUMERIC):B_IDLE_ENERGY

730 ACCEPT AT(15,22) SIZE(-4) VALIDATE(NUMERIC) :P_IDLE_ENERGY

740 ACCEPT AT(16,19) SIZE(-2) VALIDATE(DIGIT):HUNT_ENERGY

750 ACCEPT AT(17,20) SIZE(-2) VALIDATE(DIGIT):REP_ENERGY

760 ACCEPT AT(18,23) SIZE(-2) VALIDATE(DIGIT):REST_LEVEL

770 ACCEPT AT(19,26) SIZE(-4) VALIDATE(NUMERIC):FLEE_MULT

780 ACCEPT AT(20,21) SIZE(-2) VALIDATE(DIGIT):REP_CYCLE

790 ACCEPT AT(21,13) SIZE(-2) VALIDATE(DIGIT):FOOD_CYCLE

800 CALL CLEAR

810 FOR ID=0 TO 50 :: BPHASE(ID)=1 :: FLEE_FLAG(ID)=0 :: FOR G=0 TO 5 :: BUG(ID,G)=0 :: NEXT G :: NEXT ID

820 FOR ID=0 TO NEXT_ID-1

830 BUG(ID,0)=INT(RND*3)+1 :: BUG(ID,1)=INT(RND*5)+1 :: BUG(ID,2)=INT(RND*10)+1 :: BUG(ID,3)=B_MAX_ENERGY-2 :: BUG(ID,5)=1 :: NEXT ID

840 FOR ID=0 TO PRED_NUM-1 :: PRED(ID)=P_MAX_ENERGY-5:: PPHASE(ID)=1 :: NEXT ID

850 CALL HCHAR(1,1,96,32) :: CALL VCHAR(2,1,96,23) :: CALL VCHAR(2,32,96,23) :: CALL HCHAR(24,2,96,30) ! DRAW BORDER

860 FOR I=1 TO OBSTACLE_NUM :: CALL PLACE(X,Y) :: CALL HCHAR(Y,X,104):: NEXT I ! PLACE OBSTACLES

870 FOR I=1 TO FOOD_NUM :: CALL PLACE(X,Y) :: CALL HCHAR(Y,X,128) :: NEXT I ! PLACE FOOD WIDGETS

880 FOR ID=0 TO NEXT_ID-1 :: CALL PLACE(X,Y) :: BUGX(ID)=X :: BUGY(ID)=Y :: CALL HCHAR(Y,X,112) :: NEXT ID

890 FOR ID=0 TO PRED_NUM-1 :: CALL PLACE(X,Y) :: PREDX(ID)=X :: PREDY(ID)=Y :: CALL HCHAR(Y,X,120) :: NEXT ID

900 RESTART=0

910 DEAD_FLAG=0 ! INDICATES DEATH OF BUGS EVERY CYCLE

920 TCYCLE=0 ! TOTAL NUMBER OF ELAPSED CYCLES

930 TCYCLE=TCYCLE+1 :: DISPLAY AT(24,1) SIZE(4):TCYCLE :: BUG_NUMBER=NEXT_ID-1

940 IF DEAD_FLAG=1 THEN GOSUB 1930

950 FOR ID=0 TO BUG_NUMBER

960 ON BPHASE(ID) GOSUB 1150,1520,1820

970 GOSUB 2070

980 IF RESTART=1 THEN 380

990 NEXT ID

1000 FOR ID=0 TO PRED_NUM-1

1010 ON PPHASE(ID) GOSUB 1360,1680,1890,1920

1020 GOSUB 2070

1030 IF RESTART=1 THEN 380

1040 NEXT ID

1050 RCYCLE=RCYCLE+1 :: FCYCLE=FCYCLE+1

1060 IF DEAD_FLAG=0 THEN 1080

1070 GOSUB 1930

1080 IF RCYCLE=51 THEN 1130

1090 RCYCLE=0

1100 FOR I=0 TO NEXT_ID-1

1110 IF BUG(I,3)>7 AND FLEE_FLAG(I)=0 THEN BUG(I,4)=1 :: BPHASE(I)=3

1120 NEXT I

1130 IF FCYCLE=FOOD_CYCLE THEN FCYCLE=0 :: GOSUB 2710

1140 GOTO 930

1150 CALL LOOK(BUGX(ID),BUGY(ID),PREDATOR,FOOD,FRIEND,PX,PY,FX,FY,FRX,FRY,BUG(ID,1))

1160 IF PREDATOR=1 AND BUG(ID,3)>(BUG(ID,0)*FLEE_MULT) THEN BPHASE(ID)=2 :: TARGETX(ID)=PX :: TARGETY(ID)=PY :: FLEE_FLAG(ID)=1 :: RETURN ! PREDATOR DETECTED

1170 IF FOOD=1 AND BUG(ID,3)1180 IF FRIEND=0 THEN 1250

1190 IF BUG(ID,2)>7 THEN 1230

1200 PROB=INT(RND*10)+1

1210 IF BUG(ID,2)>4 AND PROB>3 THEN 1230

1220 IF BUG(ID,2)<4 AND PROB>7 THEN 1230 ELSE 1250

1230 BPHASE(ID)=2 :: TARGETX(ID)=FRX :: TARGETY(ID)=FRY :: BUG(ID,3)=BUG(ID,3)-B_IDLE_ENERGY

1240 IF BUG(ID,3)<=0 THEN BUG(ID,5)=0 :: DEAD_FLAG=1 :: CALL HCHAR(BUGY(ID),BUGX(ID),32) :: RETURN

1250 FOR I=1 TO BUG(ID,0)

1260 TX=BUGX(ID) :: TY=BUGY(ID)

1270 CALL HCHAR(TY,TX,32) :: CALL MOVE(BUGX(ID),BUGY(ID),OBJ)

1280 IF OBJ=120 THEN BUGX(ID)=TX :: BUGY(ID)=TY :: DEAD_FLAG=1 :: BUG(ID,5)=0 :: RETURN

1290 IF OBJ=128 THEN BUG(ID,3)=BUG(ID,3)+FOOD_ENERGY :: CALL HCHAR(BUGY(ID),BUGX(ID),112):: IF BUG(ID,3)>B_MAX_ENERGY THEN BUG(ID,3)=B_MAX_ENERGY :: RETURN

1300 IF OBJ=112 THEN BUGX(ID)=TX :: BUGY(ID)=TY

1310 CALL HCHAR(BUGY(ID),BUGX(ID),112)

1320 NEXT I

1330 BUG(ID,3)=BUG(ID,3)-B_MOVE_ENERGY

1340 IF BUG(ID,3)<=0 THEN BUG(ID,5)=0 :: DEAD_FLAG=1 :: CALL HCHAR(BUGY(ID),BUGX(ID),32)

1350 RETURN

1360 IF PRED(ID)>=REST_LEVEL THEN PPHASE(ID)=3 :: RETURN

1370 CALL SEARCH(PREDX(ID),PREDY(ID),PREY,PRX,PRY)

1380 IF PREY=1 THEN 1490

1390 FOR I=1 TO 5

1400 TX=PREDX(ID) :: TY=PREDY(ID)

1410 CALL HCHAR(PREDY(ID),PREDX(ID),32) :: CALL MOVE(PREDX(ID),PREDY(ID),OBJ)

1420 IF OBJ=120 THEN PREDX(ID)=TX :: PREDY(ID)=TY

1430 IF OBJ=112 THEN GOSUB 2040 :: PRED(ID)=PRED(ID)+P_FOOD_ENERGY :: IF PRED(ID)>P_MAX_ENERGY THEN PRED(ID)=P_MAX_ENERGY :: CALL HCHAR(PREDY(ID),PREDX(ID),120) :: RETURN

1440 CALL HCHAR(PREDY(ID),PREDX(ID),120)

1450 NEXT I

1460 PRED(ID)=PRED(ID)-P_MOVE_ENERGY

1470 IF PRED(ID)<=0 THEN CALL HCHAR(PREDY(ID),PREDX(ID),32) :: PPHASE(ID)=4

1480 RETURN

1490 PTARGETX(ID)=PRX :: PTARGETY(ID)=PRY :: PPHASE(ID)=2 :: PRED(ID)=PRED(ID)-P_IDLE_ENERGY

1500 IF PRED(ID)<=0 THEN CALL HCHAR(PREDY(ID),PREDX(ID),32) :: PPHASE(ID)=4

1510 RETURN

1520 BPHASE(ID)=1

1530 IF FLEE_FLAG(ID)=1 THEN CALL FLEE(BUGX(ID),BUGY(ID),TARGETX(ID),TARGETY(ID),BUG(ID,0)) ELSE 1550

1540 BUG(ID,3)=BUG(ID,3)-(BUG(ID,0)*FLEE_MULT) :: FLEE_FLAG(ID)=0 :: RETURN

1550 FOR I=1 TO BUG(ID,0)

1560 CALL HCHAR(BUGY(ID),BUGX(ID),32) :: TX=BUGX(ID) :: TY=BUGY(ID)

1570 CALL TARGET_MOVE(BUGX(ID),BUGY(ID),TARGETX(ID),TARGETY(ID),OBJ,DX,DY)

1580 IF OBJ=120 THEN DEAD_FLAG=1 :: BUG(ID,5)=0 :: CALL HCHAR(BUGY(ID),BUGX(ID),32) :: RETURN

1590 IF OBJ=112 THEN BUGX(ID)=TX :: BUGY(ID)=TY

1600 IF OBJ=128 THEN BUGX(ID)=BUGX(ID)+DX :: BUGY(ID)=BUGY(ID)+DY :: BUG(ID,3)=BUG(ID,3)+FOOD_ENERGY :: IF BUG(ID,3)>B_MAX_ENERGY THEN BUG(ID,3)=B_MAX_ENERGY :: GOTO 1640

1610 IF OBJ=32 THEN BUGX(ID)=BUGX(ID)+DX :: BUGY(ID)=BUGY(ID)+DY

1620 CALL HCHAR(BUGY(ID),BUGX(ID),112)

1630 NEXT I

1640 CALL HCHAR(BUGY(ID),BUGX(ID),112)

1650 BUG(ID,3)=BUG(ID,3)-B_MOVE_ENERGY

1660 IF BUG(ID,3)<=0 THEN BUG(ID,5)=0 :: DEAD_FLAG=1 :: CALL HCHAR(BUGY(ID),BUGX(ID),32)

1670 RETURN

1680 FOR I=1 TO 5

1690 TX=PREDX(ID) :: TY=PREDY(ID)

1700 CALL HCHAR(PREDY(ID),PREDX(ID),32) :: CALL TARGET_MOVE(PREDX(ID),PREDY(ID),PTARGETX(ID),PTARGETY(ID),OBJ,DX,DY)

1710 IF OBJ<>112 THEN 1730

1720 PREDX(ID)=PREDX(ID)+DX :: PREDY(ID)=PREDY(ID)+DY :: GOSUB 2040 :: PRED(ID)=PRED(ID)+P_FOOD_ENERGY :: GOTO 1770

1730 IF OBJ<>32 AND OBJ<>128 THEN 1770

1740 PTARGETX(ID)=PTARGETX(ID)+DX :: PTARGETY(ID)=PTARGETY(ID)+DY :: PREDX(ID)=PREDX(ID)+DX :: PREDY(ID)=PREDY(ID)+DY

1750 CALL HCHAR(PREDY(ID),PREDX(ID),120)

1760 NEXT I

1770 IF PRED(ID)>P_MAX_ENERGY THEN PRED(ID)=P_MAX_ENERGY

1780 PRED(ID)=PRED(ID)-HUNT_ENERGY

1790 IF PRED(ID)>REST_LEVEL THEN PPHASE(ID)=3

1800 IF PRED(ID)<=0 THEN CALL HCHAR(PREDY(ID),PREDX(ID),32) :: PPHASE(ID)=4 ELSE CALL HCHAR(PREDY(ID),PREDX(ID),120) :: PPHASE(ID)=1

1810 RETURN

1820 IF BUG(ID,3)<8 OR NEXT_ID>50 THEN BUG(ID,4)=0 :: BPHASE(ID)=1 :: BUG(ID,3)=BUG(ID,3)-B_IDLE_ENERGY :: RETURN

1830 CALL REPRODUCE(BUGX(ID),BUGY(ID),NX,NY) :: IF NX=BUGX(ID) AND NY=BUGY(ID) THEN BUG(ID,3)=BUG(ID,3)-B_IDLE_ENERGY :: RETURN

1840 BUG(ID,4)=0 :: BUG(ID,3)=BUG(ID,3)-REP_ENERGY :: CALL HCHAR(NY,NX,112) :: BPHASE(ID)=1

1850 BUGX(NEXT_ID)=NX :: BUGY(NEXT_ID)=NY :: BUG(NEXT_ID,0)=BUG(ID,0) :: BUG(NEXT_ID,1)=BUG(ID,1) :: BUG(NEXT_ID,2)=BUG(ID,2)

1860 BUG(NEXT_ID,3)=8 :: BUG(NEXT_ID,4)=0 :: BUG(NEXT_ID,5)=1

1870 BPHASE(NEXT_ID)=1 :: NEXT_ID=NEXT_ID+1

1880 RETURN

1890 PRED(ID)=PRED(ID)-P_IDLE_ENERGY

1900 IF PRED(ID)1910 RETURN

1920 RETURN

1930 ID=0 :: DEAD_FLAG=0

1940 IF ID=NEXT_ID-1 AND BUG(ID,5)=0 THEN NEXT_ID=NEXT_ID-1 :: IF NEXT_ID=0 THEN 2630 ELSE RETURN

1950 IF BUG(ID,5)=1 THEN ID=ID+1 :: IF ID=NEXT_ID THEN RETURN ELSE 1940

1960 FOR I=ID+1 TO NEXT_ID-1

1970 FOR J=0 TO 5

1980 BUG(I-1,J)=BUG(I,J)

1990 NEXT J

2000 BUGX(I-1)=BUGX(I) :: BUGY(I-1)=BUGY(I) :: TARGETX(I-1)=TARGETX(I) :: TARGETY(I-1)=TARGETY(I) :: FLEE_FLAG(I-1)=FLEE_FLAG(I) :: BPHASE(I-1)=BPHASE(I)

2010 NEXT I

2020 NEXT_ID=NEXT_ID-1 :: IF NEXT_ID=0 THEN 2630

2030 GOTO 1940

2040 FOR Z=0 TO NEXT_ID-1

2050 IF BUGX(Z)=PREDX(ID) AND BUGY(Z)=PREDY(ID) AND BUG(Z,5)=1 THEN DEAD_FLAG=1 :: BUG(Z,5)=0 :: RETURN

2060 NEXT Z

2070 CALL KEY(0,K,S)

2080 IF K=83 OR K=115 THEN STOP

2090 IF K=82 OR K=114 THEN RESTART=1 :: RETURN

2100 IF K<>71 AND K<>103 THEN RETURN

2110 FOR I=1 TO 22

2120 FIELD$(I)=""

2130 NEXT I

2140 FOR I=1 TO 3

2150 SPEED(I)=0

2160 NEXT I

2170 FOR I=1 TO 5

2180 VIG(I)=0

2190 NEXT I

2200 FOR I=1 TO 10

2210 SOCIAL(I)=0

2220 NEXT I

2230 FOR Y=2 TO 23

2240 FOR X=2 TO 31

2250 CALL GCHAR(Y,X,OBJ)

2260 IF OBJ=128 OR OBJ=104 THEN IF X<10 THEN FIELD$(Y-1)=FIELD$(Y-1)&"0"&STR$(X)&STR$(OBJ) ELSE FIELD$(Y-1)=FIELD$(Y-1)&STR$(X)&STR$(OBJ)

2270 NEXT X

2280 FIELD$(Y-1)=FIELD$(Y-1)&"99"

2290 NEXT Y

2300 DISPLAY AT(23,2) ERASE ALL:"123 12345 1234567890"

2310 DISPLAY AT(24,1):"SPEED VIGILANCE SOCIAL"

2320 FOR I=0 TO NEXT_ID-1

2330 SPEED(BUG(I,0))=SPEED(BUG(I,0))+1

2340 VIG(BUG(I,1))=VIG(BUG(I,1))+1

2350 SOCIAL(BUG(I,2))=SOCIAL(BUG(I,2))+1

2360 NEXT I

2370 FOR I=1 TO 3

2380 DISPLAY AT(22-INT(SPEED(I)/2),1+I):"*"

2390 NEXT I

2400 FOR I=1 TO 5

2410 DISPLAY AT(22-INT(VIG(I)/2),9+I):"*"

2420 NEXT I

2430 FOR I=1 TO 10

2440 DISPLAY AT(22-INT(SOCIAL(I)/2),18+I):"*"

2450 NEXT I

2460 CALL KEY(0,K,S) :: IF S=0 THEN 2460

2470 CALL CLEAR :: I=1

2480 CALL HCHAR(1,1,96,32) :: CALL VCHAR(2,1,96,23) :: CALL VCHAR(2,32,96,23) :: CALL HCHAR(24,2,96,30) ! DRAW BORDER

2490 FOR Y=2 TO 23

2500 X=VAL(SEG$(FIELD$(Y-1),I,2))

2510 IF X=99 THEN 2530

2520 OBJ=VAL(SEG$(FIELD$(Y-1),I+2,3)) :: CALL HCHAR(Y,X,OBJ) :: I=I+5 :: GOTO 2500

2530 I=1

2540 NEXT Y

2550 FOR I=0 TO NEXT_ID-1

2560 CALL HCHAR(BUGY(I),BUGX(I),112)

2570 NEXT I

2580 FOR I=0 TO PRED_NUM-1

2590 IF PPHASE(I)<4 THEN CALL HCHAR(PREDY(I),PREDX(I),120)

2600 NEXT I

2610 DISPLAY AT(24,1) SIZE(4):TCYCLE

2620 RETURN

2630 DISPLAY AT(10,4) BEEP:"THE COLONY HAS DIED!" :: DISPLAY AT(12,4):"RESTART SIMULATION?"

2640 CALL KEY(0,K,S) :: IF S=0 THEN 2640

2650 IF K=89 OR K=121 THEN 380 ELSE STOP

2660 DATA -1,-1,-1,1,0,-1,0,1,1,-1,1,1

2670 DATA -2,-2,-2,2,0,-2,0,2,2,-2,2,2

2680 DATA -3,-3,-3,3,0,-3,0,3,3,-3,3,3

2690 DATA -4,-4,-4,4,0,-4,0,4,4,-4,4,4

2700 DATA -5,-5,-5,5,0,-5,0,5,5,-5,5,5

2710 FOR I=1 TO FOOD_REGEN :: CALL PLACE(X,Y) :: CALL HCHAR(Y,X,128) :: NEXT I

2720 RETURN

2730 SUB PLACE(X,Y)

2740 X=INT(RND*30)+2 :: Y=INT(RND*21)+2

2750 CALL GCHAR(Y,X,C) :: IF C<>32 THEN 2740

2760 SUBEND

2770 SUB DIR(CX,CY)

2780 CX=INT(RND*2) :: DIR=INT(RND*10)+1 :: IF DIR>5 THEN CX=-CX

2790 CY=INT(RND*2) :: DIR=INT(RND*10)+1 :: IF DIR>5 THEN CY=-CY

2800 IF CX=0 AND CY=0 THEN 2780

2810 SUBEND

2820 SUB LOOK(BUGX,BUGY,PREDATOR,FOOD,FRIEND,PX,PY,FX,FY,FRX,FRY,V)

2830 FOR I=1 TO 6 :: BLOCK(I)=0 :: NEXT I

2840 PREDATOR,FOOD,FRIEND=0

2850 RESTORE 2660

2860 FOR I=1 TO V

2870 FOR J=1 TO 6

2880 READ DX,DY

2890 IF BLOCK(J)=1 THEN 2960

2900 IF BUGX+DX>0 AND BUGX+DX<33 THEN X=BUGX+DX

2910 IF BUGY+DY>0 AND BUGY+DY<25 THEN Y=BUGY+DY :: CALL GCHAR(Y,X,OBJ)

2920 IF OBJ=96 OR OBJ=104 THEN BLOCK(J)=1 :: GOTO 2960 ! SKIP OBSTRUCTIONS

2930 IF OBJ=120 THEN PREDATOR=1 :: PX=X :: PY=Y :: SUBEXIT ! LOOK FOR PREDATORS

2940 IF OBJ=128 AND FOOD=0 THEN FOOD=1 :: FX=X :: FY=Y :: GOTO 2960! LOOK FOR FOOD

2950 IF OBJ=112 AND FRIEND=0 THEN FRIEND=1 :: BLOCK(J)=1 :: FRX=X :: FRY=Y ! LOOK FOR OTHER BUGS

2960 NEXT J

2970 NEXT I

2980 SUBEND

2990 SUB FLEE(BUGX,BUGY,PX,PY,S)

3000 X=BUGX :: Y=BUGY :: FOR I=1 TO S

3010 CALL HCHAR(Y,X,32)

3020 CALL DIR(CX,CY)

3030 NX=X+CX :: NY=Y+CY :: CALL GCHAR(NY,NX,OBJ)

3040 IF NX<2 OR NX>31 OR NY<2 OR NY>23 OR OBJ=104 THEN GOTO 3080 ! AVOID ALL OBSTRUCTIONS

3050 PDIST=INT(SQR((PX-X)^2+(PY-Y)^2)) :: NDIST=INT(SQR((PX-NX)^2+(PY-NY)^2))

3060 IF NDIST<=PDIST THEN GOTO 3020 ! AVOID DIRECTIONS TOWARDS PREDATOR

3070 X=NX :: Y=NY

3080 CALL HCHAR(Y,X,112)

3090 NEXT I

3100 BUGX=X :: BUGY=Y

3110 SUBEND

3120 SUB TARGET_MOVE(ORGX,ORGY,TX,TY,OBJ,DX,DY)

3130 DX=0 :: DY=0

3140 IF TX-ORGX>0 THEN DX=1 :: GOTO 3160

3150 IF TX-ORGX<0 THEN DX=-1

3160 IF TY-ORGY>0 THEN DY=1 :: GOTO 3180

3170 IF TY-ORGY<0 THEN DY=-1

3180 X=ORGX+DX :: Y=ORGY+DY :: CALL GCHAR(Y,X,OBJ)

3190 IF OBJ=104 THEN DX=0 :: DY=0

3200 SUBEND

3210 SUB MOVE(ORGX,ORGY,OBJ)

3220 CALL DIR(DX,DY) :: X=ORGX+DX :: Y=ORGY+DY :: CALL GCHAR(Y,X,OBJ)

3230 IF X<2 OR X>31 OR Y<2 OR Y>23 OR OBJ=104 THEN 3220

3240 ORGX=X :: ORGY=Y

3250 SUBEND

3260 SUB SEARCH(PREDX,PREDY,PREY,PRX,PRY)

3270 FOR I=1 TO 6 :: BLOCK(I)=0 :: NEXT I

3280 PREY=0 :: RESTORE 2660

3290 FOR I=1 TO 5

3300 FOR J=1 TO 6

3310 READ DX,DY

3320 IF BLOCK(J)=1 THEN 3390

3330 IF PREDX+DX>0 AND PREDX+DX<33 THEN X=PREDX+DX ELSE 3390

3340 IF PREDY+DY>0 AND PREDY+DY<25 THEN Y=PREDY+DY ELSE 3390

3350 CALL GCHAR(Y,X,OBJ)

3360 IF OBJ=96 OR OBJ=104 THEN BLOCK(J)=1 :: GOTO 3390 ! SKIP OBSTRUCTIONS

3370 IF OBJ=112 THEN PREY=1 :: PRX=X :: PRY=Y :: SUBEXIT ! LOOK FOR PREY

3380 IF OBJ=120 THEN BLOCK(J)=1

3390 NEXT J

3400 NEXT I

3410 SUBEND

3420 SUB REPRODUCE(X,Y,NX,NY)

3430 NX=0 :: NY=0

3440 FOR I=X-1 TO X+1

3450 FOR J=Y-1 TO Y+1

3460 CALL GCHAR(J,I,OBJ) :: IF OBJ=32 OR OBJ=128 THEN NX=I :: NY=J :: SUBEXIT

3470 NEXT J

3480 NEXT I

3490 IF NX=0 AND NY=0 THEN NX=X :: NY=Y

3500 SUBEND[/code]

 

 

 

Clearly, we are well beyond the contents of the original book which inspired all of this, and yet there are still many possibilities out there. Any further work on this simulation line however will need likely be done in another language such as TurboForth or Pascal for speed.

GAMMA.ZIP

Edited by Vorticon
  • Like 2
Link to comment
Share on other sites

What a cool concept!!!

 

This is some in-depth stuff here, man!

 

I'm going to run the sim a few times and I'll post some results when I can.

 

***Side note***

 

I also HIGHLY recommend TidBit to anyone working on in-depth logic or complex menu features... The last thing TI-related I did before I moved to Tennessee was build a fairly awesome menu engine for the Beryl project... None of which I could have done very well without it. I, too, would love to have TidBit in a standalone format...

Link to comment
Share on other sites

Vorticon, how would you define "stable"....

 

So far the counter is at 15 and the sim seems to be at a relative stability... I have lost one predator, but the bugs and food seem to be rejuvenating fairly steadily.

 

Another thing... I did not write down what my settings were I started with. If I start a new sim, will my old settings be the starting point for my new sim?

Link to comment
Share on other sites

Okay, this is very cool. I have some pictures of the first simulation I ran.

 

graph95_zps541be5ae.jpg

 

At cycle 95, the graph showed some interesting stuff... very different from the initial graph early on... It seems the bugs specialized pretty quickly in an attempt to adapt.

 

 

sim96_zpsd1ebca14.jpg

 

Here they are, thriving, having outlasted the predators... Plenty of food, plenty of bugs. Looks pretty good.

 

 

sim107_zps00ac8816.jpg

 

Here at cycle 107, however, the food supply is running short and the bugs start to die off little by little... They still maintain for quite a while, but it's evident that the growing population doesn't have the food supply regeneration frequency they need to maintain the population.

 

 

sim134dead_zps9a163eb3.jpg

 

Alas, after the population dwindled down to just a few bugs, the replenished food supply did not come in time. The colony died.

 

 

**I'm very intrigued by this simulation...

 

 

 

**SETTINGS**

 

variablessim_zps73639161.jpg

  • Like 1
Link to comment
Share on other sites

Vorticon, how would you define "stable"....

 

So far the counter is at 15 and the sim seems to be at a relative stability... I have lost one predator, but the bugs and food seem to be rejuvenating fairly steadily.

 

Another thing... I did not write down what my settings were I started with. If I start a new sim, will my old settings be the starting point for my new sim?

 

A stable ecosystem is when the bugs and predators do not completely die off over an extended period of time (500 cycles?). Now you could also just have bugs with no predators that can perpetuate their existence in perfect balance with the food supply, and in that situation the farthest I ever got was 256 cycles. With predators around, the latter die off usually within 25-30 cycles, and I have yet to find the correct ratio of bugs to predators, along with the various energy gains/losses settings. It certainly gives us a glimpse of why it is so easy for humans to disrupt current ecosystems which are likely very delicately balanced...

Link to comment
Share on other sites

Your simulation run clearly shows that speed and vigilance were determined to be crucial factors in survival. However, I am a little surprised that social interaction was so low as to be practically irrelevant. In real life, prey tend to huddle in herds for protection, which does not seem to be the case under these specific circumstances... I'm going to replicate your settings and see if I can re-create that finding :)

Link to comment
Share on other sites

Below is the formatted source code (which for some mysterious reason has lost all of its indentations...):

 

You forgot to use "code" tags inside the "spoiler" tags:

 

[ spoiler ] [ code ] your code goes here [ /code ] [ /spoiler ]

 

Remove the spaces of course. Also note that after an update to the forum some time ago, any group of four spaces are converted to tabs, even in code tags, so it will blow the formatting anyway, as well as any kind of ASCII formatting you try to do.

 

Matt, I was wondering if you would consider creating a stand-alone version of TidBit so we are not dependent on having an internet connection all the time.

 

http://atariage.com/forums/topic/172765-basic-xb-translator/

 

It is on page 14 of the forum, but I'll bump it so you can find it easier. The first post in the thread has the .zip. It is written in PHP so you can run it on pretty much any OS you want to use.

Link to comment
Share on other sites

  • 3 years later...

A couple of days ago I was looking for a programming project to run on my recently completed PDP-8 replica computer, and I remembered a chapter on neural nets in the book titled The Tinkertoy Computer and Other Machinations from the pages of Scientific American by A.K. Dewdney. A fascinating book by the way with lots of super interesting computational projects and you can find the PDF copy here: https://archive.org/details/tinkertoycomputer00dewd

So based on the text and the algorithmic outline, I programmed a neural net which is capable of converting from polar to cartesian coordinates on a purely empirical basis with just a set of interconnected "neurons". There are 3 neurons for input (2 for the polar coordinates and one as a fixed offset number), 2 output neurons for the resulting X/Y coordinates, and 20 intermediate neurons connected to each of the input and output neurons. Each connection is initially given a random weight. What the program does is get a random set of polar coordinates (radius and angle) and feed them to the input neurons. Then the output neurons result is compared to the expected X/Y coordinates from the standard sine/cosine conversions and the error is fed retrogradely to the intermediate neurons, with the weights of the connections between both the input and output sides adjusted accordingly.

When this is repeated several thousand times, the net will usually converge to the correct result within 6 decimal places consistently, at least on the PDP-8, all without having any knowledge of trigonometry or any concept of coordinates!

 

Here's the program for the TI. It required some tweaking because the PDP-8 has a number representation limit of 10-626 whereas the TI goes to only 10-99 and so I was running into overflow issues. It also runs VERY slowly, doing about 200 iterations per hour. Given that we need at least 10000 iterations to start seeing a convergence, that adds up to about 50 hrs of computing time at a minimum :-D

 

 

1 REM POLARNET
2 REM NEURAL NET FOR POLAR TO CARTESIAN COORDINATES CONVERSION
5 REM INITIALIZATION
7 RANDOMIZE
10 DIM S1(3,20),S2(20,3)
20 DIM INP(3),O(2),T(2),E(2)
21 DIM M1(20),M0(20)
22 DIM G(20),G1(20)
25 INP(3)=1000
40 FOR I=1 TO 20
50 FOR J=1 TO 3
60 S1(J,I)=0.1*RND
70 NEXT J
80 NEXT I
90 FOR I=1 TO 2
100 FOR J=1 TO 20
110 S2(J,I)=0.1*RND
120 NEXT J
130 NEXT I
140 REM FORWARD COORDINATE CONVERSION
150 INP(1)=RND
170 INP(2)=RND*2*3.14159265359
180 FOR I=1 TO 20
190 M1(I)=0
200 FOR J=1 TO 3
210 M1(I)=0.1*(M1(I)+S1(J,I)*INP(J))
215 IF ABS(M1(I))>220 THEN 150
220 M0(I)=0.1*(1/(1-EXP(-M1(I))))
225 NEXT J
226 NEXT I
227 T(1)=INP(1)*COS(INP(2))
228 T(2)=INP(1)*SIN(INP(2))
230 FOR I=1 TO 2
240 O(I)=0
250 FOR J=1 TO 20
260 O(I)=O(I)+S2(J,I)*M0(J)
270 E(I)=T(I)-O(I)
280 NEXT J
290 NEXT I
295 REM BACK PROPAGATION
300 FOR I=1 TO 2
310 FOR J=1 TO 20
320 S2(J,I)=S2(J,I)+0.1*M0(J)*E(I)
330 NEXT J
340 NEXT I
350 FOR I=1 TO 20
360 G(I)=0
370 FOR J=1 TO 2
380 G(I)=G(I)+E(J)*S2(I,J)
390 G1(I)=M1(I)*(1-M1(I))
400 NEXT J
410 NEXT I
420 FOR I=1 TO 2
430 FOR J=1 TO 20
440 D=0.1*G1(J)*G(J)*INP(I)
450 S1(I,J)=S1(I,J)+D
460 NEXT J
470 NEXT I
475 REM DISPLAY RESULTS
480 N=N+1
485 PRINT
486 PRINT "TRIAL #";N
490 PRINT "RADIUS=";INP(1),"ANGLE=";INP(2)
500 PRINT "CALCULATED X=";O(1),"CALCULATED Y=";O(2)
510 PRINT "TARGET X=";T(1),"TARGET Y=";T(2)
550 PRINT "TOTAL ERROR=";SQR(E(1)^2+E(2)^2)
560 GOTO 150
570 END

 

 

 

Fascinating stuff... Going further, one can experiment with the number of intermediate neurons or with different types of calculations and see what happens.

Trust me, read the book. Highly recommended.

  • Like 3
Link to comment
Share on other sites

Though it is not close to the capacity of the PDP-8, the TI via TI Basic actually can go down to 10-128—the console display routine just doesn't display it properly. You can prove this by assigning a number between 10-99 and 10-128 to a variable and displaying the product of that variable and a number that will bring it back into printing range (2-digit exponent):

 

10 A = 1E-120

20 B = 1E21

30 PRINT A;B;A*B

RUN

1.E-** 1.E+21 1.E-99

 

fbForth 2.0 and TurboForth 1.2 will handle it because I rewrote part of the floating point package I ported from the MDOS floating point library (with permission, of course) to include a formatted print option for 3-digit E notation.

 

...lee

Link to comment
Share on other sites

Though it is not close to the capacity of the PDP-8, the TI via TI Basic actually can go down to 10-128—the console display routine just doesn't display it properly. You can prove this by assigning a number between 10-99 and 10-128 to a variable and displaying the product of that variable and a number that will bring it back into printing range (2-digit exponent):

 

10 A = 1E-120

20 B = 1E21

30 PRINT A;B;A*B

RUN

1.E-** 1.E+21 1.E-99

 

fbForth 2.0 and TurboForth 1.2 will handle it because I rewrote part of the floating point package I ported from the MDOS floating point library (with permission, of course) to include a formatted print option for 3-digit E notation.

 

...lee

 

Ah... I was just going by the User Manual content. Good to know!

Link to comment
Share on other sites

That is really cool! I'm definitely going to have to read that book. How do you know how many neurons you need for a given task? Also, once you "teach" the network, can you then feed in other polar coordinates and get results faster?

 

Apparently significantly increasing the number of intermediate neurons beyond 20-30 does not necessarily enhance performance, and may actually give you a worse result... At least according to the book :) Maybe something to experiment with...

And yes, once the network reaches a stable output level, you can just preserve the weights of all the connections and just feed it polar coordinates. One way to do it is say once the program reaches 20000 iterations, you can have it ask you for input, then have it only run the forward coordinate conversion section and not go through the back propagation section so that no changes to the connection weights are made. Even better yet, using the Missing Link bitmap extensions, at the end of 20000 iterations, I could have the network go through 360 degrees sequentially 1 degree at a time with a standard radius of 1 and have it draw the resulting pixels at the calculated x/y coordinates on the screen. Next to it go through the same procedure but using the standard sine/cosine conversion and match the network circle to the calculated one. They should pretty much match. If the network circle is distorted, then it's not quite stable yet.

The problem is that it's really slow on the TI, and as a matter of fact my program has been running for nearly 28hrs now and it still has ways to go... The PDP-8 is much faster.

Link to comment
Share on other sites

  • 4 weeks later...

So in a bout of insomnia, I was watching an episode of the British TV show from the 80's titled The Computer Programme, and they were showing a program on the BBC micro learning how to play Tic-Tac-Toe without knowing the rules. It seemed like the perfect game to try something like that on given that it is super simple to play, so I decided to try and create something similar for the TI 99/4A.

 

The program is written in XB over the course of the past few hours. Basically when you start it up it will go into learning mode and play itself for the number of trials you input. Needless to say that a large number of trials will be needed in order for it to improve its play. What it does is randomly place pieces on the board and compile statistics on the likelihood that any particular move at any particular time will have a good chance of leading to a win. Once it's done with the trials, it will have in memory a list of "best moves" which it will try to use against the human player.

Then you will get a chance to test its mettle in real games.

 

The video below is just a quick demo with only 10 trials, so needless to say that it plays horrifically bad. I'm currently having it run a 500 trial run (it's slow...) and I'll see how its play improves. It may need far more than that though...

* Note: Somehow I managed to append the video to some test footage of my Phoenix chess game under development. No sure how this happened...

 

https://youtu.be/M-T47lRBqWE

 

Here's the code. It's rough but I wrote it pretty quickly as an experiment :) The squares are represented as a grid of numbers 1-9 as below which you will use to input the player moves:

 

1 2 3

4 5 6

7 8 9

 

EDIT: I caught a couple of bugs with further testing. With 1000 trials, it was now able to consistently recognize where to place a marker to complete a row, column or diagonal and thus win. It's still pretty dumb otherwise :grin: I'm going to have it run for a few thousand trials overnight and see what kind of improvements I get.

 

 

10 RANDOMIZE
11 CALL CLEAR
12 DIM WD1(9,9),WD2(8,9),L1(9,9),L2(8,9),M1(9,9),M2(8,9)
20 DISPLAY AT(1,1)BEEP:"READY TO LEARN!" :: DISPLAY AT(2,1):"PRESS ANY KEY TO START..."
30 CALL KEY(0,K,S) :: IF S=0 THEN 30
31 CALL CLEAR
32 MODE=1
35 FOR I=1 TO 9 :: B$(I)="" :: NEXT I
36 DISPLAY AT(1,1)BEEP:"ENTER # OF TRIALS: " :: ACCEPT AT(1,20):MT
50 GOSUB 10000
51 DISPLAY AT(22,1):"TRIAL #";1
55 GOSUB 10060 :: DISPLAY AT(24,1):""
60 SIDE=1
80 LOC=INT(RND*(9-TURN))+1
90 N=0 :: P=1
100 IF B$(P)="" THEN N=N+1 :: IF N=LOC AND SIDE=1 THEN B$(P)="X" :: GOSUB 10060 :: GOTO 111 ELSE IF N=LOC THEN B$(P)="O" :: GOSUB 10060 :: GOTO 111
110 P=P+1 :: GOTO 100
111 GOSUB 10120
112 IF SIDE=1 THEN S1(TURN+1)=P ELSE S2(TURN+1)=P
113 IF RESULT<>0 THEN 140
120 TURN=TURN+1 :: IF TURN>8 THEN GOTO 140
130 IF SIDE=1 THEN SIDE=2 ELSE SIDE=1
135 GOTO 80
140 IF RESULT=1 THEN DISPLAY AT(24,1)BEEP:"X WINS!" :: WX=WX+1 :: DISPLAY AT(5,15):"X WIN #: ";WX
150 IF RESULT=2 THEN DISPLAY AT(24,1)BEEP:"O WINS!" :: WO=WO+1 :: DISPLAY AT(6,15):"O WIN #: ";WO
151 IF RESULT=0 THEN DISPLAY AT(24,1)BEEP:"DRAW!" :: D=D+1 :: DISPLAY AT(7,15):"DRAW #: ";D
152 GOSUB 10250
160 TRIAL=TRIAL+1 :: IF TRIAL>MT-1 THEN 190 ELSE DISPLAY AT(22,1):"TRIAL #";TRIAL+1
170 FOR I=1 TO 9 :: B$(I)="" :: NEXT I :: TURN=0
175 FOR I=1 TO 9 STEP 2 :: S1(I)=0 :: NEXT I
176 FOR I=2 TO 8 STEP 2 :: S2(I)=0 :: NEXT I
180 GOTO 55
190 DISPLAY AT(20,1)BEEP:"LEARNING COMPLETE!" :: DISPLAY AT(21,1):"PRESS ANY KEY"
200 CALL KEY(0,K,S) :: IF S=0 THEN 200
205 CALL CLEAR
206 MODE=2
210 FOR I=1 TO 9 STEP 2
220 FOR J=1 TO 9
230 IF L1(I,J)=0 THEN M1(I,J)=WD1(I,J)ELSE M1(I,J)=WD1(I,J)/L1(I,J)
240 NEXT J
250 NEXT I
260 FOR I=2 TO 8 STEP 2
270 FOR J=1 TO 9
280 IF L2(I,J)=0 THEN M2(I,J)=WD2(I,J)ELSE M2(I,J)=WD2(I,J)/L2(I,J)
290 NEXT J
300 NEXT I
310 DISPLAY AT(1,1)BEEP:"READY TO PLAY!" :: DISPLAY AT(2,1):"PRESS ANY KEY TO START..."
320 CALL KEY(0,K,S) :: IF S=0 THEN 320
330 FOR I=1 TO 9 :: B$(I)="" :: NEXT I
331 SIDE=1 :: TURN=1
332 DISPLAY AT(5,1)BEEP:"PLAY FIRST? (Y/N)"
333 CALL KEY(0,K,S) :: IF S=0 THEN 333
334 IF CHR$(K)="Y" THEN 450
335 CALL CLEAR
340 GOSUB 10000
350 DISPLAY AT(22,1)BEEP:"MY TURN..." :: DISPLAY AT(24,1):""
355 BEST=0
360 IF SIDE=2 THEN 410
370 FOR I=1 TO 9
380 IF MAX(M1(TURN,I),BEST)>BEST AND B$(I)="" THEN BPOS=I :: BEST=M1(TURN,I) :: GOTO 390
381 IF MAX(M1(TURN,I),BEST)382 IF INT(RND*10)+1<=5 AND B$(I)="" THEN BEST=M1(TURN,I) :: BPOS=I
390 NEXT I
400 B$(BPOS)="X" :: GOSUB 10060 :: TURN=TURN+1 :: SIDE=2
401 GOSUB 10120 :: IF RESULT=0 THEN 460
402 DISPLAY AT(23,1)BEEP:"I WIN!!!" :: DISPLAY AT(24,1):"PLAY AGAIN? (Y/N)"
403 CALL KEY(0,K,S) :: IF S=0 THEN 403
404 IF CHR$(K)="N" THEN STOP
405 CALL CLEAR :: GOTO 310
410 FOR I=1 TO 9
420 IF MAX(M2(TURN,I),BEST)>BEST AND B$(I)="" THEN BPOS=I :: GOTO 430
421 IF MAX(M2(TURN,I),BEST)422 IF INT(RND*10)+1<=5 AND B$(I)="" THEN BEST=M2(TURN,I) :: BPOS=I
430 NEXT I
440 B$(BPOS)="O" :: GOSUB 10060 :: TURN=TURN+1 :: SIDE=1 :: GOSUB 10120 :: GOTO 401
450 CALL CLEAR :: GOSUB 10000
460 IF TURN>9 THEN DISPLAY AT(23,1)BEEP:"DRAW!!!" :: DISPLAY AT(24,1)BEEP:"PLAY AGAIN? (Y/N)" :: GOTO 403
465 DISPLAY AT(22,1)BEEP:"YOUR TURN..."
470 DISPLAY AT(24,1)BEEP:"ENTER MOVE..."
480 CALL KEY(0,K,S) :: IF S=0 THEN 480
490 IF K<49 OR K>57 THEN 480
500 IF B$(K-48)<>"" THEN 480
510 IF SIDE=1 THEN B$(K-48)="X" ELSE B$(K-48)="O"
520 GOSUB 10060 :: GOSUB 10120
530 IF RESULT<>0 THEN 570
540 TURN=TURN+1 :: IF TURN>9 THEN 460
550 IF SIDE=1 THEN SIDE=2 ELSE SIDE=1
560 GOTO 350
570 DISPLAY AT(23,1)BEEP:"YOU WIN!!!" :: DISPLAY AT(24,1)BEEP:"PLAY AGAIN? (Y/N)" :: GOTO 403
10000 REM DISPLAY BOARD ROUTINE
10010 CALL CLEAR
10020 IF MODE=2 THEN DISPLAY AT(1,1):"PLAYING MODE" ELSE DISPLAY AT(1,1):"LEARNING MODE"
10030 FOR I=1 TO 11 :: DISPLAY AT(I+4,4):"* *" :: NEXT I
10040 DISPLAY AT(8,1):"***********" :: DISPLAY AT(12,1):"***********"
10050 RETURN
10060 REM DISPLAY GAME MARKERS ROUTINE
10065 X=2 :: Y=6
10070 FOR I=1 TO 9
10080 DISPLAY AT(Y,X)SIZE(1):B$(I)
10090 X=X+4 :: IF X>10 THEN X=2 :: Y=Y+4
10100 NEXT I
10110 RETURN
10120 REM CHECK FOR WIN
10130 OFST=0
10140 FOR I=1 TO 3
10150 IF(B$(I+OFST)=B$(I+1+OFST))AND(B$(I+1+OFST)=B$(I+2+OFST))AND(B$(I+OFST)<>"")THEN 10240
10160 OFST=OFST+2 :: NEXT I
10180 FOR I=1 TO 3
10190 IF(B$(I)=B$(I+3))AND(B$(I+3)=B$(I+6))AND(B$(I)<>"")THEN 10240
10200 NEXT I
10210 IF(B$(1)=B$(5))AND(B$(5)=B$(9))AND(B$(1)<>"")THEN 10240
10220 IF(B$(3)=B$(5))AND(B$(5)=B$(7))AND(B$(3)<>"")THEN 10240
10230 RESULT=0 :: RETURN
10240 RESULT=SIDE :: RETURN
10250 REM TABULATE RESULTS
10260 IF SIDE=2 THEN 10420
10270 IF RESULT=2 THEN 10350
10280 FOR I=1 TO 9 STEP 2
10290 WD1(I,S1(I))=WD1(I,S1(I))+1
10300 NEXT I
10310 FOR I=2 TO 8 STEP 2
10320 L2(I,S2(I))=L2(I,S2(I))+1
10330 NEXT I
10340 RETURN
10350 FOR I=1 TO 9 STEP 2
10360 L1(I,S1(I))=L1(I,S1(I))+1
10370 NEXT I
10380 FOR I=2 TO 8 STEP 2
10390 WD2(I,S2(I))=WD2(I,S2(I))+1
10400 NEXT I
10410 RETURN
10420 IF RESULT=1 THEN 10500
10430 FOR I=1 TO 9 STEP 2
10440 L1(I,S1(I))=L1(I,S1(I))+1
10450 NEXT I
10460 FOR I=2 TO 8 STEP 2
10470 WD2(I,S2(I))=WD2(I,S2(I))+1
10480 NEXT I
10490 RETURN
10500 FOR I=1 TO 9 STEP 2
10510 WD1(I,S1(I))=WD1(I,S1(I))+1
10520 NEXT I
10530 FOR I=2 TO 8 STEP 2
10540 L2(I,S2(I))=L2(I,S2(I))+1
10550 NEXT I
10560 RETURN

 

  • Like 4
Link to comment
Share on other sites

A few observations after 5000 trials (thank heavens for overdrive mode in Classic99!):

- There seems to be a 50% higher chance to win for the player who starts first. This seems to be corroborated by Dr. Google.

- The computer seems to consistently favor the right lower corner of the board. Odd...

- It still has not discovered the importance of the center square

- It still plays like shit...

 

I'm going to try and tweak things a bit. I'm afraid it will need larger trial sizes still, and that is where it becomes really painful on the TI... Perhaps my next project should be networking several TI's for parallel processing! :-D

  • Like 2
Link to comment
Share on other sites

  • 5 years later...
  • 1 year later...
On 10/30/2016 at 1:34 AM, Vorticon said:

I'm going to try and tweak things a bit. I'm afraid it will need larger trial sizes still, and that is where it becomes really painful on the TI... Perhaps my next project should be networking several TI's for parallel processing! :-D

Hey Vorticon,

 

Very neat TI program.  Thanks for starting this interesting discussion of early BASIC AI programming.  I've been trying to compile a list (and working examples) of such programs, including some from Heiserman's book.

Type-in-Mania-AI-Programs

Thought you and others here might be interested. 

  • Like 1
Link to comment
Share on other sites

46 minutes ago, jgerrie said:

Hey Vorticon,

 

Very neat TI program.  Thanks for starting this interesting discussion of early BASIC AI programming.  I've been trying to compile a list (and working examples) of such programs, including some from Heiserman's book.

Type-in-Mania-AI-Programs

Thought you and others here might be interested. 

Very cool project! I'm definitely going to take a close look at some of these tonight :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...