Corona virus simulator

General FreeBASIC programming questions.
ShawnLG
Posts: 142
Joined: Dec 25, 2008 20:21

Corona virus simulator

Post by ShawnLG »

I have written a small program that shows how the corona virus spreads from person to person from close contact. This does not take on real world simulation of the corona virus. This would be very difficult to program. Way too many variables and situations would need to be considered.

[Updated Mar 25, 2020:]
Now includes "Shelter-in-place" which shows how effective it is on mitigating the spread of the virus.

[Updated Apr 14, 2020:]
Added max & min travel distance from home. This will remove nomadic movement and simulate communal movement.
Added vacation (long distance travel). This has a huge effect on the virus's long term survival. It can escape from heard immunity.
Added hashing for much faster O time complexity for infection search.

CoronaSim.bas

Code: Select all

'Corona virus (COVID 19) simulator v1.1 by Shawn Grieb

Const WHITE = RGB(255,255,255)
Const GREEN = RGB(0,255,0)
Const RED =  RGB(255,0,0)
Const YELLOW = RGB(200,200,0)
Const GREY = RGB(175,175,175)
Const DARKGREY = RGB(100,100,100)
Const HEALTHY = 0
Const INFECTED = 1
Const IMMUNED = 2
Const DEAD = 3
Const MOBILE = 0
Const STAYATHOME = 1 

'Hash settings
Const HASHSTACKSIZE = 10
Const HASHMULTIPLYER = 5

'User modifiable constants.
Const NUMOFPEOPLE = 20000
Const SCREENX = 1280
Const SCREENY = 720
Const DEATHRATE = 0.034   'Percent of people who die from complications of the virus. Define in decimal form. 
Const SHELTERINPLACE = .25'Percent of people who shelter in place. Define in decimal form.
Const INFDURATION = 500   'Infection duration.
Const IMMDURATION = 5000  'Immunity duration.
Const MAXDISTANCE = 15    'The max distance the most adventurous persons will travel from home. (This is not vacation travel)
Const MINDISTANCE = 10    'The minimum distance to define nonadventurous homebodies.
Const TRAVELDELAYRATE = 5 'Number of program iterations before one person vacation travels (long distance) to a new random point and make it their new home base.

Type person
	Dim As Integer homex 'Homex and homey is the person's home base or center of their area of travel in their community.
	Dim As Integer homey 'Homex and homey will make the random walk non-nomadic.
	Dim As Integer distance 'How far from home the person travels or how adventurous they are.
	Dim As Integer x 'X and Y are current position on map
	Dim As Integer y
	Dim As Integer healthstate
	Dim As Integer mobilestate
	Dim As Integer durationcount
End Type

'StashTable, the hashing of stacked bins.
type StashTable
    declare Constructor(tsize as Integer, stackdepth As integer)
    declare destructor()
    declare sub push(xkey As Integer, ykey As Integer, id As Integer)
    Declare Function setstackdump(xkey As Integer, ykey As Integer) As Integer
    Declare Function pop() As Integer
    Declare Sub reset()
    private:
    dim as Integer Ptr Ptr sht
    Dim As Integer Ptr tx
    Dim As Integer Ptr ty
    Dim As Integer Ptr si
    Dim as Integer tablesize
    Dim As Integer stacksize
    Dim As Integer popstackindex
    Dim As LongInt poptableindex
End type

constructor StashTable(dimsize as Integer, stackdepth As integer)
    this.sht = new Integer Ptr [dimsize+1]
    this.tx = New Integer [dimsize+1]
    this.ty = New Integer [dimsize+1]
    this.si = New Integer [dimsize+1]
    For i As Integer = 0 To dimsize
    	this.sht[i] = New Integer [stackdepth+1]
    	this.tx[i] = -1
    	this.si[i] = 0
    Next i
    this.tablesize = dimsize
    this.stacksize = stackdepth
    this.popstackindex = -1
    this.poptableindex = -1
End constructor

destructor StashTable()
  	For i As Integer = 0 To this.tablesize
  		Delete [] This.sht[i]
  	Next i
    Delete [] this.sht
    Delete this.tx
    Delete this.ty
    Delete This.si
End destructor
 
sub StashTable.push(xkey As Integer, ykey As Integer, idkey As Integer)
    dim as LongInt index = (xkey * ykey) mod this.tablesize
    dim as Integer hashcount = 0
    Do
    	If This.tx[index] = -1 Then
    		this.tx[index] = xkey
    		this.ty[index] = ykey
    	EndIf
    	'push key in valid index
    	If this.tx[index] = xkey And this.ty[index] = ykey Then
    		If this.si[index] < this.stacksize Then
    			this.sht[index][this.si[index]] = idkey
    			this.si[index] = this.si[index] + 1
    			Exit Do
    		Else
    			Print "Push stack overflow!"
    			Sleep
    			exit Do
    		EndIf
    	Else
    		index = (index + 1) mod this.tablesize
  			if hashcount > this.tablesize Then
  				print "Push hash falure!"
  				Sleep
  			end If
  			hashcount = hashcount + 1
    	EndIf
    loop
end Sub

function StashTable.setstackdump(xkey As Integer, ykey As Integer) As Integer
	Dim As LongInt index = (xkey * ykey) Mod this.tablesize
	Dim as Integer hashcount = 0
    Do
    	If this.tx[index] = -1 Then 
    		Return 0
  		ElseIf This.tx[index] = xkey And this.ty[index] = ykey Then
  			this.poptableindex = index
  			this.popstackindex = This.si[index] - 1
  			Return -1
  		Else
  			index = (index + 1) mod this.tablesize
  			if hashcount > this.tablesize Then
  				print "Setstackdump hash falure!"
  				Sleep
  			end If
  			hashcount = hashcount + 1
  		EndIf  
    Loop
End Function

Function StashTable.pop() As Integer
	Dim As Integer popkey = -1
	If this.poptableindex > -1 Then
		popkey = this.sht[this.poptableindex][this.popstackindex]
		this.popstackindex = this.popstackindex - 1
		If this.popstackindex = -1 Then
			this.poptableindex = -1
		EndIf
	End If
	Return popkey
End Function

Sub StashTable.reset()
	For t As Integer = 0 To This.tablesize
    	this.tx[t] = -1
    	this.si[t] = 0
    Next t
    this.popstackindex = -1
    this.poptableindex = -1
End Sub

Dim As stashtable hash = stashtable(NUMOFPEOPLE * HASHMULTIPLYER, HASHSTACKSIZE)

ScreenRes SCREENX, SCREENY, 32,,0
Dim As Any Ptr backbuffer, mapbuffer
backbuffer = ImageCreate(SCREENX,SCREENY,,32)
mapbuffer = ImageCreate(SCREENX,SCREENY,,32)
Dim As Integer travelstate = 0
Dim As person Ptr p
p = New person [NUMOFPEOPLE+1]

For i As Integer = 1 To NUMOFPEOPLE
	p[i].homex = SCREENX * Rnd
	p[i].homey = SCREENY * Rnd
	p[i].x = p[i].homex
	p[i].y = p[i].homey
	p[i].distance = (MAXDISTANCE-MINDISTANCE) * Rnd + MINDISTANCE
	p[i].healthstate = HEALTHY
	P[i].mobilestate = MOBILE
	If Rnd < SHELTERINPLACE Then p[i].mobilestate = STAYATHOME
	p[i].durationcount = 0
Next
p[1].healthstate = INFECTED 'Start with one person infected.

Do
	Dim As Integer direction
	hash.reset()
	For i As Integer = 1 To NUMOFPEOPLE
	 	If p[i].healthstate <> DEAD Then
	 		If p[i].mobilestate = MOBILE Then
	 			direction = 5 * Rnd
	 			Select Case direction
	 			Case 1'left
		 			If p[i].x > 1 Then
		 				If p[i].x > p[i].homex - p[i].distance Then
		 					p[i].x = p[i].x - 1
		 				End If
		 			EndIf
	 			Case 2'right
		 			If P[i].x < SCREENX-1 Then
		 				If p[i].x < p[i].homex + p[i].distance Then
		 			 		p[i].x = p[i].x + 1
		 			 	End If
		 			EndIf
	 			Case 3'up
		 			If p[i].y > 1 Then
		 				If p[i].y > p[i].homey - p[i].distance Then
		 					p[i].y = p[i].y - 1
		 				End If
		 			EndIf
	 			Case 4'down
		 			If p[i].y < SCREENY-1 Then
		 				If p[i].y < p[i].homey + p[i].distance Then
		 					p[i].y = p[i].y + 1
		 				End If
		 			EndIf
	 			End Select
	 		End If
	 	End If
	 	hash.push(p[i].x, p[i].y, i)
	Next i
	For i As Integer = 1 To NUMOFPEOPLE
	 	'Check for nebors and infect them.
	 	If p[i].healthstate = INFECTED Then
	 		If hash.setstackdump(p[i].x, p[i].y) Then
	 			Dim As Integer index
	 			Do		
	 				index = hash.pop()
	 				If index > -1 Then
	 					If p[index].healthstate = HEALTHY Then 
	 						p[index].healthstate = INFECTED
	 					End If
	 				Else
	 					Exit Do
	 				End If
	 			Loop
	 		EndIf
	 	End If
	 	'Check infected statecount.
	 	If p[i].healthstate = INFECTED Then
	 		If p[i].durationcount < INFDURATION Then
	 			p[i].durationcount = p[i].durationcount + 1
	 		Else
	 			If Rnd < DEATHRATE Then
	 				p[i].healthstate = DEAD
	 				p[i].durationcount = 0
	 			Else
	 				p[i].healthstate = IMMUNED
	 				p[i].durationcount = 0
	 			EndIf
	 		EndIf
	 	EndIf
	 	'Check immuned statecount.
	 	If p[i].healthstate = IMMUNED Then
	 		If p[i].durationcount < IMMDURATION Then
	 			p[i].durationcount = p[i].durationcount + 1
	 		Else
	 			p[i].healthstate = HEALTHY
	 			p[i].durationcount = 0
	 		EndIf
	 	EndIf
	Next
	Line backbuffer, (0,0)-(SCREENX-1,SCREENY-1),0,BF'cls
	
	'Move one person for long distance travel. (move or vacation)
	If travelstate = 0 Then
		Dim As Integer index = (Rnd * NUMOFPEOPLE+1)-1 'Pick a person at random.
		If p[index].healthstate <> DEAD Then 'The dead do not go on vacation.
			Dim As Integer oldx = p[index].x
			Dim As Integer oldy = p[index].y
			Dim As Integer newx = Rnd * SCREENX
			Dim As Integer newy = Rnd * SCREENY
			p[index].homex = newx
			p[index].homey = newy
			p[index].x = p[index].homex
			p[index].y = p[index].homey
			'Draw travel vector.
			Line backbuffer, (newx,newy)-(oldx,oldy),GREY
		End If
	End If
	travelstate = (travelstate + 1) Mod TRAVELDELAYRATE
	'Draw persons and stats.
	Dim As Integer healthycount = 0, infectedcount = 0, immunedcount = 0, deadcount = 0
	
	For i As Integer = 1 To NUMOFPEOPLE
		Dim As Integer x = p[i].x, y = p[i].y
		Dim As Long c
		Select Case p[i].healthstate
		Case HEALTHY
			c = GREEN
			healthycount = healthycount + 1
		Case INFECTED
			c = RED
			infectedcount = infectedcount + 1
		Case IMMUNED
			c = YELLOW
			immunedcount = immunedcount + 1
		case DEAD
			c = WHITE
			deadcount = deadcount + 1
		End Select
		PSet backbuffer, (x,y),c
	Next
	Draw String backbuffer, (SCREENX/2 -48, 0), "(Corona Sim v1.1)", WHITE,, PSet
	Draw String backbuffer, (0, 0), "Healthy:  "+Str(healthycount), GREEN,, PSet
	Draw String backbuffer, (0, 9), "Infected: "+Str(infectedcount), RED,, PSet
	Draw String backbuffer, (0, 19), "Immuned:  "+Str(immunedcount), YELLOW,, PSet
	Draw String backbuffer, (0, 29), "Dead:     "+Str(deadcount), GREY,, PSet
	Draw String backbuffer, (SCREENX-180,0), "Shelter-In-Place: "+Str(SHELTERINPLACE*100)+"%", GREY,, PSet
	Draw String backbuffer, (SCREENX-180,9), "Death Rate: "+Str(DEATHRATE*100)+"%", GREY,, PSet
	ScreenLock
	Put (0,0),backbuffer,PSet
	ScreenUnLock
	Sleep 1
Loop Until InKey <> ""
ImageDestroy(backbuffer)
ImageDestroy(mapbuffer)
Delete [] p
Last edited by ShawnLG on Apr 14, 2020 16:24, edited 2 times in total.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Corona virus simulator

Post by jj2007 »

Very cute, thumbs up!
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Corona virus simulator

Post by srvaldez »

see https://www.washingtonpost.com/graphics ... simulator/
Richard Russel author of bbc Basic wrote a nice version in bbc Basic, but their Forum is down so I can't post a link
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: Corona virus simulator

Post by deltarho[1859] »

Without Randomize: 166 dead

Five runs with Randomize: 196, 150, 151, 174, 184 dead

With Randomize and many more runs will give us a potential upper bound on deaths; that is a worst-case scenario.

With more than 30 runs we can then use the normal distribution to calculate confidence limits on the expected number of deaths.
grindstone
Posts: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: Corona virus simulator

Post by grindstone »

Nice work!
bluatigro
Posts: 660
Joined: Apr 25, 2012 10:35
Location: netherlands

Re: Corona virus simulator

Post by bluatigro »

look also to my version :
'virus outbreak sim'
UEZ
Posts: 972
Joined: May 05, 2017 19:59
Location: Germany

Re: Corona virus simulator

Post by UEZ »

@ShawnLG: well done but the move of the pixels are too turbulent imho...

Here my contribution as I don't want to create another topic:

Code: Select all

'Coded by UEZ build 2020-04-02
#include "string.bi"

#Define _Dist(x1, x2, y1, y2)	(((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1)))
#Define _Round(x)    			((x + 0.5) Shr 0)
#Define Ceiling(x)				(-((-(x) * 2.0 - 0.5) Shr 1))
#Define Map(a, b, c)			(a / b * c)

Const iW = 1024, iH = 768, iPeople = 19999, iPSize = 1, iMaxSickDays = 14, fDaySpeed = 0.0075, iDayInoFound = 60, probDeath = 0.05, infProb = 0.25, gH = 100

Type vZone
	Dim As Ushort x1, y1, x2, y2
	Dim As Uinteger pp(iPeople + 1) 'index of people
	Dim As Ulong c
End Type

Declare Sub Motion()
Declare Function RandomRange(fStart As Single, fEnd As Single) As Single
Declare Sub CreateGridZones(Zones() As vZone, iZones As Ushort, imgw As Ushort, imgh As Ushort)

Const As ULong  iBGColor = &hFF000000

ScreenRes iW, iH, 32, 2, 100
ScreenSet 1, 0

Dim Shared As Any Ptr img, img_clr
img = Imagecreate(iW, iH, &hFF404040, 32)
img_clr = Imagecreate(iW, iH - gH, iBGColor, 32)

Randomize , 2

Dim Shared As Uinteger iPSize2, iPrevDaysPassed = 0
iPSize2 = iPSize^2
Dim Shared As Single fDaysPassed = 0
Type vPeople
	Dim As Single x, y, vx, vy, sickdays, healthydays
	Dim As Ulong c
	Dim As Ubyte status, zone 'status: healthy = 0, infected = 1, cured = 2, dead = 3, inoculated = 4
End Type

Dim Shared As Ushort p0, iGridZones = 12^2
Dim Shared As vZone GridZone(iGridZones)
Dim As Uinteger i, j

CreateGridZones(GridZone(), iGridZones, iW, iH - gH)

iGridZones -= 1
For j = 0 To iGridZones 'create color for each grid zone for debugging purpose
	GridZone(j).c = &h80000000 Or Culng(Rnd() * &hFFFFFF)
Next
	
Dim Shared As vPeople People(iPeople)
For i = 0 To iPeople
	People(i).x = RandomRange(iPSize + 1, iW - iPSize - 1)
	People(i).y = RandomRange(iPSize + 1, iH - iPSize - gH - 1)
	People(i).c = &hFFFFFFFF
	People(i).vx = 0.15 * Rnd() - 0.075
	People(i).vy = 0.15 * Rnd() - 0.075
	People(i).status = 0
	People(i).sickdays = 0
	People(i).healthydays = 0
Next
p0 = Cuint(Rnd * iPeople) 'gunman aka patient zero
People(p0).c = &hFFFF0000
People(p0).status = 1
'People(p0).vx *= 5
'People(p0).vy *= 4

Dim As Ulong iFPS = 0, iFPS_current = 0
Dim As Double fTimer = Timer

Do
	Put img, (0, 0), img_clr, Pset
	Motion()
	Put (0, 0), img, Pset
	Draw String(1, 1), iFPS_current & " fps", Rgba(&hF0, &hF0, &h10, &hFF)
	Flip
	fDaysPassed += fDaySpeed
	If Timer - fTimer > 0.99 Then
		iFPS_current = iFPS
		iFPS = 0
		fTimer = Timer
	Else
		iFPS += 1
	End If
    Sleep 1, 1
Loop Until Len(InKey())

Imagedestroy(img_clr)
Imagedestroy(img)

Sub Motion()
	Dim As Uinteger i, j, k, l, iBucket, index, iHealthy = 0, iInfected = 0, iCured = 0, iDead = 0, iInoculated = 0
	Static As Single cr = 0
	Dim As Single t1, t2
	For j = 0 To iGridZones 'reset amount if people in the bucket
		GridZone(j).pp(0) = 0
		'Line img, (GridZone(j).x1, GridZone(j).y1)-(GridZone(j).x2, GridZone(j).y2), GridZone(j).c, BF 'display GridZone for debugging
	Next
	For i = 0 To iPeople
		'move each people if not dead
		If People(i).status <> 3 Then 'skip dead people
			People(i).x += People(i).vx 
			People(i).y += People(i).vy
		End If
		'check border collision
		If People(i).x < 0 Or People(i).x > iW - iPSize - 1 Then People(i).vx *= -1
		If People(i).y < 0 Or People(i).y > iH - iPSize - gh - 1 Then People(i).vy *= -1
		'group people into GridZone for more efficient collision check afterwards
		For j = 0 To iGridZones
			If People(i).x > GridZone(j).x1 And People(i).x < GridZone(j).x2 - iPSize And People(i).y > GridZone(j).y1 And People(i).y < GridZone(j).y2 - iPSize Then
				GridZone(j).pp(0) += 1
				GridZone(j).pp(GridZone(j).pp(0)) = i
				'People(i).c = GridZone(j).c
				People(i).zone = j
				Exit For
			End If
		Next
		
		If fDaysPassed > 7 And People(i).status = 0 And Rnd() < 0.000000075 Then
			If People(i).status = 0 Then People(i).status = 1 'make random people sick. People came back from infected country
		End If
		
		If People(i).status = 0 Then People(i).healthydays += fDaySpeed
		
		If People(i).healthydays > iDayInoFound And People(i).status = 0 Then 'immunisation has been found -> inoculation started
			If Rnd() < 0.0015 Then People(i).status = 4 'add a delay as not each people will be incoculated at the same time
		End If
		
		If People(i).sickdays > iMaxSickDays Then
			People(i).sickdays = 0
			If Rnd() < probDeath Then 'probability of death at 5%
				People(i).status = 3
				People(i).vx = 0
				People(i).vy = 0
			Else 'cured
				People(i).status = 2
			End If
		End If
		
		Select Case People(i).status
			Case 0
				iHealthy += 1
			Case 1
				People(i).sickdays += fDaySpeed
				iInfected += 1
				If i = p0 Then	'show patient zero with a circle during infection phase and color flash
					People(p0).c = &hFF000000 Or (cr Shl 16)
					cr += 10
					t1 = iPSize / 2
					'Circle img, (People(i).x + t1, People(i).y + t1), 2 * iPSize, &hFFC0C000
				Else
					People(i).c = &hFFF00000
				End If
			Case 2
				iCured += 1
				People(i).c = &hFF00F000
			Case 3
				iDead += 1
				People(i).c = &hFFE238EC
			Case 4
				iInoculated += 1
				People(i).c = &hFF2020FF
		End Select

		Line img, (People(i).x, People(i).y)-(People(i).x + iPSize, People(i).y + iPSize), People(i).c, BF
	Next
	
	'collision check of infected peoples
	For i = 0 To iPeople		
		If People(i).status = 1 Then 'don't check dead and healty peoples		
			iBucket = GridZone(People(i).zone).pp(0)
			For j = 1 To iBucket
				index = GridZone(People(i).zone).pp(j)
				If People(index).status = 0 And index <> i Then
					If Int(_Dist(People(i).x, People(index).x, People(i).y, People(index).y)) <= iPSize2 And Rnd() > infProb Then 'infect people by 75% probability
						People(index).status = 1
						
						'increase the speed of infection
						'People(index).vx *= -1
						'People(index).vy *= -1
						
						'decrease the speed of infection -> infected people will move reverse direction on infection
						'People(i).vx *= -1
						'People(i).vy *= -1
					End If
				End If
			Next
		End If
	Next
	Dim As Ushort iSum = iHealthy + iCured + iInoculated
	Windowtitle("Corona Infection Simulation by UEZ / h: " & iSum & ", inf: " & iInfected & Format(iInfected / (iPeople - iDead), " (0.00%)") & _
				", c: " & iCured & ", d: " & iDead & Format(iDead / (iPeople + 1), " (0.00%)") & _
				", ino: " & iInoculated & ", day: " & Format(fDaysPassed, "#"))
				
	Static As Single posx = 0
	If posx <= iW Then
		If Cushort(fDaysPassed) Mod 7 = 0 And fDaysPassed > 1 And iPrevDaysPassed < Cushort(fDaysPassed) Then 
			Line img, (posx, iH - gH)-(posx, iH), &hFF000000
			iPrevDaysPassed = fDaysPassed
			'posx += 1
		Else
			t2 = gH / (iPeople + 1)
			Line img, (posx, iH)-(posx, iH - (iHealthy * t2)), &h40FFFFFF
			Line img, (posx, iH)-(posx, iH - (iInfected * t2)), &h40FF0000
			If iDead Then Line img, (posx, iH)-(posx, iH - (iDead * t2)), &hF0E238EC
			If iCured Then Line img, (posx, iH - gH)-(posx, iH - gH + (iCured * t2)), &h4000F000
			If iInoculated Then Line img, (posx, iH - gH)-(posx, iH - gH + (iInoculated * t2)), &hF02020FF
		End If
		posx += fDaySpeed * 10
	End If
End Sub

'Original code by Neptilo @ https://math.stackexchange.com/questions/466198/algorithm-to-get-the-maximum-size-of-n-squares-that-fit-into-a-rectangle-with-a
'Modified by UEZ
Sub CreateGridZones(Zones() As vZone, iZones As Ushort, imgw As Ushort, imgh As Ushort)
	Dim As Single ratio = Iif(Frac(Sqr(iZones)) = 0, 1, Iif(imgw >= imgh, imgw / imgh, imgh / imgw))
	Dim As Single ncols_float = Sqr(iZones * ratio), nrows_float = iZones / ncols_float
	
	'Find best option filling the whole height
	Dim As Uinteger nrows1 = Ceiling(nrows_float), ncols1 = Ceiling(iZones / nrows1)
	While nrows1 * ratio < ncols1
		nrows1 += 1
		ncols1 = Ceiling(iZones / nrows1)
	Wend
	Dim As Single cell_size1 = imgh / nrows1
	
	'Find best option filling the whole width
	Dim As Uinteger ncols2 = Ceiling(ncols_float), nrows2 = Ceiling(iZones / ncols2)
	While ncols2 < nrows2 * ratio
		ncols2 += 1
		nrows2 = Ceiling(iZones / ncols2)
	Wend
	Dim As Single cell_size2 = imgw / ncols2

	'Find the best values
	Dim As Uinteger nrows, ncols
	If cell_size1 < cell_size2 Then
		nrows = nrows1
		ncols = ncols1
	Else
		nrows = nrows2
		ncols = ncols2
	End If
	
	Dim As Uinteger i,j, k, x, y
	Dim As Integer dz = iZones - (nrows * ncols), bz = Iif(dz <> 0, 1, 0)
	Dim As Single dx = imgw / ncols, dy = imgh / nrows
	
	For j = 0 To nrows - 1 - bz
		For i = 0 To ncols - 1
			x = Cuint(i * dx)
			Zones(k).x1 = x
			Zones(k).x2 = x + dx
			Zones(k).y1 = (j Mod nrows) * dy
			Zones(k).y2 = Zones(k).y1 + dy
			k += 1
		Next
	Next
	
	If bz Then
		ncols = iZones - k
		dx = imgw / ncols
		For i = 0 To ncols - 1
			x = Cuint(i * dx)
			Zones(k).x1 = x
			Zones(k).x2 = x + dx
			Zones(k).y1 = (j Mod nrows) * dy
			Zones(k).y2 = Zones(k).y1 + dy
			k += 1
		Next
	End If
End Sub


Function RandomRange(fStart As Single, fEnd As Single) As Single
   Return Rnd() * (fEnd - fStart) + fStart
End Function
Runs fasted on my system when using -gen gcc -O 3 -s gui in x64 mode.

White: normal healthy
Red: infected
Green: cured
Purple: dead
Blue: inoculated

Image

Edit1: added inoculation
Edit2: small code optimizations (thanks badidea for the suggestions)
Edit3: small code optimizations (thanks badidea for the suggestions)
Edit4: increased zone size -> now much better performance. Be careful when changing the amount of zones!
Edit5: added random source of infection to simulate people travel and some other things
Edit6: added a graph at the bottom
Last edited by UEZ on Apr 02, 2020 7:14, edited 12 times in total.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Corona virus simulator

Post by badidea »

UEZ wrote:@ShawnLG: well done but the move of the pixels are too turbulent imho...
No 'Herd immunity' 100% infection rate.
UEZ
Posts: 972
Joined: May 05, 2017 19:59
Location: Germany

Re: Corona virus simulator

Post by UEZ »

badidea wrote:
UEZ wrote:@ShawnLG: well done but the move of the pixels are too turbulent imho...
No 'Herd immunity' 100% infection rate.
Currently no immunization has been found...^^
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Corona virus simulator

Post by badidea »

UEZ wrote:
badidea wrote:No 'Herd immunity' 100% infection rate.
Currently no immunization has been found...^^
I think your "R0 (basic reproduction number)" is too high (https://en.wikipedia.org/wiki/Herd_immunity). For the corona-virus R0 is not known very accurate yet (see table). With these 'social distancing' why try to bring this number below 1 (for now).
How many others does one ill person infect (on average) in the beginning of your simulation?
This 'gunman' infects hundreds when he gets a large speed. Looks like a zombie apocalypse.

Concerning code this:
If Particles(index).status <> 1 And Particles(index).status <> 2 And Particles(index).status <> 3 And index <> i Then
Can be:
If Particles(index).status = 0 And index <> i Then
I think?

And I would use an enum:
enum E_STATUS
ST_INIT '0
ST_INFEC '1
ST_CURED '2
ST_DEAD '3
end enum

And I think that fPSizeHalf can be left out in:
If Int(_Dist(Particles(i).x + fPSizeHalf, Particles(index).x + fPSizeHalf, _
Particles(i).y + fPSizeHalf, Particles(index).y + fPSizeHalf)) <= iPSize Then
Because Dist_() does (x2 - x1) and (y2 - y1) so fPSizeHalf disappears.

To further speed-up the simulation, Sqr() is not needed, you can compared against iPSize ^ 2, which is a constant (9).

To make it more realistic, one could reduce the speed of the infected, e.g. by half. And hope that they don't get on to an air-plane to the other side of the map.

With this modified code, you see that some never get infected:

Code: Select all

'Coded by UEZ build 2020-03-25 (modified by badidea)
#include "string.bi"

'#Define _Dist(x1, x2, y1, y2)   (Sqr((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1)))
#Define _DistSq(x1, x2, y1, y2)   ((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1))

Declare Sub Motion()
Declare Function RandomRange(fStart As Single, fEnd As Single) As Single

Const As UShort iW = 1024, iH = 768
Const As ULong  iBGColor = &hFF000000

ScreenRes iW, iH, 32, 2
ScreenSet 1, 0

Dim Shared As Any Ptr img, img_clr
img = Imagecreate(iW, iH, 0, 32)
img_clr = Imagecreate(iW, iH, iBGColor, 32)

Randomize , 2

const As Uinteger iParticles = 4999, iPSize = 3
const As Single fPSizeHalf = iPSize / 2
const as single minInfecDist = iPSize * iPSize

enum E_STATUS
	ST_INIT
	ST_INFEC
	ST_CURED
	ST_DEAD
end enum

Type vParticle
   Dim As Single x, y, vx, vy, days
   Dim As Ulong c
   Dim As Ubyte status, zone 'status: alife = 0, infected = 1, cured = 2, dead = 3
End Type

Type vZone
   Dim As Ushort x1, y1, x2, y2
   Dim As Uinteger pp(5000) 'index of particle
   Dim As Ulong c
End Type

Dim Shared As vZone Zones(3)
Dim As Uinteger i, j

'left upper
Zones(0).x1 = 0
Zones(0).y1 = 0
Zones(0).x2 = iW / 2
Zones(0).y2 = iH / 2
Zones(0).pp(0) = 0
Zones(0).c = &hFFFF8080

'right upper
Zones(1).x1 = iW / 2
Zones(1).y1 = 0
Zones(1).x2 = iW
Zones(1).y2 = iH / 2
Zones(1).pp(0) = 0
Zones(1).c = &hFF80FF80

'left bottom
Zones(2).x1 = 0
Zones(2).y1 = iH / 2
Zones(2).x2 = iW / 2
Zones(2).y2 = iH
Zones(2).pp(0) = 0
Zones(2).c = &hFF8080FF

'right bottom
Zones(3).x1 = iW / 2
Zones(3).y1 = iH / 2
Zones(3).x2 = iW
Zones(3).y2 = iH
Zones(3).pp(0) = 0
Zones(3).c = &hFFFFFFFF

Dim Shared As vParticle Particles(iParticles)
For i = 0 To iParticles
   Particles(i).x = RandomRange(iPSize + 1, iW - iPSize - 1)
   Particles(i).y = RandomRange(iPSize + 1, iH - iPSize - 1)
   Particles(i).c = &hFFFFFFFF
   Particles(i).vx = 0.5 * Rnd() - 0.25
   Particles(i).vy = 0.5 * Rnd() - 0.25
   Particles(i).status = ST_INIT
   Particles(i).days = 0
Next
i = Cuint(Rnd * iParticles) 'gunman
Particles(i).c = &hFFFF0000
Particles(i).status = ST_INFEC
Particles(i).vx *= 0.5 '5 
Particles(i).vy *= 0.4 '4

Dim As Ulong iFPS = 0, iFPS_current = 0
Dim As Double fTimer = Timer

Do
   Put img, (0, 0), img_clr, Pset
   Motion()
   Put (0, 0), img, Pset
   Draw String(1, 1), iFPS_current & " fps", Rgba(&hF0, &hF0, &h10, &hFF)
   Flip
   If Timer - fTimer > 0.99 Then
      iFPS_current = iFPS
      iFPS = 0
      fTimer = Timer
   Else
      iFPS += 1
   End If
    Sleep 1, 1
Loop Until Len(InKey())

Imagedestroy(img_clr)
Imagedestroy(img)

Sub Motion()
   Dim As Uinteger i, j, k, l, iBucket, index, iAlive = 0, iInfected = 0, iCured = 0, iDead = 0
   For j = 0 To 3 'reset amount if pixel in the bucket
      Zones(j).pp(0) = 0
   Next
   For i = 0 To iParticles
      'move each pixel if not dead
      If Particles(i).status <> ST_DEAD Then
         Particles(i).x += Particles(i).vx
         Particles(i).y += Particles(i).vy
      End If
      'check border collision
      If Particles(i).x < 0 Or Particles(i).x > iW - iPSize - 1 Then Particles(i).vx *= -1
      If Particles(i).y < 0 Or Particles(i).y > iH - iPSize - 1 Then Particles(i).vy *= -1
      'group pixel into zones for collision check afterwards
      For j = 0 To 3
         If Particles(i).x > Zones(j).x1 And Particles(i).x < Zones(j).x2 - iPSize And Particles(i).y > Zones(j).y1 And Particles(i).y < Zones(j).y2 - iPSize Then
            Zones(j).pp(0) += 1
            Zones(j).pp(Zones(j).pp(0)) = i
            'Particles(i).c = Zones(j).c
            Particles(i).zone = j
            Exit For
         End If
      Next
      
      If Particles(i).days > 14 Then
         Particles(i).days = 0
         If Rnd() < 0.05 Then 'dead
            Particles(i).status = ST_DEAD
            Particles(i).vx = 0
            Particles(i).vy = 0
         Else 'cured
            Particles(i).status = ST_CURED
            'back to normal speed
            Particles(i).vx *= 2
            Particles(i).vy *= 2
         End If
      End If
      Select Case Particles(i).status
         Case ST_INIT
            iAlive += 1
            Particles(i).c = &hFFFFFFFF
         Case ST_INFEC
            Particles(i).days += 0.0075
            iInfected += 1
            Particles(i).c = &hFFF00000
         Case ST_CURED
            iCured += 1
            Particles(i).c = &hFF00F000
         Case ST_DEAD
            iDead += 1
            Particles(i).c = &hFFE238EC
      End Select
      Line img, (Particles(i).x, Particles(i).y)-(Particles(i).x + iPSize, Particles(i).y + iPSize), Particles(i).c, BF
   Next
   'collision check of infected pixels
   For i = 0 To iParticles      
      If Particles(i).status = ST_INFEC Then       
         If Particles(i).status <> ST_DEAD Then
            iBucket = Zones(Particles(i).zone).pp(0)
            For j = 1 To iBucket
               index = Zones(Particles(i).zone).pp(j)
               If Particles(index).status = ST_INIT And index <> i Then
                  If Int(_DistSq(Particles(i).x, Particles(index).x, Particles(i).y, Particles(index).y)) <= minInfecDist Then
                     Particles(index).status = ST_INFEC
                     Particles(index).vx *= 0.5
                     Particles(index).vy *= 0.5
                  End If
               End If
            Next
         End If
      End If
   Next
   Windowtitle("Corona Infection Simulation / alive: " & 1 + iParticles - iDead & ", infected: " & iInfected & ", cured: " & iCured & ", dead: " & iDead & Format(iDead / (iParticles + 1), " (0.00%)"))
End Sub

Function RandomRange(fStart As Single, fEnd As Single) As Single
   Return Rnd() * (fEnd - fStart) + fStart
End Function
Edit: ST_ALIVE changed to ST_INIT
Last edited by badidea on Mar 25, 2020 22:04, edited 2 times in total.
UEZ
Posts: 972
Joined: May 05, 2017 19:59
Location: Germany

Re: Corona virus simulator

Post by UEZ »

@badidead: thanks for having a closer look to the code.

Some of your code suggestions I had already made. But to avoid Sqr was a good hint.

Well, my target was not create a realistic simulation with all possibilities and parameters because I don't have deep knowledge about the science behind. This is more a pseudo simulation to see some pixels moving around.
I added extra the "gunman" to spread the virus faster to the public...^^

Btw, I've updated the code above.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Corona virus simulator

Post by badidea »

UEZ wrote:Btw, I've updated the code above.
One more thing, you have:

Code: Select all

  If Particles(i).status = 1 Then       
         If Particles(i).status <> 3 And Particles(i).status <> 4 Then 'don't check dead and healty pixels
But status the status is 0,1,2, or 3
So this can be reduced to just:

Code: Select all

  If Particles(i).status = 1 Then
I think?

What does alive mean in your code? This alive include infected and cured?
UEZ
Posts: 972
Joined: May 05, 2017 19:59
Location: Germany

Re: Corona virus simulator

Post by UEZ »

badidea wrote:
UEZ wrote:Btw, I've updated the code above.
One more thing, you have:

Code: Select all

  If Particles(i).status = 1 Then       
         If Particles(i).status <> 3 And Particles(i).status <> 4 Then 'don't check dead and healty pixels
But status the status is 0,1,2, or 3
So this can be reduced to just:

Code: Select all

  If Particles(i).status = 1 Then
I think?

What does alive mean in your code? This alive include infected and cured?
Thanks - your are right - fixed the part with unneeded checks.

Alive means not dead.^^ The pixel is infected (red) but still alive and with a probability of 5% the pixel will die. Alive = infected (not dead) + cured / inoculated.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Corona virus simulator

Post by badidea »

UEZ wrote:Alive means not dead.^^ The pixel is infected (red) but still alive and with a probability of 5% the pixel will die. Alive = infected (not dead) + cured / inoculated.
But this comment is confusing:
Dim As Ubyte status, zone 'status: alive = 0, infected = 1, cured = 2, dead = 3, inoculated = 4
On infection you switch form 0 to 1. So 0 must mean 'initial' or something I think.

To my 'forked' version, I added a 'day counter' and a 'infected by gunman (patient 0)' counter.
With patient 0 at the same speed as the others, he infects 10 to 25 others (depending on his actual speed and start position).

Code: Select all

dim shared as integer iGunMan, infectedbyGunMan = 0

'Coded by UEZ build 2020-03-25 (modified by badidea)
#include "string.bi"

'#Define _Dist(x1, x2, y1, y2)   (Sqr((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1)))
#Define _DistSq(x1, x2, y1, y2)   ((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1))

Declare Sub Motion()
Declare Function RandomRange(fStart As Single, fEnd As Single) As Single

Const As UShort iW = 1024, iH = 768
Const As ULong  iBGColor = &hFF000000

ScreenRes iW, iH, 32, 2
width iW \ 8, iH \ 16
ScreenSet 1, 0

Dim Shared As Any Ptr img, img_clr
img = Imagecreate(iW, iH, 0, 32)
img_clr = Imagecreate(iW, iH, iBGColor, 32)

Randomize , 2

const As Uinteger iParticles = 4999, iPSize = 3
const As Single fPSizeHalf = iPSize / 2
const as single minInfecDist = iPSize * iPSize

enum E_STATUS
	ST_INIT
	ST_INFEC
	ST_CURED
	ST_DEAD
end enum

Type vParticle
   Dim As Single x, y, vx, vy, days
   Dim As Ulong c
   Dim As Ubyte status, zone 'status: alife = 0, infected = 1, cured = 2, dead = 3
End Type

Type vZone
   Dim As Ushort x1, y1, x2, y2
   Dim As Uinteger pp(5000) 'index of particle
   Dim As Ulong c
End Type

Dim Shared As vZone Zones(3)
Dim As Uinteger i, j

'left upper
Zones(0).x1 = 0
Zones(0).y1 = 0
Zones(0).x2 = iW / 2
Zones(0).y2 = iH / 2
Zones(0).pp(0) = 0
Zones(0).c = &hFFFF8080

'right upper
Zones(1).x1 = iW / 2
Zones(1).y1 = 0
Zones(1).x2 = iW
Zones(1).y2 = iH / 2
Zones(1).pp(0) = 0
Zones(1).c = &hFF80FF80

'left bottom
Zones(2).x1 = 0
Zones(2).y1 = iH / 2
Zones(2).x2 = iW / 2
Zones(2).y2 = iH
Zones(2).pp(0) = 0
Zones(2).c = &hFF8080FF

'right bottom
Zones(3).x1 = iW / 2
Zones(3).y1 = iH / 2
Zones(3).x2 = iW
Zones(3).y2 = iH
Zones(3).pp(0) = 0
Zones(3).c = &hFFFFFFFF

Dim Shared As vParticle Particles(iParticles)
For i = 0 To iParticles
   Particles(i).x = RandomRange(iPSize + 1, iW - iPSize - 1)
   Particles(i).y = RandomRange(iPSize + 1, iH - iPSize - 1)
   Particles(i).c = &hFFFFFFFF
   Particles(i).vx = 0.5 * Rnd() - 0.25
   Particles(i).vy = 0.5 * Rnd() - 0.25
   Particles(i).status = ST_INIT
   Particles(i).days = 0
Next
i = Cuint(Rnd * iParticles) 'gunman (patient 0)
Particles(i).c = &hFFFF0000
Particles(i).status = ST_INFEC
'Particles(i).vx *= 5 
'Particles(i).vy *= 4
iGunMan = i

Dim As Ulong iFPS = 0, iFPS_current = 0
Dim As Double fTimer = Timer
dim as single simDays = 0

Do
   Put img, (0, 0), img_clr, Pset
   Motion()
   Put (0, 0), img, Pset
   Draw String(1, 1), iFPS_current & " fps", Rgba(&hF0, &hF0, &h10, &hFF)
   Draw String(1, 1 + 16), "simDays: " & int(simDays), Rgba(&hF0, &hF0, &h10, &hFF)
   Draw String(1, 1 + 32), "Infected by gunman: " & infectedbyGunMan , Rgba(&hF0, &hF0, &h10, &hFF)
   Flip
   If Timer - fTimer > 0.99 Then
      iFPS_current = iFPS
      iFPS = 0
      fTimer = Timer
   Else
      iFPS += 1
   End If
   simDays += 0.0075
    Sleep 1, 1
Loop Until Len(InKey())

Imagedestroy(img_clr)
Imagedestroy(img)

Sub Motion()
   Dim As Uinteger i, j, k, l, iBucket, index, iAlive = 0, iInfected = 0, iCured = 0, iDead = 0
   For j = 0 To 3 'reset amount if pixel in the bucket
      Zones(j).pp(0) = 0
   Next
   For i = 0 To iParticles
      'move each pixel if not dead
      If Particles(i).status <> ST_DEAD Then
         Particles(i).x += Particles(i).vx
         Particles(i).y += Particles(i).vy
      End If
      'check border collision
      If Particles(i).x < 0 Or Particles(i).x > iW - iPSize - 1 Then Particles(i).vx *= -1
      If Particles(i).y < 0 Or Particles(i).y > iH - iPSize - 1 Then Particles(i).vy *= -1
      'group pixel into zones for collision check afterwards
      For j = 0 To 3
         If Particles(i).x > Zones(j).x1 And Particles(i).x < Zones(j).x2 - iPSize And Particles(i).y > Zones(j).y1 And Particles(i).y < Zones(j).y2 - iPSize Then
            Zones(j).pp(0) += 1
            Zones(j).pp(Zones(j).pp(0)) = i
            'Particles(i).c = Zones(j).c
            Particles(i).zone = j
            Exit For
         End If
      Next
      
      If Particles(i).days > 14 Then
         Particles(i).days = 0
         If Rnd() < 0.05 Then 'dead
            Particles(i).status = ST_DEAD
            Particles(i).vx = 0
            Particles(i).vy = 0
         Else 'cured
            Particles(i).status = ST_CURED
            'back to normal speed
            Particles(i).vx *= 2
            Particles(i).vy *= 2
         End If
      End If
      Select Case Particles(i).status
         Case ST_INIT
            iAlive += 1
            Particles(i).c = &hFFFFFFFF
         Case ST_INFEC
            Particles(i).days += 0.0075
            iInfected += 1
            Particles(i).c = &hFFF00000
         Case ST_CURED
            iCured += 1
            Particles(i).c = &hFF00F000
         Case ST_DEAD
            iDead += 1
            Particles(i).c = &hFFE238EC
      End Select
      Line img, (Particles(i).x, Particles(i).y)-(Particles(i).x + iPSize, Particles(i).y + iPSize), Particles(i).c, BF
   Next
   'collision check of infected pixels
   For i = 0 To iParticles
      If Particles(i).status = ST_INFEC Then       
            iBucket = Zones(Particles(i).zone).pp(0)
            For j = 1 To iBucket
               index = Zones(Particles(i).zone).pp(j)
               If Particles(index).status = ST_INIT And index <> i Then
                  '(i) infects (index)?
                  If Int(_DistSq(Particles(i).x, Particles(index).x, Particles(i).y, Particles(index).y)) <= minInfecDist Then
                     Particles(index).status = ST_INFEC
                     Particles(index).vx *= 0.5
                     Particles(index).vy *= 0.5
                     if i = iGunMan then infectedbyGunMan += 1
                  End If
               End If
            Next
      End If
   Next
   Windowtitle("Corona Infection Simulation / alive: " & 1 + iParticles - iDead & ", infected: " & iInfected & ", cured: " & iCured & ", dead: " & iDead & Format(iDead / (iParticles + 1), " (0.00%)"))
End Sub

Function RandomRange(fStart As Single, fEnd As Single) As Single
   Return Rnd() * (fEnd - fStart) + fStart
End Function
Another speed optimisation is to set an end-of-sickness-date, and compare against that. So that you don't have to do Particles(i).days += 0.0075 for all infected every loop. This part could even be done 1 once every 10 loops. Currently, in simulated time, it correspond to a heath check every ~10 minutes.
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Corona virus simulator

Post by dodicat »

Not so much a simulation but a message.

Code: Select all

Redim As Long t()
Dim As Long x
Do
    x+=1
    Redim Preserve t(1 To x)
    Read t(x)
Loop Until t(x)=-1
Redim Preserve t(1 To Ubound(t)-1)

Type pt
    As Long x,y
    As Ulong col
    As Long idx,done
    #define range(f,l) Int(Rnd*((l+1)-(f)))+(f)
End Type

Function dist(p1 As pt,p2 As pt) As Long
    Return ( (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y))
End Function

Function closest(pts() As pt,p As pt) Byref As Long
    Dim As Long dt=1000000,distance
    Static As Long res
    For n As Long=Lbound(pts) To Ubound(pts)
        If pts(n).idx=p.idx Or pts(n).done=1 Then Goto nxt
        distance=dist(pts(n),p)
        If dt> distance Then dt = distance:res=n
        nxt:
    Next n
    Return (res)
End Function

Sub shuffle(a() As pt)
    For n As Integer = Lbound(a) To Ubound(a)-1
        Swap a(n), a(range(n,Ubound(a)))
    Next n
End Sub

Dim As Integer w,h
Screen 20,32
Screeninfo w,h
Redim As pt c()
Dim As Long ctr
For x As Long=1 To w-2 Step 8
    For y As Long=1 To h-2 Step 8
        ctr+=1
        Redim Preserve c(1 To ctr)
        c(ctr)=Type(x,y,Rgb(0,200,0),ctr)
    Next y
Next x
For n As Long=Lbound(t) To Ubound(t)
    c(t(n)).done=1
Next
shuffle(c())
Dim As pt s=Type(range(1,(w-1)),range(1,(h-1)))
Dim As Long z =range(1,Ubound(c))
Dim As pt p=c(z)
Dim As Long cl,counter

Do
    counter+=1
    cl=closest(c(),p)
    p=c(cl)
    If c(cl).done=0 Then c(cl).col=Rgb(200,0,0)
    c(cl).done=1
    Screenlock
    Cls
    For n As Long=Lbound(c) To Ubound(c)
        Line(c(n).x-2,c(n).y-2)-(c(n).x+2,c(n).y+2),c(n).col,bf
    Next
    
    Screenunlock
    Sleep 1
Loop Until counter>ubound(c)
windowtitle "DONE . . ."
Sleep


Data _
523, 524, 525, 526, 527, 535, 536, 537, 538, 539, 540, 541, 542, 618, 619, _
620, 621, 622, 623, 624, 634, 635, 636, 637, 713, 714, 715, 717, 718, 719, _
720, 721, 732, 733, 808, 809, 815, 816, 817, 818, 829, 904, 911, 912, 913, _
914, 925, 1000, 1008, 1009, 1010, 1011, 1021, 1022, 1096, 1105, 1106, 1107, 1108, 1118, _
1192, 1201, 1202, 1203, 1204, 1214, 1288, 1298, 1299, 1300, 1301, 1310, 1384, 1385, 1394, _
1395, 1396, 1397, 1405, 1406, 1481, 1491, 1492, 1493, 1494, 1501, 1577, 1578, 1579, 1588, _
1589, 1590, 1591, 1592, 1595, 1596, 1597, 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1684, _
1685, 1686, 1687, 1688, 1689, 1690, 1691, 1692, 1781, 1782, 1783, 1784, 1785, 1786, 1787, _
1880, 1881, 2159, 2254, 2255, 2349, 2350, 2351, 2352, 2353, 2354, 2355, 2356, 2357, 2358, _
2359, 2360, 2361, 2362, 2363, 2364, 2365, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2451, _
2452, 2453, 2454, 2455, 2456, 2457, 2458, 2459, 2460, 2461, 2538, 2539, 2540, 2541, 2542, _
2543, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, _
2558, 2639, 2653, 2654, 2735, 2749, 2831, 2844, 2939, 3122, 3123, 3128, 3129, 3130, 3131, _
3132, 3216, 3217, 3218, 3219, 3223, 3224, 3225, 3226, 3227, 3228, 3229, 3312, 3313, 3314, _
3315, 3319, 3320, 3323, 3324, 3325, 3326, 3407, 3408, 3414, 3415, 3420, 3421, 3422, 3503, _
3510, 3517, 3599, 3605, 3613, 3695, 3701, 3708, 3791, 3792, 3797, 3803, 3887, 3888, 3889, _
3890, 3891, 3892, 3893, 3894, 3895, 3896, 3897, 3898, 3899, 3900, 3901, 3984, 3985, 3986, _
3987, 3988, 3989, 3990, 3991, 3992, 3993, 3994, 3995, 3996, 3997, 3998, 4082, 4083, 4084, _
4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4189, 4284, 4463, 4483, 4559, 4560, _
4578, 4579, 4580, 4655, 4656, 4657, 4658, 4674, 4675, 4676, 4751, 4752, 4753, 4754, 4755, _
4756, 4770, 4771, 4772, 4847, 4848, 4849, 4850, 4851, 4852, 4853, 4854, 4867, 4868, 4943, _
4947, 4948, 4949, 4950, 4951, 4952, 4962, 4963, 5039, 5045, 5046, 5047, 5048, 5049, 5050, _
5057, 5058, 5143, 5144, 5145, 5146, 5147, 5148, 5150, 5151, 5152, 5153, 5241, 5242, 5243, _
5244, 5245, 5246, 5337, 5338, 5339, 5340, 5431, 5432, 5433, 5519, 5524, 5525, 5526, 5527, _
5615, 5618, 5619, 5620, 5711, 5712, 5713, 5714, 5807, 5808, 5903, 6962, 6963, 6964, 6969, _
6970, 6971, 6972, 6973, 7056, 7057, 7058, 7059, 7060, 7061, 7067, 7068, 7069, 7151, 7152, _
7155, 7156, 7157, 7158, 7164, 7165, 7247, 7252, 7253, 7254, 7261, 7262, 7343, 7349, 7350, _
7351, 7358, 7439, 7445, 7446, 7447, 7448, 7454, 7535, 7542, 7543, 7544, 7549, 7550, 7631, _
7632, 7638, 7639, 7640, 7641, 7645, 7727, 7728, 7729, 7730, 7735, 7736, 7737, 7738, 7739, _
7740, 7741, 7832, 7833, 7834, 7835, 7836, 8210, 8211, 8216, 8217, 8218, 8219, 8220, 8304, _
8305, 8306, 8307, 8311, 8312, 8313, 8314, 8315, 8316, 8317, 8400, 8401, 8402, 8403, 8407, _
8408, 8411, 8412, 8413, 8414, 8495, 8496, 8502, 8503, 8508, 8509, 8510, 8591, 8598, 8605, _
8687, 8693, 8701, 8783, 8789, 8796, 8879, 8880, 8885, 8891, 8975, 8976, 8977, 8978, 8979, _
8980, 8981, 8982, 8983, 8984, 8985, 8986, 8987, 8988, 8989, 9072, 9073, 9074, 9075, 9076, _
9077, 9078, 9079, 9080, 9081, 9082, 9083, 9084, 9085, 9086, 9170, 9171, 9172, 9173, 9174, _
9175, 9176, 9177, 9178, 9179, 9180, 9181, 9277, 9372, 9647, 9743, 9839, 9852, 9853, 9930, _
9931, 9932, 9933, 9934, 9935, 9936, 9937, 9938, 9939, 9940, 9941, 9942, 9943, 9944, 9945, _
9946, 9947, 9948, 9949, 10025, 10026, 10027, 10028, 10029, 10030, 10031, 10032, 10033, 10034, 10035, _
10036, 10037, 10038, 10039, 10040, 10041, 10042, 10043, 10044, 10045, 10120, 10121, 10127, 10140, 10141, _
10223, 10311, 10319, 10407, 10415, 10503, 10504, 10599, 10600, 10601, 10696, 10697, 10698, 10707, 10708, _
10709, 10710, 10711, 10712, 10713, 10714, 10792, 10793, 10794, 10801, 10802, 10803, 10804, 10805, 10806, _
10807, 10808, 10809, 10810, 10811, 10896, 10897, 10900, 10904, 10905, 10906, 10907, 10908, 10992, 10996, _
11002, 11003, 11004, 11005, 11087, 11092, 11099, 11100, 11101, 11183, 11188, 11195, 11196, 11197, 11198, _
11279, 11284, 11292, 11293, 11294, 11375, 11376, 11380, 11388, 11389, 11390, 11471, 11472, 11473, 11476, _
11484, 11485, 11568, 11569, 11570, 11571, 11572, 11580, 11581, 11664, 11665, 11666, 11667, 11668, 11675, _
11676, 11762, 11763, 11764, 11769, 11770,-1 
Post Reply