#Include "fbgfx.bi"
#Ifdef __FB_WIN32__
#Include "windows.bi"
#EndIf

Using fb

Enum Caption
	CaptionClick=100 'клик по заголовку окна
	CaptionClose 'клик по кнопке закрытия окна
	CaptionMinimize 'клик по кнопке минимизировать
	ButtonNew 'клик по кнопке новая игра
	ButtonLevel 'клик по кнопке режим игры
End Enum

Type Record
	Sword As ZString*15 'слово
	BestMoves As Integer 'лучшее меньшее кол-во ходов для слова
	BestTime As Integer 'лучшее меньшее время для слова
End Type

Type Statistic
	Current As Integer 'текущее собираемое слово
	Moves As Integer 'текущее кол-во ходов
	Time_ As Integer 'текущее время
	Time_1 As Double ' переменная для получения начального времени
	Time_2 As Double ' переменная для получения разницы времени
End Type

Type matrix
	As Byte one 'горизонтальная верхняя
	As Byte two 'горизонтальная средняя
	As Byte three 'горизонтальная нижняя
	As Byte four ' вертикальная левая верхняя
	As Byte five ' вертикальная правая верхняя
	As Byte six ' вертикальная левая нижняя
	As Byte seven ' вертикальная правая нижняя
	As UByte Scode ' сканкод буквы
End Type

Type Extmatrix
	As Integer y(1 To 3)={30,250,450} ' размеры Y для рядов сегментов
	As matrix matrix ' матрица сегмента
End Type

Type game
	As Integer w,h 'ширина и высота окна
	As Integer Mx,My 'координаты мыши
	As Integer Wx,Wy 'координаты окна
	As Integer LenSegment=35 ' длина сегмента
	As Integer LenWord ' длина слова
	As Byte Mode ' режим игры(легкий, затрудненный)
	As Integer OldClick 'для сохранения номера сегмента
	#Ifdef __FB_WIN32__
	as HICON icon ' хендл для икнки
	#EndIf
	As Byte CaptionClickflag,SpriteFlag,CheckWinflag 'флаги клика по заголовку окна,сегменту;выигрыша
	As Any Ptr hwnd 'хендл окна
	As Any Ptr sprite,button,buttonL,caption,VBorder,HBorder,pif 'буферы для изображений
	As Statistic Stat ' структурированная переменная статистики игры
	As EVENT ev 'структурированная переменная для получения событий
	As Record RecordWord(1 To 40)={_
	("агава",0,0),("агнец",0,0),("ананас",0,0),("ангар",0,0),_
	("анонс",0,0),("багор",0,0),("баланс",0,0),("банан",0,0),_
	("барабан",0,0),("баррель",0,0),("барьер",0,0),("бегун",0,0),_
	("белорус",0,0),("берег",0,0),("беречь",0,0),("берлога",0,0),_
	("венера",0,0),("вор",0,0),("гавань",0,0),("газобаллон",0,0),_
	("газон",0,0),("гроза",0,0),("егерь",0,0),("епанча",0,0),_
	("ересь",0,0),("есаул",0,0),("забрало",0,0),("завал",0,0),_
	("запара",0,0),("обречь",0,0),("уговор",0,0),("угорь",0,0),_
	("угроза",0,0),("червь",0,0),("череп",0,0),("чересчур",0,0)}'массив предустановленных слов и рекордов по ним
	As Integer ColorM(1 To 16)={&hFB4533,&hFFFF51,&h11D60F,&hC553B1,&hD7B74E,_
	&h49C5F8,&h7DE2D2,&hDF0597,&hC4B48E,&hF3A4FE,_
	&h3EAC4B,&hE08292,&h01B3FC,&hC5BF32,&h96DCAF,&hC917A0} ' массив цветов
	As Extmatrix segment( 1 To 3 , 1 To 16 )'массив всех сегментов
	As matrix templateChar(1 To 16)={_
	(1,1,0,1,1,1,1,224),(1,0,0,1,0,1,0,227),(1,1,1,1,1,1,1,226),_
	(0,1,0,1,1,1,1,237),(1,1,1,1,0,1,0,229),(0,0,1,1,1,1,1,246),_
	(1,0,1,1,0,1,0,241),(1,1,0,1,1,1,0,240),(1,0,1,1,1,1,1,238),_
	(1,1,1,1,0,1,1,225),(1,0,0,1,1,1,1,235),(0,1,1,1,0,1,1,252),_
	(0,1,1,1,1,0,1,243),(1,1,1,0,1,0,1,231),(0,1,0,1,1,0,1,247),_
	(1,0,0,1,1,1,1,239)} 'шаблоны для отображения букв сегментами
	Declare Constructor() ' начальная инициализация
	Declare Destructor() ' освобождение ресурсов
	Declare Sub NewGame() ' новая игра
	Declare Sub EVENTSUB() ' полученией событий
	Declare Sub OpenSaveRecords( fl As Integer = 0) ' сохранение и загрузка рекордов
	Declare Sub DoubleSegment(id As Integer) ' копия сегмента для Drag and Drop
	Declare Sub RndWord() ' случайное слово при загрузке новой игры
	Declare Sub ReplaceMatrix(id As Integer=0,dest As Integer=0,extmode As Integer=2) 'перезапись сегментов при слиянии или начальной рандомной инициализации
	Declare Sub Update() ' обновление рисования
	Declare Function CheckWin() As Integer 'проверка на выигрыш
	Declare Sub RandomSegment() ' случайное заполнение сегментов первого верхнего ряда
	Declare Sub SegmentDraw(N As Integer=16,y As Integer =1,color_ As Integer=0,fl As Byte=1)'рисование сегментов
	Declare Sub WindowPosition()' изменение позиций окна
	Declare Function MouseCaptionClick() As Integer 'получение расшифровки клика по чему-либо
End Type

Dim obj As game ' объект класса

Constructor game()
	Screen 19,32,2,8
	Randomize Timer
	ScreenInfo w,h
	ScreenSet 1
	WindowTitle "GameWordFB"
	ScreenControl(GET_WINDOW_HANDLE,Cast(Integer,hwnd))
	sprite = ImageCreate(LenSegment+2,LenSegment*2+2,&h0)
	pif = ImageCreate(186,207)
	BLoad "pif.bmp",pif
	button = ImageCreate(50,30)
	buttonL = ImageCreate(50,30)
	caption = ImageCreate(w,30)
	VBorder = ImageCreate(4,h)
	HBorder = ImageCreate(w-8,4)
	Line button, (0,0)-Step(50,30),&h4545CF,bf
	Line buttonL, (0,0)-Step(50,30),&h4545CF,bf
	Draw String button,(14,8),"New",&hffffff
	Draw String buttonL,(10,8),"Easy",&hffffff
	For i As Integer = 0 To 30
		Line caption, (0,i)-(w,i),(&h454545)+(i*5)+20,bf
	Next
	Line (0,31)-(4,h),&h4545AB,BF
	Line HBorder,(0,0)-(w-8,4),&h4545AB,BF
	Line VBorder,(0,0)-(4,h),&h4545AB,BF
	Line caption,(w-29,1)-(w-3,20),&h0,B
	Draw String caption, (w-18,3),"x",&hff0000
	#Ifdef __FB_WIN32__
	icon=LoadIcon(GetModuleHandle(0),MAKEINTRESOURCE(100))
	SendMessage(hwnd,WM_SETICON,ICON_BIG,Cast(Lparam,icon))
	Line caption, (w-55,1)-(w-29,20),&h0,B
	Draw String caption, (w-44,4),"-",&hff0000
	#EndIf
	Draw String caption,((w\2-48),10),"* GameWord *",&hFFDD00
	OpenSaveRecords()
	NewGame()
	EVENTSUB()
End Constructor

Destructor game()
	ImageDestroy(sprite)
	ImageDestroy(button)
	ImageDestroy(buttonL)
	ImageDestroy(caption)
	ImageDestroy(VBorder)
	ImageDestroy(HBorder)
	ImageDestroy(pif)
	#Ifdef __FB_WIN32__
	DestroyIcon(icon)
	#EndIf
End Destructor

Sub game.NewGame()
	RandomSegment()
	RndWord()
	ReplaceMatrix()
	Stat.Time_=0
	Stat.Moves=0
	CheckWinflag=0
	Stat.Time_2 = Timer
End Sub

Sub game.OpenSaveRecords( fl As Integer )
	If fl=0 Then
		Open "Records" For Input As #1
		If Err <> 0 Then Exit Sub
		For i As Integer = 1 To 40
			Dim As ZString*10 TS
			Input #1,TS
			RecordWord(i).BestMoves = Val(TS)
			Input #1,TS
			RecordWord(i).BestTime = Val(TS)
		Next
	Else
		Open "Records" For Output As #1
		If Err <> 0 Then Exit Sub
		For i As Integer = 1 To 40
			Print #1,RecordWord(i).BestMoves
			Print #1,RecordWord(i).BestTime
		Next
	EndIf
	Close #1
End Sub

Function game.CheckWin() As Integer
	For i As Integer = 1 To Lenword
		If segment(2,i).matrix.one<>segment(3,i).matrix.one Then Return 0
		If segment(2,i).matrix.two<>segment(3,i).matrix.two Then Return 0
		If segment(2,i).matrix.three<>segment(3,i).matrix.three Then Return 0
		If segment(2,i).matrix.four<>segment(3,i).matrix.four Then Return 0
		If segment(2,i).matrix.five<>segment(3,i).matrix.five Then Return 0
		If segment(2,i).matrix.six<>segment(3,i).matrix.six Then Return 0
		If segment(2,i).matrix.seven<>segment(3,i).matrix.seven Then Return 0
	Next
	Return 1
End Function

Sub game.Update()
	SegmentDraw(,,&h202020,0)
	SegmentDraw(LenWord,2,&h202020,0)
	SegmentDraw(LenWord,3,&h202020,0)
	SegmentDraw()
	SegmentDraw(LenWord,2)
	SegmentDraw(LenWord,3)
	Draw String(w-145,h-160), "Moves:       " & Stat.Moves,&hffffff
	Draw String(w-145,h-140), "Time:        " & Stat.Time_,&hffffff
	Draw String(w-145,h-120), "RecordMoves: " & RecordWord(Stat.Current).BestMoves,&hffffff
	Draw String(w-145,h-100), "RecordTime:  " & RecordWord(Stat.Current).BestTime,&hffffff
	Put (w-200,h-400),pif
	Put (w-60,h-40),button
	Put (w-115,h-40),buttonL
	Put (0,0),caption
	Put (4,h-4),HBorder
	Put (0,30),VBorder
	Put (w-4,30),VBorder
	If SpriteFlag=1 Then
		Put (Mx-(LenSegment\2),My-LenSegment),sprite
	EndIf
End Sub

Sub game.RndWord()
	Stat.Current = Int((Rnd*36))+1
	LenWord = Len(RecordWord(Stat.Current).SWord)
	For i As Integer =1 To LenWord
		For j As Integer = 1 To 16
			If RecordWord(Stat.Current).SWord[i-1]=templateChar(j).Scode Then
				For k As Integer = 2 To 3
					segment(k,i).matrix.one=templateChar(j).one
					segment(k,i).matrix.two=templateChar(j).two
					segment(k,i).matrix.three=templateChar(j).three
					segment(k,i).matrix.four=templateChar(j).four
					segment(k,i).matrix.five=templateChar(j).five
					segment(k,i).matrix.six=templateChar(j).six
					segment(k,i).matrix.seven=templateChar(j).seven
				Next
				Exit For
			EndIf
		Next
	Next
End Sub

Sub game.ReplaceMatrix(id As Integer,dest As Integer,extmode As Integer)
	Dim As Integer r_n_d
	For i As Integer =1 To LenWord
		For j As Integer = 1 To 10
			If id<>0 Then
				r_n_d=id
				i=dest
				Stat.moves+=1
			Else
				r_n_d=Int((Rnd*16))+1
			EndIf
			segment(extmode,i).matrix.one Xor=segment(1,r_n_d).matrix.one
			segment(extmode,i).matrix.two Xor=segment(1,r_n_d).matrix.two
			segment(extmode,i).matrix.three Xor=segment(1,r_n_d).matrix.three
			segment(extmode,i).matrix.four Xor=segment(1,r_n_d).matrix.four
			segment(extmode,i).matrix.five Xor=segment(1,r_n_d).matrix.five
			segment(extmode,i).matrix.six Xor=segment(1,r_n_d).matrix.six
			segment(extmode,i).matrix.seven Xor=segment(1,r_n_d).matrix.seven
			If id<>0 Then Exit For, For
		Next
	Next
End Sub

Sub game.RandomSegment()
	For i As Integer = 1 To 16
		segment(1,i).matrix.one=Int(Rnd*2)
		segment(1,i).matrix.two=Int(Rnd*2)
		segment(1,i).matrix.three=Int(Rnd*2)
		segment(1,i).matrix.four=Int(Rnd*2)
		segment(1,i).matrix.five=Int(Rnd*2)
		segment(1,i).matrix.six=Int(Rnd*2)
		segment(1,i).matrix.seven=Int(Rnd*2)
	Next
End Sub

Sub game.SegmentDraw(N As Integer,y As Integer, color_ As Integer,fl As Byte)
	Dim As Integer col
	For i As Integer = 1 To N
		If fl=1 Then
			col=ColorM(i)
		Else
			col=color_
		EndIf
		If segment(y,i).matrix.one=fl Then
			Line(8+(i-1)*(LenSegment)+13*i,segment(y,y).y(y)+30)-Step((LenSegment),0),Col
		EndIf
		If segment(y,i).matrix.two=fl Then
			Line(8+(i-1)*(LenSegment)+13*i,segment(y,y).y(y)+LenSegment+30)-Step((LenSegment),0),Col
		EndIf
		If segment(y,i).matrix.three=fl Then
			Line(8+(i-1)*(LenSegment)+13*i,segment(y,y).y(y)+LenSegment*2+30)-Step((LenSegment),0),Col
		EndIf
		If segment(y,i).matrix.four=fl Then
			Line(8+(i-1)*(LenSegment)+13*i,segment(y,y).y(y)+30)-Step(0,(LenSegment)),Col
		EndIf
		If segment(y,i).matrix.five=fl Then
			Line(8+(i-1)*(LenSegment)+13*i+LenSegment,segment(y,y).y(y)+30)-Step(0,(LenSegment)),Col
		EndIf
		If segment(y,i).matrix.six=fl Then
			Line(8+(i-1)*(LenSegment)+13*i,segment(y,y).y(y)+LenSegment+30)-Step(0,(LenSegment)),Col
		EndIf
		If segment(y,i).matrix.seven=fl Then
			Line(8+(i-1)*(LenSegment)+13*i+LenSegment,segment(y,y).y(y)+LenSegment+30)-Step(0,(LenSegment)),Col
		EndIf
	Next
End Sub

Sub game.DoubleSegment(id As Integer)
	Line sprite, (0,0)-(LenSegment+2,LenSegment*2+2),&h201010,BF
	If segment(1,id).matrix.one=1 Then
		Line sprite,(1,1)-Step((LenSegment),0),&hffffff
	EndIf
	If segment(1,id).matrix.two=1 Then
		Line sprite,(1,1+LenSegment)-Step((LenSegment),0),&hffffff
	EndIf
	If segment(1,id).matrix.three=1 Then
		Line sprite,(1,1+LenSegment*2)-Step((LenSegment),0),&hffffff
	EndIf
	If segment(1,id).matrix.four=1 Then
		Line sprite,(1,1)-Step(0,(LenSegment)),&hffffff
	EndIf
	If segment(1,id).matrix.five=1 Then
		Line sprite,(1+LenSegment,1)-Step(0,(LenSegment)),&hffffff
	EndIf
	If segment(1,id).matrix.six=1 Then
		Line sprite,(1,1+LenSegment)-Step(0,(LenSegment)),&hffffff
	EndIf
	If segment(1,id).matrix.seven=1 Then
		Line sprite,(1+LenSegment,1+LenSegment)-Step(0,(LenSegment)),&hffffff
	EndIf
End Sub

Sub game.WindowPosition()
	ScreenControl  GET_WINDOW_POS, wX, wY
	ScreenControl  SET_WINDOW_POS, wX+ev.dx, wY+ev.dy
End Sub

Function game.MouseCaptionClick() As Integer
	Static xor_ As Byte=1
	If Mx >=0 And Mx <= w-55 And My>0 And My<=30 Then
		Return CaptionClick
	ElseIf Mx >=w-29 And Mx<=w And My>0 And My<=20 Then
		Return CaptionClose
	ElseIf Mx >=w-55 And Mx<=w-30 And My>0 And My<=20 Then
		Return CaptionMinimize
	ElseIf Mx >=w-60 And Mx<=w-10 And My>h-40 And My<=h-10 Then
		NewGame()
	ElseIf Mx >=w-115 And Mx<=w-75 And My>h-40 And My<=h-10 Then
		Line buttonL,(1,1)-Step(45,28),&h4545CF,BF
		Xor_ Xor=1
		If xor_ = 1 Then
			Draw String buttonL,(10,8),"Easy",&hffffff
			mode=0
		Else
			Draw String buttonL,(10,8),"Hard",&hff0000
			mode=1
		EndIf
	EndIf
	Select Case My
		Case 30+segment(1,1).y(1) To 30+segment(1,1).y(1)+ LenSegment*2
			For i As Integer = 1 To 16
				Select Case Mx
					Case 8+(i-1)*(LenSegment)+13*i To 8+(i-1)*(LenSegment)+13*i+LenSegment
						Return i
				End Select
			Next
		Case 30+segment(1,1).y(2) To 30+segment(1,1).y(2)+ LenSegment*2
			For i As Integer = 1 To LenWord
				Select Case Mx
					Case 8+(i-1)*(LenSegment)+13*i To 8+(i-1)*(LenSegment)+13*i+LenSegment
						Return i+16
				End Select
			Next
	End Select
End Function

Sub game.EVENTSUB()
	Do
		If (ScreenEvent(@ev)) Then
			Select Case ev.type
				Case EVENT_MOUSE_BUTTON_PRESS
					Dim As Integer Click=MouseCaptionClick()
					Select Case Click
						Case CaptionClick
							CaptionClickflag = 1
						Case CaptionMinimize
							#Ifdef __FB_WIN32__
							ShowWindow(hwnd,SW_MINIMIZE)
							#Else
							CaptionClickflag = 1
							#EndIf
						Case CaptionClose
							OpenSaveRecords(1)
							Exit Sub
						Case 1 To 16
							If CheckWinflag=0 Then
								DoubleSegment(Click)
								OldClick=Click
								SpriteFlag=1
							EndIf
					End Select
				Case EVENT_MOUSE_BUTTON_RELEASE
					If SpriteFlag=1 Then
						Dim As Integer Click=MouseCaptionClick()
						Select Case Click
							Case 17 To 16+LenWord
								ReplaceMatrix(OldClick,Click-16)
								CheckWinflag=CheckWin()
								If CheckWinflag=1 Then
									If RecordWord(Stat.Current).BestMoves = 0 Or Stat.moves < RecordWord(Stat.Current).BestMoves Then
										RecordWord(Stat.Current).BestMoves = Stat.moves
									EndIf
									If RecordWord(Stat.Current).BestTime = 0 Or Stat.time_ < RecordWord(Stat.Current).BestTime Then
										RecordWord(Stat.Current).BestTime = Stat.time_
									EndIf
								EndIf
							Case 1 To 16
								If Mode=0 And OldClick<>Click Then
									ReplaceMatrix(OldClick,Click,1)
								EndIf
						End Select
						SpriteFlag=0
					EndIf
					CaptionClickflag = 0
				Case EVENT_MOUSE_MOVE
					Mx=ev.x:My=ev.y
					If CaptionClickflag = 1 Then WindowPosition()
			End Select
		End If
		Update()
		PCopy
		Sleep(10)
		Cls
		If CheckWinflag=0 Then
			Stat.Time_1 = Timer - Stat.Time_2
			Stat.Time_=Int(Stat.Time_1)
		Else
			Draw String (350,200),"Congratulations!",&hFFDD00
		EndIf
	Loop Until MultiKey(1)
End Sub
