Kinda works but something is wrong.
Code: Select all
#include "fbgfx.bi"
#include "string.bi"
#if __FB_LANG__ = "fb"
Using FB '' Scan code constants are stored in the FB namespace in lang FB
#endif
#If Defined(__FB_WIN32__) 'windows timers resolution update
Declare Function HighPrecisionClock Lib "winmm" Alias "timeBeginPeriod"(As Ulong=1) As Long
HighPrecisionClock
#EndIf
const graph_scr_x = 1920 'screenres
const graph_scr_y = 1080
const graph_pix_per_vsync = 6 'wrong name for speed of the pipes per frame
const graph_xoffset = 1400 'draw location of neural netwerk
const graph_yoffset = 200
const graph_size = 50 'draw size of neural netwerk
const graph_set_fps = 60
dim as boolean graph_vsync_on
const pipe_with = 100 'with of the moving pipes
const pipe_interval = 100 'next pipe interval frame - pipe_rnd_interval
const pipe_rnd_interval = 40 'decided space betwin pipes
const pipe_max = 19 'max nummer of pipes in screen
const player_count = 199 'nummer of players
const player_size = 20 'display size of player (no collion check for size only center point)
const player_jump_interval = 30 'how many frames pass to flap(jump) again
const pipe_holesize = 0.25 '1 = full screen hole / 0 = no hole
'const gen_threats = 1 'not use now
const gen_size = player_count 'nummer of players(bird) = nummer of neural networks(gen)
const gen_mutate_perc_top = 0.1 'top 0.1= 10% selection to mutate from
const gen_mutate_perc_weight = 0.1 'how many weight are been modified
const gen_mutate_streght_weight = 1 'how mach to to modify the weights
const gen_update_fit_selection_frames = 50 'inteval how many times opdate the fittset brains
const gen_mutate_new = 0.2 'random new chance
const nn_node_in = 6
const nn_node_hidden = 5
const nn_layer_hidden = 1 'nummer of hidden layers (0 = 1)
const nn_node_out = 2
const nn_bias = nn_node_in + (nn_node_hidden * (nn_layer_hidden+1)) + nn_node_out - 1
'pre calculation neural netwerk
const nn_weights_in_hidden = nn_node_in * nn_node_hidden 'connection from in to first hidden layer
const nn_weights_hidden_layer = (nn_node_hidden * nn_node_hidden) * nn_layer_hidden 'hidden layer to layer connecions
const nn_weights_hidden_out = nn_node_hidden * nn_node_out
const nn_weights = nn_weights_in_hidden + nn_weights_hidden_layer + nn_weights_hidden_out -1
const gen_fit_selection_size = (gen_size + 1) * gen_mutate_perc_top
const gen_fit_mutate_size = (nn_weights + 1) * gen_mutate_perc_weight
declare function round(n as single) as string
declare Function Regulate(Byval MyFps As long,Byref fps As long, reset_ as boolean = false) As long
type Neural_network
as single bias(nn_bias)
as single weight(nn_weights)
as short ID
as ulong fitness = 0
as ulong best_fitness = 0
declare constructor
end type
type nn_gen
as Neural_network nn_brain(gen_size)
as ushort nn_fit_selection(gen_fit_selection_size) 'gen pointer array value
as ushort nn_fit_selection_counter = 0
declare sub set_all_random()
declare sub gen_draw_brain(a as ubyte)
declare sub gen_calc_brain(a as ubyte)
declare sub select_fittest()
declare function is_ID_in_selection(s as ushort) as boolean
declare sub mutate(n as ushort)
end type
type bird
as single x, y
as single old_x, old_y
as single vel_y 'vel_x
as single next_top_pipe_height
as single next_bottom_pipe_height
as single next_pipe_distance
as long jump_timeout = 0
as byte state = 1 '0 = ready, -1 = dead, 1 = active
declare sub jump()
declare sub go_left()
declare sub go_right()
declare sub process()
declare sub respawn()
declare constructor
end type
type pipe_hole
as short x
as short old_x
as single top
'as single old_top
as longint active_time = 0
as longint pipe_id
end type
type flappy_game
as pipe_hole pipes(pipe_max)
as longint count_pipe = 0
as double start_time = 0
declare sub draw_pipes()
declare sub process_timers()
declare sub add_pipe()
declare sub remove_pipe()
declare function check_player_collision(p as bird) as boolean
end type
type rnd8_16bit
Union
as ulong in32_rnd
type
as ubyte out8_a
as ubyte out8_b
as ushort out16_c
end type
end Union
declare constructor
declare function give16_rndXrnd() as single '-0.4999 to 0.4999
declare function give16_rnd() as single '0 to 0.9999999
end type
screenres graph_scr_x, graph_scr_y, 32, , 1
Dim stats_image As Any Ptr = ImageCreate( graph_scr_x, graph_scr_y, RGB(0, 64, 128) )
randomize timer,2
dim Shared as short pipe_count = 0
dim shared as longint graph_frame_counter = 1
dim as short stats_buffer(player_count)
dim as short stats_counter = 0
dim as single stats_scale = 0, stats_y_pointer = 0
dim as long fps
randomize timer
dim ai as nn_gen
ai.set_all_random()
start: 'note: ai is not reset
dim as string key
dim as bird player(player_count)
dim game as flappy_game
'game.start_time = 0
graph_frame_counter = 1
game.add_pipe()
player(0).state = 1
graph_vsync_on = true
for tmp as ushort = 0 to 199
graph_frame_counter += 1
game.process_timers()
next
do
dim as short stats_buffer(player_count)
stats_counter = 0
for i as ushort = 0 to gen_size
if player(i).state >= 0 then
stats_counter += 1
stats_buffer(ai.nn_brain(i).ID) += 1
end if
next i
if graph_vsync_on or (graph_frame_counter mod 30 ) = 0 then
if stats_counter > 0 then
stats_scale = (graph_scr_y - 1) / (stats_counter)
stats_y_pointer = 0
line stats_image, (graph_scr_x - 1, 0)-(graph_scr_x - 1, graph_scr_y-1),&h000000
for i as ushort = 0 to gen_size
if stats_buffer(i) > 0 then
line stats_image, (graph_scr_x - 1, stats_y_pointer)-(graph_scr_x - 1, stats_y_pointer + (stats_buffer(i) * stats_scale) - 2), ai.nn_brain(i).ID*647321
stats_y_pointer += stats_buffer(i) * stats_scale
'print i, stats_buffer(i), ai.nn_brain(i).fitness
end if
next i
Put stats_image, (-1, 0), stats_image, PSet
end if
end if
'print
graph_frame_counter += 1
key = inkey ' clear keyboard buffer
game.process_timers()
if (graph_frame_counter mod gen_update_fit_selection_frames) = 0 then ai.select_fittest()
'if game.check_player_collision(player(0)) andalso player(0).state > 0 then beep: player(0).state = -1: goto start
if stats_counter = 0 then ai.select_fittest()
for i as short = 0 to gen_size
player(i).process()
'if stats_counter = 0 then
if player(i).state = -1 then player(i).respawn: ai.mutate(i)
if game.check_player_collision(player(i)) then player(i).state = -1
if player(i).state > 0 then
ai.nn_brain(i).fitness += 1
ai.nn_brain(i).bias(0)=player(i).next_top_pipe_height
ai.nn_brain(i).bias(1)=player(i).next_bottom_pipe_height
ai.nn_brain(i).bias(2)=-player(i).vel_y*5
ai.nn_brain(i).bias(3)=player(i).next_pipe_distance / graph_scr_x
ai.nn_brain(i).bias(4)=(player(i).x-(graph_scr_x/2)) / graph_scr_x
ai.nn_brain(i).bias(5)=(player(i).y-(graph_scr_y/2)) / graph_scr_y
ai.gen_calc_brain(i)
if ai.nn_brain(i).bias(nn_weights_hidden_out) > .05 then player(i).jump
if ai.nn_brain(i).bias(nn_weights_hidden_out+1) > .25 then player(i).go_right
if ai.nn_brain(i).bias(nn_weights_hidden_out+1) < -.25 then player(i).go_left
end if
next i
'if stats_counter = 0 then sleep
if multikey(SC_UP) then player(0).jump
if multikey(SC_LEFT) then player(0).go_left
if multikey(SC_RIGHT) then player(0).go_right
if multikey(SC_ESCAPE) then exit do
if key = " " then
regulate(graph_set_fps, fps, true) 'reset
if graph_vsync_on then graph_vsync_on = false else graph_vsync_on = true
end if
if graph_vsync_on then sleep regulate(graph_set_fps, fps) else var tmp = regulate(graph_set_fps, fps)
locate 1,1
screenlock
'cls
if graph_vsync_on then Put (0, 0), stats_image, PSet
if graph_vsync_on then
ai.gen_draw_brain(ai.nn_fit_selection(0))
print stats_counter
print ai.nn_fit_selection_counter
print
if ai.nn_fit_selection_counter > 0 then
for i as ushort = 0 to ai.nn_fit_selection_counter - 1
color ai.nn_brain( ai.nn_fit_selection(i)).id *647321
print i ,ai.nn_fit_selection(i), ai.nn_brain(ai.nn_fit_selection(i)).best_fitness
next i
color RGB(255,255,255)
end if
end if
game.draw_pipes()
draw string (200,12),"Framerate = " & fps & " ( " & format(fps / graph_set_fps, "#") & "x )"
draw string (graph_scr_x / 2 - 50, graph_scr_y / 2),"<Press spacebar> to run normal/full speed", &h000000
for n as short = player_count to 0 step -1
if player(n).state >= 0 then
'circle (player(n).old_x, player(n).old_y*graph_scr_y), player_size, &h000000, , , , F
if graph_vsync_on then if graph_vsync_on then circle (player(n).x, player(n).y*graph_scr_y), player_size, ai.nn_brain(n).ID*647321, , , , F
'draw string (player(n).x-48, player(n).y*graph_scr_y-4),str(ai.nn_brain(n).ID), ai.nn_brain(n).ID*647321
if graph_vsync_on then circle (player(n).x, player(n).y*graph_scr_y), player_size-2, &h000000,
circle (player(n).x, player(n).y*graph_scr_y), player_size, &hFFFFFF,
end if
next
'locate 1,50: print graph_frame_counter
screenunlock
loop
sleep
end
sub bird.go_left()
if state = 0 then state = 1
x -=5
if x < 0 then x = 0
end sub
sub bird.go_right()
if state = 0 then state = 1
x +=5
if x > graph_scr_x-1 then x = graph_scr_x - 1
end sub
sub bird.jump()
if state = 0 then state = 1
if (graph_frame_counter - jump_timeout) > player_jump_interval then
vel_y /= 2.5
vel_y -= 0.015
jump_timeout = graph_frame_counter
end if
end sub
sub bird.process()
if state = 1 then
'Gravity
old_x = x
old_y = y
vel_y += 0.0005
y += vel_y
end if
end sub
sub bird.respawn()
x = 200+rnd*500
y = rnd*.8 + 0.1
state = 1
vel_y = 0
end sub
constructor bird
x = 200+rnd*500
y = rnd*.8 + 0.1
end constructor
sub flappy_game.process_timers()
'print (graph_frame_counter - start_time)
if (graph_frame_counter - start_time) > pipe_interval then start_time += (graph_frame_counter - start_time)-rnd* pipe_rnd_interval: add_pipe()
end sub
sub flappy_game.remove_pipe()
for i as ubyte = 0 to pipe_max-1
pipes(i) = pipes(i + 1)
next i
pipes(pipe_max).active_time = 0
pipe_count -=1
end sub
sub flappy_game.add_pipe()
dim as single pipe_rnd
pipe_count += 1
for i as ubyte = 0 to pipe_max
if pipes(i).active_time = 0 then
count_pipe +=1
pipes(i).pipe_id = count_pipe
pipes(i).active_time = graph_frame_counter
pipe_rnd = rnd * (1 - pipe_holesize )
pipes(i).top = pipe_rnd
pipes(i).x = graph_scr_x - (graph_frame_counter - pipes(i).active_time) * graph_pix_per_vsync
pipes(i).old_x = pipes(i).x
exit sub
end if
next i
end sub
sub flappy_game.draw_pipes()
dim as longint t = graph_frame_counter
for i as ubyte = 0 to pipe_max
if pipes(i).active_time <> 0 then
'line (pipes(i).old_x, 0)-(pipes(i).old_x + pipe_with, graph_scr_y*pipes(i).top), &h000000, BF
'line (pipes(i).old_x, graph_scr_y * (pipes(i).top + pipe_holesize))-(pipes(i).old_x + pipe_with, graph_scr_y-1), &h000000, BF
'draw string (pipes(i).old_x+ pipe_with/2-4, 8), str(pipes(i).pipe_id), &h000000
pipes(i).old_x = pipes(i).x
if pipes(i).old_x < -pipe_with then
remove_pipe(): i -=1
else
pipes(i).x = graph_scr_x - (t - pipes(i).active_time) * graph_pix_per_vsync
line (pipes(i).x, 0)-(pipes(i).x + pipe_with, graph_scr_y*pipes(i).top), &hAAAAAA, BF
line (pipes(i).x, graph_scr_y * (pipes(i).top + pipe_holesize))-(pipes(i).x + pipe_with, graph_scr_y-1), &h888888, BF
'draw string (pipes(i).old_x+ pipe_with/2-4, 8), str(pipes(i).pipe_id), &h000000
end if
end if
next i
end sub
function flappy_game.check_player_collision(p as bird) as boolean
dim as short x1 = any
dim as short x2 = any
dim as short y1 = any
dim as short y2 = any
dim as short py = any
dim as short last_x2 = 0
if p.y > 1 then return true
if p.x <= 0 then return true
for i as ubyte = 0 to pipe_count-1
x1 = pipes(i).x
x2 = (pipes(i).x + pipe_with)
if x1 < p.x andalso x2 > p.x then
y1 = graph_scr_y * pipes(i).top
y2 = graph_scr_y * (pipes(i).top + pipe_holesize)
py = p.y * graph_scr_y
if y1 < py andalso y2 > py then
'line (x1, y1)-(x2, y2), &h00FF00, bf
else
return true
end if
end if
if last_x2 < x2 andalso x2 > p.x then
'look for next colision height
last_x2 = x2
'y1 = graph_scr_y * pipes(i).top
'y2 = graph_scr_y * (pipes(i).top + pipe_holesize)
'line (0, y1+1)-(x2, y1+1), &hff0000
'line (0, y2-1)-(x2, y2-1), &hff0000
p.next_top_pipe_height = p.y - pipes(i).top
p.next_bottom_pipe_height = -(p.y - (pipes(i).top + pipe_holesize))
p.next_pipe_distance = x1
'draw string (x2, y1-8),"1 = " & p.next_top_pipe_height
'draw string (x2, y2),"2 = " & p.next_bottom_pipe_height
exit for ' need pipe do not need checks now
end if
next i
end function
Function Regulate(Byval MyFps As long,Byref fps As long, reset_ as boolean = false) As long
Static As Double timervalue, _LastSleepTime, t3, frames
if reset_ then timervalue = 0: _LastSleepTime = 0: t3 = 0: frames = 0: fps = 0
frames += 1
If (Timer-t3) >= 1 Then t3 = Timer: fps = frames: frames = 0
dim as double sleeptime=_LastSleepTime + ((1 / myfps) - Timer + timervalue) * 1000
If sleeptime<1 Then sleeptime = 1
_LastSleepTime = sleeptime
timervalue = Timer
Return sleeptime
End Function
'-------------------------------------------------Neural netwerk -------------------------
sub nn_gen.mutate(n as ushort)
static as ushort loop_counter :loop_counter += 1
if nn_fit_selection_counter = 0 then exit sub
dim as ushort loop_select = loop_counter mod nn_fit_selection_counter
dim as ushort random_select = nn_fit_selection(loop_select)
if rnd < gen_mutate_new then nn_brain(n).constructor: nn_brain(n).ID = n
if is_ID_in_selection(n) = false then
nn_brain(n) = nn_brain(random_select) ' copy is done
if nn_brain(n).fitness > nn_brain(n).best_fitness then nn_brain(n).best_fitness = nn_brain(n).fitness
nn_brain(n).fitness = 0
dim as ushort b
for a as ubyte = 0 to gen_fit_mutate_size -1
dim as rnd8_16bit pole
b = nn_weights * pole.give16_rnd
nn_brain(n).weight(b) += pole.give16_rndXrnd
'if nn_brain(n).weight(b) > 1 then nn_brain(n).weight(b) = 1
'if nn_brain(n).weight(b) < -1 then nn_brain(n).weight(b) = -1
next a
'print
'print nn_weights, gen_fit_mutate_size
'print gen_mutate_streght_weight
'sleep
'end
end if
if nn_brain(n).fitness > nn_brain(n).best_fitness then nn_brain(n).best_fitness = nn_brain(n).fitness
nn_brain(n).fitness = 0
end sub
function nn_gen.is_ID_in_selection(s as ushort) as boolean
if nn_fit_selection_counter > 0 then
for i as short = 0 to nn_fit_selection_counter-1
if nn_brain(nn_fit_selection(i)).ID = nn_brain(s).ID then return true : exit function
next i
end if
end function
sub nn_gen.select_fittest()
dim as ushort highest_fitness_found = 0, highest_fitness_found_old
dim as ubyte found
dim as byte selection(gen_size) 'pre mask array to nn_selection(gen__selection_size)
'dim as ushort 'fit_counter = 0
nn_fit_selection_counter = 0
for a as ushort = 0 to gen_size
if nn_brain(a).fitness > highest_fitness_found then highest_fitness_found = nn_brain(a).fitness
next
'print
'print gen_fit_selection_size, highest_fitness_found
highest_fitness_found_old = highest_fitness_found
do
found = 0
for a as ushort = 0 to gen_size
if selection(a) = 0 andalso nn_brain(a).fitness = highest_fitness_found then
selection(a) = 1
if is_ID_in_selection(a) = false then
nn_fit_selection(nn_fit_selection_counter) = a
'fit_counter += 1
nn_fit_selection_counter += 1
found = 1
end if
'print is_ID_in_selection(a)
exit for
end if
next
if highest_fitness_found = 0 then exit do
if found = 0 then highest_fitness_found -= 1 ' this is slow!!!!!!!!!!!!!!!!!!!!
if (highest_fitness_found_old /10) > highest_fitness_found then exit do
loop until nn_fit_selection_counter >= gen_fit_selection_size ' leave loop when fit selection is full
'call mutate after this
end sub
sub nn_gen.gen_calc_brain(a as ubyte)
Clear nn_brain(a).bias(nn_node_in), 0, (nn_bias-nn_node_in+1) * SizeOf(single) 'clear als outputs
dim as single output_offset = nn_node_in
dim as single input_offset = 0
dim as ushort count_weight = 0
for c as ubyte = 0 to nn_node_hidden - 1
for b as ubyte = 0 to nn_node_in - 1
nn_brain(a).bias(output_offset+c) += nn_brain(a).bias(input_offset+b) * nn_brain(a).weight(count_weight)
count_weight += 1
next
'nn_brain(a).bias(output_offset+c) /= nn_node_in
next
if nn_layer_hidden > 0 then
for d as ubyte = 0 to nn_layer_hidden -1
output_offset = nn_node_in + (nn_node_hidden * (d+1))
input_offset = nn_node_in + (nn_node_hidden * d)
'print "mid input_offset"; input_offset
'print "mid output_offset"; output_offset
for c as ubyte = 0 to nn_node_hidden - 1
for b as ubyte = 0 to nn_node_hidden - 1
nn_brain(a).bias(output_offset+c) += nn_brain(a).bias(input_offset+b) * nn_brain(a).weight(count_weight)
count_weight += 1
next
'nn_brain(a).bias(output_offset+c) /= nn_node_hidden
next
next
end if
output_offset = nn_node_in + (nn_node_hidden * (nn_layer_hidden+1))
input_offset = nn_node_in + (nn_node_hidden * (nn_layer_hidden))
for c as ubyte = 0 to nn_node_out - 1
for b as ubyte = 0 to nn_node_hidden - 1
nn_brain(a).bias(output_offset+c) += nn_brain(a).bias(input_offset+b) * nn_brain(a).weight(count_weight)
count_weight += 1
next
'nn_brain(a).bias(output_offset+c) /= nn_node_hidden
next
end sub
'subs and functions
sub nn_gen.set_all_random()
for a as ushort = 0 to gen_size
nn_brain(a).ID = a
next
end sub
constructor Neural_network
for c as ushort = 0 to nn_weights
weight(c) = rnd * 2 -1
next
fitness = 0
best_fitness = 0
end constructor
sub nn_gen.gen_draw_brain(a as ubyte)
dim as short in_offset = ((nn_node_in - 1) / 2 * graph_size)
dim as short hidden_offset = ((nn_node_hidden - 1) / 2 * graph_size)
dim as short out_offset = ((nn_node_out - 1) / 2 * graph_size)
dim as short x, y, x2, y2
dim as ushort count_bias = 0
dim as ushort count_weight = 0
'part weights
for c as ubyte = 0 to nn_node_hidden - 1
for b as ubyte = 0 to nn_node_in - 1
x = graph_xoffset
y = graph_yoffset + b*graph_size - in_offset
x2 = graph_xoffset + graph_size*2
y2 = graph_yoffset + c*graph_size - hidden_offset
line(x, y)-(x2, y2), &hff00ff
draw string ((x+x2)/2 - 16,(y+y2)/2-8+b*8),round(nn_brain(a).weight(count_weight)), &hFFFF00
count_weight += 1
next
next
if nn_layer_hidden > 0 then
for e as ubyte = 0 to nn_layer_hidden-1
for d as ubyte = 0 to nn_node_hidden - 1
for f as ubyte = 0 to nn_node_hidden - 1
x = graph_xoffset + (4 + (e-1)*2) * graph_size
y = graph_yoffset + d*graph_size - hidden_offset
x2 = graph_xoffset + (4 + (e)*2) * graph_size
y2 = graph_yoffset + f*graph_size - hidden_offset
line(x, y)-(x2, y2), &hff00ff
draw string ((x+x2)/2 - 16,(y+y2)/2-8+f*8),round(nn_brain(a).weight(count_weight)), &hFFFF00
count_weight += 1
next
next
next
end if
for d as ubyte = 0 to nn_node_hidden - 1
for f as ubyte = 0 to nn_node_out - 1
x = graph_xoffset + (4 + (nn_layer_hidden-1)*2) * graph_size
y = graph_yoffset + d*graph_size - hidden_offset
x2 = graph_xoffset + (4 + nn_layer_hidden*2) * graph_size
y2 = graph_yoffset + f*graph_size - out_offset
line(x, y)-(x2, y2), &hff00ff
draw string ((x+x2)/2 - 16,(y+y2)/2-8+f*8),round(nn_brain(a).weight(count_weight)), &hFFFF00
count_weight += 1
next
next
' part bias
for b as ubyte = 0 to nn_node_in - 1
x = graph_xoffset
y = graph_yoffset + b*graph_size - in_offset
circle (x, y), graph_size/4 , &hFF0000
draw string (x-12,y-4), round(nn_brain(a).bias(count_bias)), &hFFFFff
count_bias += 1
next
for c as ubyte = 0 to nn_node_hidden - 1
x = graph_xoffset + graph_size*2
y = graph_yoffset + c*graph_size - hidden_offset
circle (x, y), graph_size/4 , &h00FF00
draw string (x-12,y-4), round(nn_brain(a).bias(count_bias)), &hFFFFff
count_bias += 1
next
if nn_layer_hidden > 0 then
for e as ubyte = 0 to nn_layer_hidden -1
for d as ubyte = 0 to nn_node_hidden - 1
x = graph_xoffset + (4 + e*2) * graph_size
y = graph_yoffset + d*graph_size - hidden_offset
circle (x, y), graph_size/4 , &h00FF00
draw string (x-12,y-4),round(nn_brain(a).bias(count_bias)), &hFFFFff
count_bias += 1
next
next
end if
for f as ubyte = 0 to nn_node_out - 1
x = graph_xoffset + (4 + nn_layer_hidden*2) * graph_size
y = graph_yoffset + f*graph_size - out_offset
circle (x, y), graph_size/4 , &h0000FF
draw string (x-12,y-4),round(nn_brain(a).bias(count_bias)), &hFFFFff
count_bias += 1
next
end sub
function round(n as single) as string
return Format(n, "#.##")
end function
constructor rnd8_16bit
in32_rnd = rnd * 4294967296
end constructor
function rnd8_16bit.give16_rndXrnd() as single
return ((out8_a-128) * (out8_b-128)) /16128
end function
function rnd8_16bit.give16_rnd() as single
return out16_c / 65535.002
end function