Letter Puzzle

Miscellaneous Forums/Blitz Showcase/Letter Puzzle

I got the PointInPoly() function working now so you can directly select a shape with the mouse. Same for rotation. Just hover over a shape then RIGHT-CLICK to rotate and LEFT-CLICK to move. The shape becomes the active one under both situations

Conrad,
I had to change the 2nd shape so that it draws in a clockwise manor. The PointInPoly() function only works on polygons constructed in a clockwise fashion
Can you therefore update the puzzle completion checking routine since this is will be currently broken?

SuperStrict
Framework BRL.GLMax2D
Graphics 800,600

'-----------
' SHAPE DATA
'-----------
'       num. points, x, y,   x,   y,   x,   y,   x,  y,   x,  y

Global shapes:tShape[4]
shapes[0]=tShape.Create([ 30.0,-100.0  ,  30.0, 55.0  ,  -40.0, 55.0  ,  -40.0,-30.0])
shapes[1]=tShape.Create([ 35.0,-005.0  ,  35.0, 25.0  ,  -35.0, 25.0  ,  -35.0,-75.0  ])
shapes[2]=tShape.Create([-15.0, 050.0  , -15.0,-15.0  ,   50.0,-15.0])
shapes[3]=tShape.Create([ 30.0,-100.0  ,  30.0, 90.0  ,  -15.0, 45.0  ,  -40.0, 70.0  ,  -40.0, -30.0])

Local GameHandle:tGameHandle=tGameHandle.Create(4)

While Not KeyHit(KEY_ESCAPE)
	GameHandle.mainLoop()
	Flip
	Cls
Wend

End

'---------------------------------------------
' GameHandle type
' -Handles general flow of the game
'---------------------------------------------
Type tGameHandle
	Const SOL_DIST:Int=8 ' distance there may be between points for them to be 'connected'
	Const MODE_MOVE:Int=1
	Const MODE_ROTATE:Int=2
	Global oldGfx:Int[]=New Int[4] ' colR,colG,colB,lineW
	
	Field numShapes:Int,numSolutions:Int
	Field solData1:Int[] ' solution data [p1]
	Field solData2:Int[] ' solution data [shape p1]
	Field solData3:Int[] ' solution data [p2]
	Field solData4:Int[] ' solution data [shape p2]
	Field selectedShape:Int=-1
	Field currentMode:Int=MODE_MOVE
	Field tmpX:Int=-1,tmpY:Int=-1 ' mouse move

	Function Create:tGameHandle(_numshapes%)
		Local g:tGameHandle=New tGameHandle
		g.numShapes=_numshapes
		g.LoadSolutions()
		g.repositionShapes()
		g.selectedShape=0
		SetClsColor( 50,130,50 )
		Return G
	EndFunction
	
	Method loadSolutions()
		Local pX%,pY%,s1%,s2%	
		ReadData( numSolutions )
		solData1=New Int[numSolutions]
		solData2=New Int[numSolutions]
		solData3=New Int[numSolutions]
		solData4=New Int[numSolutions]
		For Local i%=0 Until numSolutions
			ReadData(pX)
			ReadData(s1)
			ReadData(pY)
			ReadData(s2)
			solData1[i]=pX
			solData2[i]=s1
			solData3[i]=pY
			solData4[i]=s2
		Next
	EndMethod
	
	Method repositionShapes()
		For Local i:Int=0 Until numShapes
			shapes[i].setPosition( i*100+200,300 )
		Next
	End Method
	
	Method draw()
		For Local i:Int=0 Until numShapes
			shapes[i].changeCol( 255-i*20,255-i*20,255-i*20 )
			If i=selectedShape Then shapes[i].changeCol( 80,250,60 )
			If PointInPoly(MouseX()-shapes[i].posX,MouseY()-shapes[i].posY,shapes[i].polydata)
				shapes[i].changeCol ($ff,$40,$40)
				If (MouseHit(1) Or MouseHit(2)) Then selectedShape=i
			EndIf
			shapes[i].draw
		Next
		drawGUI()
	EndMethod
	
	Method drawGUI()
		setGfx( 0,0,0,2 )
		DrawRect( 0,0,GraphicsWidth(),100 )
		setGfx( 255,255,255,2 )
		DrawText( "Rotate (rmb) and move (lmb) to pieces so they form the letter:",50,10 )
		setGfx( 255,50,50,2 )
		DrawRect( 550,10,18,25 )
		setGfx( 255,255,255,2 );SetScale( 2.0,2.0 )
		DrawText( "T",550,10 );SetScale( 1.0,1.0 )
		DrawText( "Press keys [1-4] or [TAB] to select pieces",50,70 )
		restoreGfx()
	End Method
	
	Method checkIfFinsished:Byte()
		Local i%,x1%,y1%,x2%,y2%,dx%,dy%
		For i=0 Until numSolutions
			x1=shapes[solData2[i]].PolyData[solData1[i]*2]+shapes[solData2[i]].posX
			y1=shapes[solData2[i]].PolyData[solData1[i]*2+1]+shapes[solData2[i]].posY
			x2=shapes[solData4[i]].PolyData[solData3[i]*2]+shapes[solData4[i]].posX
			y2=shapes[solData4[i]].PolyData[solData3[i]*2+1]+shapes[solData4[i]].posY
			dx=Abs(x1-x2);dy=Abs(y1-y2)
			If ( Sqr(dx*dx+dy*dy) > SOL_DIST )
				Return False
			EndIf
		Next
		Return True
	EndMethod
			
	Method mainLoop()
		handleInput()
		draw()
		If( checkIfFinsished()=True )
			completed()
		EndIf
	EndMethod
	
	Method completed()
		Local count:Int
		selectedShape=-1
		While( count < 10 )
			Delay( 80 )
			If( (count Mod 2)=0 )
				SetClsColor( 200,50,50 )
			Else
				SetClsColor( 50,200,50 )
			EndIf
			Cls
			draw()
			Flip
			count:+1
		Wend
		count=0
		setGfx( 0,0,0,2 )
		SetClsColor( 200,50,50 )
		While( count < 10 )
			Delay( 80 )
			If( (count Mod 2)=0 )
				SetClsColor( 200,50,50 )
			Else
				SetClsColor( 50,200,50 )
			EndIf
			Cls()
			draw()
			DrawRect( GraphicsWidth()/2-(count*40)/2,GraphicsHeight()/2-(count*30)/2,count*40,count*30 )
			Flip
			count:+1
		Wend
		draw()
		DrawRect( GraphicsWidth()/2-(count*40)/2,GraphicsHeight()/2-(count*30)/2,count*40,count*30 )
		setGfx( 200,200,200,2 )
		SetScale( 2.0,2.0 )
		DrawText( "Congratualations!",GraphicsWidth()/2-(count*40)/2+30,GraphicsHeight()/2-(count*30)/2+30 )
		SetScale( 2.8,4.0 )
		DrawText( "Puzzle completed!",GraphicsWidth()/2-(count*40)/2+10,GraphicsHeight()/2-(count*30)/2+100 )
		Flip
		restoreGfx()
		WaitKey()
		End
	EndMethod
	
	Method handleInput()
		If KeyDown(key_up) shapes[selectedShape].move(0,-3)
		If KeyDown(key_down) shapes[selectedShape].move(0,3)
		If KeyDown(key_left) shapes[selectedShape].move(-3,0)
		If KeyDown(key_right) shapes[selectedShape].move(3,0)
		
		If KeyHit(KEY_1) selectedShape=0
		If KeyHit(KEY_2) selectedShape=1
		If KeyHit(KEY_3) selectedShape=2
		If KeyHit(KEY_4) selectedShape=3
		If KeyHit(KEY_5) selectedShape=4
		If KeyHit(KEY_6) selectedShape=5
		If KeyHit(KEY_7) selectedShape=6
		
		If KeyDown(KEY_R) shapes[selectedShape].rotate(3)
		
		If KeyHit(KEY_TAB)
			selectedShape:+1
			If selectedShape>3 selectedShape=0
		EndIf
		
		If( MouseDown(MOUSE_LEFT) )
			If tmpX=-1 tmpX=MouseX()
			If tmpY=-1 tmpY=MouseY()
			shapes[selectedShape].move( MouseX()-tmpX,MouseY()-tmpY )
			tmpX=MouseX()
			tmpY=MouseY()	
		ElseIf( MouseDown(MOUSE_RIGHT) )	
			If tmpX=-1 tmpX=MouseX()
			If tmpY=-1 tmpY=MouseY()
			shapes[selectedShape].rotate( MouseX()-tmpX+MouseY()-tmpY )
			tmpX=MouseX()
			tmpY=MouseY()
		Else
			tmpX=-1
			tmpY=-1
		EndIf	
	EndMethod
	
	Function setGfx( _r:Int,_g:Int,_b:Int,_lw:Int )
		restoreGfx()
		GetColor( oldGfx[0],oldGfx[1],oldGfx[2] )
		SetColor( _r,_g,_b )
		SetLineWidth( _lw )
	EndFunction
	
	Function restoreGfx()
		SetColor ( tGameHandle.oldGfx[0],tGameHandle.oldGfx[1],tGameHandle.oldGfx[2] )
		SetLineWidth( oldGfx[3] )
	EndFunction
End Type

'---------------------------------------------
' Shape type
' -Holds all data for every shape
'---------------------------------------------
Type tShape
	Field posX:Int,posY:Int
	Field PolyData#[]
	Field colorR:Int=255,colorG:Int=255,colorB:Int=255
	Field drawPoints:Byte=False
	Field lineW:Int=3
	
	Function Create:tShape(pdata#[])
		Local s:tShape=New tShape
		s.PolyData=pdata
		Return s
	EndFunction
	
	Function createSquare:tShape(_w#=100.0,_h#=100.0)
		Local s:tShape=tShape.Create([0.0,0.0,_w,0.0,_w,_h,0.0,_h])
		Return s
	EndFunction
	
	Method move( _dx:Int,_dy:Int )
		posX:+_dx
		posY:+_dy
	EndMethod
	
	Method setPosition(nx#,ny# )
		posX=nx ; posY=ny
	EndMethod
	
	Method rotate( _angle:Int )
		Local xnew:Float,ynew:Float
		Local p%=0
		Repeat
			xnew=PolyData[p]*Cos(_angle)-PolyData[p+1]*Sin(_angle)
			ynew=PolyData[p]*Sin(_angle)+PolyData[p+1]*Cos(_angle)
			PolyData[p]=xnew
			PolyData[p+1]=ynew
			p:+2
		Until p>=PolyData.Length
	EndMethod
		
	Method draw()
		tGameHandle.setGfx( colorR,colorG,colorB,lineW )
		SetOrigin posX,posY
		DrawPoly polydata
		SetOrigin 0,0
		tGameHandle.restoreGfx()
	EndMethod
	
	Method changeCol(_r:Int,_g:Int,_b:Int,_lw:Int=2)
		colorR=_r
		colorG=_g
		colorB=_b
		lineW=_lw
	EndMethod
End Type


Function calcDist:Int(s0:tShape,s1:tShape)
	Local dx:Int,dy:Int
	dx=Abs(s0.posX+s1.posX)
	dy=Abs(s0.posY+s1.posY)
	Return( Int( Sqr( dx*dx+dy*dy ) ) )
End Function

Function dot%(x0%,y0%,x1%,y1%,x2%,y2%)
	Return (x1-x0)*(y2-y1)-(x2-x1)*(y1-y0)
End Function

Function PointInPoly%(px%,py%,p#[])
	Local i%=0
	' compare x/y coords with next x/y coords in array
	Repeat
		If dot(p[i+0],p[i+1],p[i+2],p[i+3],px,py)<=0 Return False
		i:+2
	Until i=p.Length-2
	i=p.Length-2
	' compare last x/y coord pair with first
	If dot(p[i+0],p[i+1],p[0],p[1],px,py)>0 Return True
	Return False
End Function


'--------------
' SOLUTION DATA
'--------------
'    NumSolutions,   point1-id, point1-shape-id, point2-id, point2-shape-id ...
DefData 5,            3,0,1,3,   0,2,0,3, 3,3,3,1,   0,0,2,2,   0,1,4,3