kategoria: Blitz
[#1] Astar w BB
Dostałem od kolegi tukinema kod algorytmu szukania najkrótszej drogi (astar) w AMOSie. Użyłem go w pisanej przeze mnie AmiGearsTactics. Teraz gdy przepisuje całość z AMOSa na BB przyszła kolej na astar. Zamieniłem amosowe komendy na te z BB, zrezygnowałem z procedur na rzecz etykiet i podprogramów i na pierwszy rzut oka wszystko wygląda poprawnie jednak nie daje się uruchomić. Wywali mi komunikaty o braku END IF po IF (wskazując IF lub pętle REPEAT). Oczywiście te komendy tam się znajdują i ich ilość i kolejność raczej jest poprawna (pod AMOSem działało). Czy ktoś znający lepiej BB (czyli raczej każdy na tym forum) zechciał mi pomóc i byłby w stanie zlokalizować błąd?

; declare variables
MAPWIDTH=10
MAPHEIGHT=10

; create needed arrays
Dim WALKABILITY(MAPWIDTH,MAPHEIGHT)
Dim OPENLIST(MAPWIDTH*MAPHEIGHT)
Dim OPENX(MAPWIDTH*MAPHEIGHT)
Dim OPENY(MAPWIDTH*MAPHEIGHT)
Dim PARX(MAPWIDTH,MAPHEIGHT)
Dim PARY(MAPWIDTH,MAPHEIGHT)
Dim FCOST(MAPWIDTH*MAPHEIGHT)
Dim GCOST(MAPWIDTH,MAPHEIGHT)
Dim HKOST(MAPWIDTH*MAPHEIGHT)
Dim PATHLENGTH(1)
Dim PATHLOCATION(1)

; declare constants
CONST_ONOPENLIST=1
CONST_ONCLOSEDLIST=2
CONST_ONNEITHERLIST=0
CONST_NOTFINISHED=0
CONST_FOUND=1
CONST_NONEXISTENT=2
CONST_WALKABLE=0
CONST_UNWALKABLE=1

; Main Program
WALKABILITY(0,0)=0 : WALKABILITY(0,1)=0 : WALKABILITY(0,2)=0 : WALKABILITY(0,3)=0
WALKABILITY(1,0)=1 : WALKABILITY(1,1)=0 : WALKABILITY(1,2)=0 : WALKABILITY(1,3)=1
WALKABILITY(2,0)=1 : WALKABILITY(2,1)=1 : WALKABILITY(2,2)=0 : WALKABILITY(2,3)=0

PATHFINDERID=1
STRTX=0
STRTY=0
TARGETX=7
TARGETY=9
NODIAGONAL=True

JSR FINDPATH
Print PATH
PATHFINDERID=1
JSR PATHREAD

End

.FINDPATH

Dim LISTARRAY(MAPWIDTH,MAPHEIGHT)
PATHLENGTH(PATHFINDERID)=CONST_NOTFINISHED
PATHLOCATION(PATHFINDERID)=1

OPENLISTITEMS=1
OPENLIST(1)=1
OPENX(1)=STRTX : OPENY(1)=STRTY
GCOST(STRTX,STRTY)=0

Repeat
If OPENLISTITEMS<>0

PARXVAL=OPENX(OPENLIST(1)) : PARYVAL=OPENY(OPENLIST(1))
LISTARRAY(PARXVAL,PARYVAL)=CONST_ONCLOSEDLIST

OPENLISTITEMS=OPENLISTITEMS-1
OPENLIST(1)=OPENLIST(OPENLISTITEMS+1)
V=1
Repeat
U=V
If 2*U<=OPENLISTITEMS
If FCOST(OPENLIST(U))>=FCOST(OPENLIST(2*U)) : V=2*U : End If
End If
If 2*U+1<=OPENLISTITEMS
If FCOST(OPENLIST(V))>=FCOST(OPENLIST(2*U+1)) : V=2*U+1 : End If
End If
If U<>V
TEMP=OPENLIST(U)
OPENLIST(U)=OPENLIST(V)
OPENLIST(V)=TEMP
Else
Pop Repeat
End If
Until qw=12

For B=PARYVAL-1 To PARYVAL+1
For A=PARXVAL-1 To PARXVAL+1

If A<>-1 AND B<>-1 AND A<>MAPWIDTH AND B<>MAPHEIGHT

If LISTARRAY(A,B)<>CONST_ONCLOSEDLIST

If WALKABILITY(A,B)=CONST_WALKABLE

CORNER=CONST_WALKABLE
If A=PARXVAL-1
If B=PARYVAL-1
If NODIAGONAL
CORNER=CONST_UNWALKABLE
Else
If WALKABILITY(PARXVAL-1,PARYVAL)=CONST_UNWALKABLE OR WALKABILITY(PARXVAL,PARYVAL-1)=CONST_UNWALKABLE

CORNER=CONST_UNWALKABLE
End If
End If
Else If B=PARYVAL+1
If NODIAGONAL
CORNER=CONST_UNWALKABLE
Else
If WALKABILITY(PARXVAL,PARYVAL+1)=CONST_UNWALKABLE OR WALKABILITY(PARXVAL-1,PARYVAL)=CONST_UNWALKABLE

CORNER=CONST_UNWALKABLE
End If
End If
End If
Else If A=PARXVAL+1
If B=PARYVAL-1
If NODIAGONAL
CORNER=CONST_UNWALKABLE
Else
If WALKABILITY(PARXVAL,PARYVAL-1)=CONST_UNWALKABLE OR WALKABILITY(PARXVAL+1,PARYVAL)=CONST_UNWALKABLE

CORNER=CONST_UNWALKABLE
End If
End If
Else If B=PARYVAL+1
If NODIAGONAL
CORNER=CONST_UNWALKABLE
Else
If WALKABILITY(PARXVAL+1,PARYVAL)=CONST_UNWALKABLE OR WALKABILITY(PARXVAL,PARYVAL+1)=CONST_UNWALKABLE

CORNER=CONST_UNWALKABLE
End If
End If
End If
End If
If CORNER=CONST_WALKABLE

If LISTARRAY(A,B)<>CONST_ONOPENLIST
SQUARESCHECKED=SQUARESCHECKED+1
M=OPENLISTITEMS+1
OPENLIST(M)=SQUARESCHECKED
OPENX(OPENLIST(M))=A : OPENY(OPENLIST(M))=B

If Abs(A-PARXVAL)=1 AND Abs(B-PARYVAL)=1
If NODIAGONAL=False
AGCOST=14
Else
AGCOST=150000
End If
Else
AGCOST=10
End If
GCOST(A,B)=GCOST(PARXVAL,PARYVAL)+AGCOST

HKOST(OPENLIST(M))=10*(Abs(A-TARGETX)+Abs(B-TARGETY))
FCOST(OPENLIST(M))=GCOST(A,B)+HKOST(OPENLIST(M))
PARX(A,B)=PARXVAL : PARY(A,B)=PARYVAL

While M<>1
If FCOST(OPENLIST(M))<=FCOST(OPENLIST(M/2))
TEMP=OPENLIST(M/2)
OPENLIST(M/2)=OPENLIST(M)
OPENLIST(M)=TEMP
M=M/2
Else
Pop Repeat
End If
Wend
OPENLISTITEMS=OPENLISTITEMS+1
LISTARRAY(A,B)=CONST_ONOPENLIST

Else

If Abs(A-PARXVAL)=1 AND Abs(B-PARYVAL)=1
If NODIAGONAL=False
AGCOST=14
Else
AGCOST=150000
End If
Else
AGCOST=10
End If
TEMPGCOST=GCOST(PARXVAL,PARYVAL)+AGCOST

If TEMPGCOST<GCOST(A,B)
PARX(A,B)=PARXVAL
PARY(A,B)=PARYVAL
GCOST(A,B)=TEMPGCOST

If LISTARRAY(A,B)=CONST_ONOPENLIST
For X=1 To OPENLISTITEMS
If OPENX(OPENLIST(X))=A AND OPENY(OPENLIST(X))=B
FCOST(OPENLIST(X))=GCOST(A,B)+HKOST(OPENLIST(X))
M=X

While M<>1
If FCOST(OPENLIST(M))<FCOST(OPENLIST(M/2))
TEMP=OPENLIST(M/2)
OPENLIST(M/2)=OPENLIST(M)
OPENLIST(M)=TEMP
M=M/2
Else
Pop Repeat
End If
Wend

Pop Repeat
End If
Next
End If

End If

End If
End If
End If
End If
End If
Next
Next


Else
PATH=CONST_NONEXISTENT : Pop Repeat
End If

If LISTARRAY(TARGETX,TARGETY)=CONST_ONOPENLIST Then PATH=CONST_FOUND : Pop Repeat

Forever


If PATH=CONST_FOUND

PATHX=TARGETX : PATHY=TARGETY
Repeat
TEMPX=PARX(PATHX,PATHY)
PATHY=PARY(PATHX,PATHY)
PATHX=TEMPX
PATHLENGTH(PATHFINDERID)=PATHLENGTH(PATHFINDERID)+1
Until PATHX=STRTX AND PATHY=STRTY
Reserve PATHFINDERID,PATHLENGTH(PATHFINDERID)*4+30
; Reserve As Work PATHFINDERID,PATHLENGTH(PATHFINDERID)*4+30
BANKADDR=Start(PATHFINDERID)
PATHX=TARGETX : PATHY=TARGETY
CELLPOSITION=PATHLENGTH(PATHFINDERID)*4
While NOT(PATHX=STRTX AND PATHY=STRTY)
Poke BANKADDR+CELLPOSITION,PATHX
Poke BANKADDR+CELLPOSITION+2,PATHY
CELLPOSITION=CELLPOSITION-4
TEMPX=PARX(PATHX,PATHY)
PATHY=PARY(PATHX,PATHY)
PATHX=TEMPX
Wend
Poke BANKADDR,STRTX
Poke BANKADDR+2,STRTY
End If
RTS

.PATHREAD
PATHLOCATION(PATHFINDERID)=1
BANKADDR=Start(PATHFINDERID)
While PATHLOCATION(PATHFINDERID)<=PATHLENGTH(PATHFINDERID)
A=Peek(BANKADDR+PATHLOCATION(PATHFINDERID)*4)
B=Peek(BANKADDR+PATHLOCATION(PATHFINDERID)*4+2)
PATHLOCATION(PATHFINDERID)=PATHLOCATION(PATHFINDERID)+1
Print "X:";A;" Y:";B
Wend
Erase PATHFINDERID
RTS

Ostatnia aktualizacja: 29.09.2024 22:49:19 przez cramer
[#2] Re: Astar w BB

@cramer, post #1

Warto by to uprościć. Pamiętaj, że nie piszesz już w Amosie. Nie musisz tworzyć sterty tablic. Masz tu do dyspozycji struktury oraz dynamiczne listy.

Ja pisząc własny algorytm (nie A*, a Dijkstry) musiałem się nauczyć używać list. Wtedy nie korzystałem z gotowego kodu, a sam sobie napisałem. Przykładowo tutaj masz stertę tablic. Wystarczą do tego dwie listy: otwarta i zamknięta.

Ostatnia aktualizacja: 30.09.2024 08:41:10 przez tukinem
[#3] Re: Astar w BB

@cramer, post #1

Nie znam się na BB (poza popełnieniem paru przykładzików), więc się wypowiem :)
Nie mieszaj IF THEN i IF END IF. Ja bym wszędzie użył IF + END IF.

Tak na marginesie: Koszmarnie się to czyta.
2
[#4] Re: Astar w BB

@asman, post #3

Tak na marginesie: Koszmarnie się to czyta.

Faktycznie. Ja się zgubiłem po drugim IFie. :) Jak analizować takie źródła gdy składają się z kilkuset plików i wiele z nich to ponad 1000 linii? szeroki uśmiech
1
[#5] Re: Astar w BB

@asman, post #3

Wystarczy porobić sobie wcięcia w kodzie i ich pilnować. Amos z automatu je tworzył. TED w BB nie ma takiej funkcji.

Można sobie mieszać If...Then z If ... EndIf. Warunkiem jest to, żeby If...Then...Else trzymać w jednej linii. Wtedy się nie pogubimy.

@cramer: przerobię Ci ten kod, ale nie będę zmieniać tablic na listy. Do tego sam będziesz musiał dojrzeć ;)

1 rada: stałe istnieją w Blitz Basic i nie tworzy się przez CONST_STALA = 0, tylko przez #STALA = 0. To co zrobiłeś to ci wyszły zmienne.
2 rada: Blitz Basic to nie C. Tu nie ma End If, tylko jest EndIf.
3 rada: Blitz Basic to nie E. Tu nie ma Else If, tylko jest osobno Else : If : EndIf.

Oprócz tego: POP REPEAT. Nie wiem co to jest i nie wiem, jak się zachowa w BB. Przepiszę Ci kod tak, jak ma być, aby się uruchomiło.

Ostatnia aktualizacja: 30.09.2024 11:49:56 przez tukinem
[#6] Re: Astar w BB

@cramer, post #1

Po mojemu tu brakuje czegoś.

BB nie ma funkcji Reserve, tylko odbywa się to przez AllocMem, bądź AllocMem_. To dwie działające prawie tak samo funkcje alokujące pamięć, ale nigdy ich nie mieszaj ze zwalnianiem pamięci przez FreeMem i FreeMem_. Radzę używać tych z podkreśleniem. One nie pochodzą z Blitz Basic, a są funkcjami systemowymi. Składnię mają tę samą, a działanie w 90% podobne.

Na ile udało mi się, na tyle Ci to zrobiłem. Przypatrz się, jak sobie można to ułatwić.

; declare variables
MAPWIDTH=10
MAPHEIGHT=10

; create needed arrays
Dim WALKABILITY(MAPWIDTH,MAPHEIGHT)
Dim OPENLIST(MAPWIDTH*MAPHEIGHT)
Dim OPENX(MAPWIDTH*MAPHEIGHT)
Dim OPENY(MAPWIDTH*MAPHEIGHT)
Dim PARX(MAPWIDTH,MAPHEIGHT)
Dim PARY(MAPWIDTH,MAPHEIGHT)
Dim FCOST(MAPWIDTH*MAPHEIGHT)
Dim GCOST(MAPWIDTH,MAPHEIGHT)
Dim HKOST(MAPWIDTH*MAPHEIGHT)
Dim PATHLENGTH(1)
Dim PATHLOCATION(1)

; declare constants
#ONOPENLIST=1
#ONCLOSEDLIST=2
#ONNEITHERLIST=0
#NOTFINISHED=0
#FOUND=1
#NONEXISTENT=2
#WALKABLE=0
#UNWALKABLE=1

; Main Program
WALKABILITY(0,0)=0 : WALKABILITY(0,1)=0 : WALKABILITY(0,2)=0 : WALKABILITY(0,3)=0
WALKABILITY(1,0)=1 : WALKABILITY(1,1)=0 : WALKABILITY(1,2)=0 : WALKABILITY(1,3)=1
WALKABILITY(2,0)=1 : WALKABILITY(2,1)=1 : WALKABILITY(2,2)=0 : WALKABILITY(2,3)=0

PATHFINDERID=1
STRTX=0
STRTY=0
TARGETX=7
TARGETY=9
NODIAGONAL=True

JSR FINDPATH
Print PATH
PATHFINDERID=1
JSR PATHREAD

End

.FINDPATH

Dim LISTARRAY(MAPWIDTH,MAPHEIGHT)
PATHLENGTH(PATHFINDERID)=#NOTFINISHED
PATHLOCATION(PATHFINDERID)=1

OPENLISTITEMS=1
OPENLIST(1)=1
OPENX(1)=STRTX : OPENY(1)=STRTY
GCOST(STRTX,STRTY)=0

Repeat
If OPENLISTITEMS<>0

PARXVAL=OPENX(OPENLIST(1)) : PARYVAL=OPENY(OPENLIST(1))
LISTARRAY(PARXVAL,PARYVAL)=#ONCLOSEDLIST

OPENLISTITEMS=OPENLISTITEMS-1
OPENLIST(1)=OPENLIST(OPENLISTITEMS+1)
V=1
Repeat
U=V
If 2*U<=OPENLISTITEMS
	If FCOST(OPENLIST(U))>=FCOST(OPENLIST(2*U)) : V=2*U : EndIf
EndIf
If 2*U+1<=OPENLISTITEMS
	If FCOST(OPENLIST(V))>=FCOST(OPENLIST(2*U+1)) : V=2*U+1 : EndIf
EndIf
If U<>V
TEMP=OPENLIST(U)
OPENLIST(U)=OPENLIST(V)
OPENLIST(V)=TEMP
Else
Pop Repeat
EndIf
Until qw=12

For B=PARYVAL-1 To PARYVAL+1
	For A=PARXVAL-1 To PARXVAL+1
		If A<>-1 AND B<>-1 AND A<>MAPWIDTH AND B<>MAPHEIGHT
			If LISTARRAY(A,B)<>#ONCLOSEDLIST
				If WALKABILITY(A,B)=#WALKABLE
					CORNER=#WALKABLE
					If A=PARXVAL-1
						If B=PARYVAL-1
							If NODIAGONAL
								CORNER=#UNWALKABLE
							Else
								If WALKABILITY(PARXVAL-1,PARYVAL)=#UNWALKABLE OR WALKABILITY(PARXVAL,PARYVAL-1)=#NWALKABLE
									CORNER=#UNWALKABLE
								EndIf
							EndIf
						Else 
							If B=PARYVAL+1
								If NODIAGONAL
									CORNER=#UNWALKABLE
								Else
									If WALKABILITY(PARXVAL,PARYVAL+1)=#UNWALKABLE OR WALKABILITY(PARXVAL-1,PARYVAL)=#UNWALKABLE
										CORNER=#UNWALKABLE
									EndIf
								EndIf
							EndIf
						Else
							If A=PARXVAL+1
								If B=PARYVAL-1
									If NODIAGONAL
										CORNER=#UNWALKABLE
									Else
										If WALKABILITY(PARXVAL,PARYVAL-1)=#UNWALKABLE OR WALKABILITY(PARXVAL+1,PARYVAL)=#UNWALKABLE
											CORNER=#UNWALKABLE
										EndIf
									EndIf
								Else
									If B=PARYVAL+1
										If NODIAGONAL
											CORNER=#UNWALKABLE
										Else
											If WALKABILITY(PARXVAL+1,PARYVAL)=#UNWALKABLE OR WALKABILITY(PARXVAL,PARYVAL+1)=#UNWALKABLE
												CORNER=#UNWALKABLE
											EndIf
										EndIf
									EndIf
								EndIf
								If CORNER=#WALKABLE
									If LISTARRAY(A,B)<>#ONOPENLIST
										SQUARESCHECKED=SQUARESCHECKED+1
										M=OPENLISTITEMS+1
										OPENLIST(M)=SQUARESCHECKED
										OPENX(OPENLIST(M))=A : OPENY(OPENLIST(M))=B
										If Abs(A-PARXVAL)=1 AND Abs(B-PARYVAL)=1
											If NODIAGONAL=False
												AGCOST=14
											Else
												AGCOST=150000
											EndIf
										Else
											AGCOST=10
										EndIf
										GCOST(A,B)=GCOST(PARXVAL,PARYVAL)+AGCOST
										HKOST(OPENLIST(M))=10*(Abs(A-TARGETX)+Abs(B-TARGETY))
										FCOST(OPENLIST(M))=GCOST(A,B)+HKOST(OPENLIST(M))
										PARX(A,B)=PARXVAL : PARY(A,B)=PARYVAL
										While M<>1
											If FCOST(OPENLIST(M))<=FCOST(OPENLIST(M/2))
												TEMP=OPENLIST(M/2)                  ; MOZNA ZAMIENIC NA TEMP=OPENLIST(M LSR 1)
												OPENLIST(M/2)=OPENLIST(M)
												OPENLIST(M)=TEMP
												M=M/2 								; MOZNA ZAMIENIC NA M = M LSR 1
											Else
												Pop Repeat 							; CO TO JEST? NIE WIEM
											EndIf
										Wend
										OPENLISTITEMS=OPENLISTITEMS+1
										LISTARRAY(A,B)=#ONOPENLIST
									Else
										If Abs(A-PARXVAL)=1 AND Abs(B-PARYVAL)=1
											If NODIAGONAL=False
												AGCOST=14
											Else
												AGCOST=150000
											EndIf
										Else
											AGCOST=10
										EndIf
										TEMPGCOST=GCOST(PARXVAL,PARYVAL)+AGCOST
										If TEMPGCOST<GCOST(A,B)
											PARX(A,B)=PARXVAL
											PARY(A,B)=PARYVAL
											GCOST(A,B)=TEMPGCOST
											If LISTARRAY(A,B)=#ONOPENLIST
												For X=1 To OPENLISTITEMS
													If OPENX(OPENLIST(X))=A AND OPENY(OPENLIST(X))=B
														FCOST(OPENLIST(X))=GCOST(A,B)+HKOST(OPENLIST(X))
														M=X
														While M<>1
															If FCOST(OPENLIST(M))<FCOST(OPENLIST(M/2))
																TEMP=OPENLIST(M/2)  		; TEMP = OPENLIST(M LSR 1)
																OPENLIST(M/2)=OPENLIST(M)	; OPENLIST (M LSR 1) = OPENLIST (M)
																OPENLIST(M)=TEMP
																M=M/2						; M = M LSR 1
															Else
																Pop Repeat
															EndIf
														Wend
														Pop Repeat
													EndIf
												Next
											EndIf
										EndIf
									EndIf
								EndIf
							EndIf
						EndIf
					EndIf
				Next
			Next
		Else
			PATH=#NONEXISTENT
			Pop Repeat
		EndIf
		If LISTARRAY(TARGETX,TARGETY)=#ONOPENLIST Then PATH=#FOUND
			Pop Repeat
			Forever
			If PATH=#FOUND
				PATHX=TARGETX : PATHY=TARGETY
				Repeat
					TEMPX=PARX(PATHX,PATHY)
					PATHY=PARY(PATHX,PATHY)
					PATHX=TEMPX
					PATHLENGTH(PATHFINDERID)=PATHLENGTH(PATHFINDERID)+1
				Until PATHX=STRTX AND PATHY=STRTY
				Reserve PATHFINDERID,PATHLENGTH(PATHFINDERID)*4+30                  ; PATHFINERID.l = AllocMem_ (PATHLENGTH(PATHFINDERID) LSL 2 +30 , 0)
				; Reserve As Work PATHFINDERID,PATHLENGTH(PATHFINDERID)*4+30
				BANKADDR=Start(PATHFINDERID)
				PATHX=TARGETX : PATHY=TARGETY
				CELLPOSITION=PATHLENGTH(PATHFINDERID)*4                             ; CELLPOSITION=PATHLENGTH(PATHFINDERID) LSL 2
				While NOT(PATHX=STRTX AND PATHY=STRTY)
					Poke BANKADDR+CELLPOSITION,PATHX
					Poke BANKADDR+CELLPOSITION+2,PATHY
					CELLPOSITION=CELLPOSITION-4
					TEMPX=PARX(PATHX,PATHY)
					PATHY=PARY(PATHX,PATHY)
					PATHX=TEMPX
				Wend
				Poke BANKADDR,STRTX
				Poke BANKADDR+2,STRTY
			EndIf
			
	; CO DALEJ???
	
RTS

.PATHREAD
PATHLOCATION(PATHFINDERID)=1
BANKADDR=Start(PATHFINDERID)
While PATHLOCATION(PATHFINDERID)<=PATHLENGTH(PATHFINDERID)
	A=Peek(BANKADDR+PATHLOCATION(PATHFINDERID)*4)
	B=Peek(BANKADDR+PATHLOCATION(PATHFINDERID)*4+2)
	PATHLOCATION(PATHFINDERID)=PATHLOCATION(PATHFINDERID)+1
	Print "X:";A;" Y:";B
Wend
Erase PATHFINDERID
RTS
[#7] Re: Astar w BB

@cramer, post #1

No ten kod wygląda znajomo
Wywali mi komunikaty o braku END IF po IF

Niestety nie znam się na BB, ale skoro wywala takie błędy, to prawdopodobnie któryś If jest niedomknięty lub jest ich za dużo. Jest informacja w której linii występuje błąd?

zrezygnowałem z procedur na rzecz etykiet i podprogramów

Można wiedzieć dlaczego? Czy są to jakieś kwestie związane z wydajnością? BB ma swój odpowiednik procedur? W przypadku przejścia na gosub / goto trzeba się upewnić czy wszystkie zmienne które były lokalne dla procedury nadal znajdują się w programie i czy mają sens.
Osobiście AMOSa nie używałem już ponad 2 lata i szczerze nie zamierzam do niego wracać jak i do jakiegokolwiek BASICa, ale akurat procedury były jedną z rzeczy w miarę przypominających współczesne programowanie i użycie zamiast nich gosub/goto to jak dla mnie cofanie się wstecz.
[#8] Re: Astar w BB

@diobou, post #7

Ja 30 lat temu jak przesiadłem sie z basica w C64 na AMOSa to procedury były najważniejszą zmianą na plus. Ale w BB wchodzi kwestia zmiennych globalnych - lokalnych w procedurach i akurat w tym przypadku lepiej jak wszystkie są lokalne, więc procedury straciły sens. DO tego sama obsługa procedur (że muszą być na początku kodu itd) sprawiły, że zdecydowałem się na podprogramy, które przecież działają podobnie jeśli wszystkie zmienne są lokalne.
[#9] Re: Astar w BB

@cramer, post #8

zdecydowałem się na podprogramy, które przecież działają podobnie jeśli wszystkie zmienne są lokalne.

Chyba miałeś na myśli "globalne".

Ostatnia aktualizacja: 07.10.2024 09:36:43 przez tukinem
1
[#10] Re: Astar w BB

@tukinem, post #9

Tzn jak nie ma procedur to wszystkie zmienne są lokalne i nic nie trzeba przełączać na globalne (widoczne dla procedur). Ale zwał jak zwał. Ważne, że działa.
[#11] Re: Astar w BB

@cramer, post #10

W Blitz Basic nie zmiennych globalnych. W kodzie głównym wszystkie zmienne są lokalne. Jeśli tworzysz statement (procedurę), czy funkcję, to możesz mieć dostęp do zmiennej albo przez SHARED, albo jeśli sobie w parametrze procedury wstawisz wskaźnik do tej zmiennej

ZMIENNA.b = 100

Statement ZWIEKSZ_O_1{wskaznik.l}
   A.b = Peek.b(wskaznik)
   A = A+1
   Poke.b wskaznik,A
End Statement



ZWIEKSZ_O_1 {&ZMIENNA}

NPrint ZMIENNA
[#12] Re: Astar w BB

@tukinem, post #6

Pytałeś o "Pop Repeat". To jest wyjście z pętli WHILE - WEND, REPEAT -UNTIL itd... tak przynajmniej wyczytałem
[#13] Re: Astar w BB

@tukinem, post #6

no niestety nie działa
komunikat... IF without END IF
[#14] Re: Astar w BB

@cramer, post #13

Masz gdzieś niedomknięty warunek. Brakuje endifa
[#15] Re: Astar w BB

@cramer, post #12

Wyskok z pętli w Amosie to była komenda Exit jak dobrze pamiętam.

Tu nie ma ale jest na to sposób.

For a=0 to 10
   a=11 ; wyskok z petli
Next
[#16] Re: Astar w BB

@cramer, post #13

Czyli klasyka, wciąż nie działa. Proponuje taktykę: dziel i rządź (Divide-and-conquer). Innymi słowy, dzielisz kod na mniejsze kawałki i kompilujesz aż w końcu będzie wiadomo gdzie był błąd.

Chociaż ja to bym zaczął od refaktoryzacji, w tym przypadku wydzieliłbym procedury z kodu. Zacząłbym od najbardziej wewnętrznych ifów i przenosił do osobnych procedur.
Oczywiście refaktoryzacja nie oznacza że kod będzie tak samo szybki jak był poprzedni, żeby nie było. Będzie wolniejszy. Ale ja wolę by działał prawidłowo a dopiero na końcu robił optymalizację o ile to tu jest pies pogrzebany. A Zrobisz jak będziesz chciał :)
[#17] Re: Astar w BB

@asman, post #16

Ja bym napisał po swojemu taki kod, ale na miarę Blitz Basic. Jest o wiele prościej używając struktur i list. Nigdy do końca nie szukałem najkrótszej drogi, a jedynie przerywałem dalsze szukanie, jeśli znalazłem pierwszą możliwą drogę. Kod ten mogę tu udostępnić, jest on zapisany jako funkcja i zwraca łańcuch np: "GGDLP", czyli góra, góra, dół, lewo, prawo. Nie jest uniwersalny, działa tylko w czterech kierunkach (brak ruchów na ukos). Omija zgrabnie ściany w tablicy. No i jest 2 razy krótszy od tego z Amosa jak dobrze pamiętam.
[#18] Re: Astar w BB

@cramer, post #8

DO tego sama obsługa procedur (że muszą być na początku kodu itd)

Nie wiem jak w Blitzu, ale w AMOSie nie muszą być na początku, właśnie najlepiej dać je na koniec, żeby mieć porządek. Dodatkowo można je fajnie zwinąć, przez co widzimy jedynie nagłówki, bez konieczności zagłębiania się w implementację. W głównym kodzie jedynie wywołujemy to, co trzeba, przez co główna pętla nie musi być dluga na kilometr.
Jednym z największych problemów AMOSa jest słaby kompilator, przez co takie procedury mogą działać wolniej niż powinny i rzeczywiście wydajniejsze może być zastosowanie gosubów.
Co nie znaczy że takie podejście jest optymalne z punktu widzenia przejrzystości kodu.
Myślę, że tutaj jimi mógłby powiedzieć coś więcej, osobiście nie porównywałem wydajności procedur vs subrutyn, nie miałem na tyle odwagi.

@cramer a jaka to w ogóle jest wersja Blitza? Bo widzę że jest kilka.

Ostatnia aktualizacja: 08.10.2024 21:36:05 przez diobou
[#19] Re: Astar w BB

@diobou, post #18

I ten kod naprawdę bardzo fajnie działał w AMOSie.
Piszę pod BB 2.10
[#20] Re: Astar w BB

@diobou, post #18

Używa tego co ja, czyli Ultimate Blitz Basic 2.1.

W BB tak jest właśnie, że procedury i funkcje muszą się znaleźć w kodzie przed ich wywołaniem. Mało tego. Trzeba im zachować zgodność z trybem AMIGA / BLITZ.
Np.: piszemy grę w trybie BLITZ (niesystemowym). Piszemy na początku kodu procedurkę blitującą. Dopóki nie przejdziemy w tryb BLITZ, kod działa w trybie AMIGA (systemowym) i jeśli w tym trybie znajdzie się procedura, a wywołamy ją w innym trybie, to wywali błąd typu: "this command is only avaible in AMIGA mode".

Można sobie stworzyć osobny plik z samymi procedurami i funkcjami, a potem dodać go do kodu głównego poprzez Include. Nie polecam jednak takiego zabiegu z własnego doświadczenia. Jeśli znajdzie się jakiś błąd w kodzie od procedur, to debugger wyświetli jedynie błąd przy Include, a nie konkretne miejsce w pliku zewnętrznym.

Procedury są dobre, bo zmniejszają rozmiar pliku exe, jeśli powtarzamy kilkukrotnie te same sekwencje kodu. Nie wiem jak z szybkością, ale sprawdzałem funkcje i okazuje się że potrafią nieźle spowalniać.

@cramer: jeśli dajesz sobie radę z JSR...RTS, to jak najbardziej używaj ich.
[#21] Re: Astar w BB

@tukinem, post #15

Kiedyś pisałem jakieś makro w Excelu w języku VBA i było można przerwać pętlę for. Teraz to już dokładnie nie pamiętam jakie to było polecenie. W Amosie sprawdziłem i polecenie Exit działa, przerywa pętlę. W innych językach też się da przerwać pętlę. Jak dobrze pamiętam to w C będzie polecenie break (może mylić mnie pamięć, bardzo rzadko stosuje się), można inne kombinacje sprawdzić takie jak: exit for, end for, end coś w tym stylu.
[#22] Re: Astar w BB

@Alkomiga, post #21

Tak, w C jest to break i wcale nie tak rzadko się to stosuje, a z tego co znalazłem to w Blitzu powinno zadziałać Pop lub Pop For.

Ostatnia aktualizacja: 09.10.2024 22:12:24 przez diobou
[#23] Re: Astar w BB

@cramer, post #1

TUTAJ opublikowałem kod algorytmu, który napisałem.

Pobierać, testować, korzystać do woli
[#24] Re: Astar w BB

@tukinem, post #23

Zdolny jestes. Nie wiem czy bym w ASM napisal cos podobnego.
Ogolnie, zeby to bylo w miare szybkie to bym pewnie przydzielil bajty dodatnie od 0 do 127 na pola przez, ktore nie mozna przechodzic.
0 (zero) to by byla sciana, przez ktora nie mozna przechodzic.
A bajty ujemne od 128 do 255, na pola przez, ktore mozna przechodzic.
Otoczylbym cala plansze/mape zerami, zeby nie sprawdzac rozmiaru planszy/mapy.
Czyli z planszy/mapy 100x100 byloby 102x102.
Wyliczylbym najpierw ile wynosi minimalna ilosc pol pomiedzy startem i meta, zeby nie liczyc dalej jak sie osiagnie taka wartosc.
Najpewniej bym mial kopie planszy/mapy w pamieci na ktorej bym zaznaczal droge.
Nie wiem czy ruch po skosach jest uwzgledniany, bo wtedy jest trudniej, ale moze byc krocej.
Problematyczna bylaby tez pewnie sytuacja, gdy nie ma drogi pomiedzy startem i meta, bo cos ja blokuje.
Tyle mojej wstepnej teorii, ale to dalej bardzo duzo roboty by bylo, byc moze trzeba by zmienic niektore moje zalozenia.
[#25] Re: Astar w BB

@Don_Adan, post #24

Tam w kodzie u mnie jest małe niedociągnięcie. Okazuje się, że błąd jest w drugim etapie, gdy idziemy o jedno pole w lewo lub w górę, to wywala brak pozycji w liście. Już to poprawiłem i dzisiaj to wrzucę.

No kod nie jest szybki. Na 020 z cycle exact i fast ram taką drogę przez całą planszę szukał przez 114 ramek czyli troszkę ponad 2 sekundy. Gdy odpaliłem ten kod w AmiBlitz, wynik to już było 135 ramek.

Po kompilacji odpaliłem na 68000 7MHz cycle exact bez fast ramu i wynik był 178, czyli już 3,5 sekundy. Bardzo długo moim zdaniem. Do konkretnej gry trzeba by go odpowiednio ulepszać.

Zrobiłem podobnie jak myślisz, ale na identycznej mapie. W 2 etapie sprawdzam dookoła startu pierwsze pola i dodaję do listy. W 3 etapie sprawdzam każde pole dookoła, dodaję do zmiennej dist 1 i umieszczam kolejne wartości w liście. W 4 etapie szukam najkrótszej drogi, a jeśli znajdę pole o większym dist (od dystansu), to wtedy usuwam pole z listy i jadę od początku.

Ostatnia aktualizacja: 20.10.2024 07:50:40 przez tukinem
[#26] Re: Astar w BB

@tukinem, post #25

Ja to juz stary jestem, i nie chce mi sie wymyslac.
Pewnie gdyby bylo to do gry, to poszedlbym po najmniejszej linii oporu.
Czyli to sam gracz ma kierowac i omijac przeszkody.
Czyli jak na drodze jest przeszkoda to gracz sie na niej zatrzymuje i sam musi ja obejsc.
Proste i szybkie w dzialaniu.

Ostatnia aktualizacja: 21.10.2024 18:22:40 przez Don_Adan
[#27] Re: Astar w BB

@Don_Adan, post #26

Gracz tak, ale jeśli piszesz ruchy dla komputera, to już wtedy sekwencję ruchów trzeba zaplanować.

Szkoda że tego algorytmu nie napisałem rok temu, bo bym go do Sołtysa zaprzęgnął i można by wtedy sterować podobnie do wersji PC bo tam mapa jest podzielona na komórki chyba 4x4 pikele albo 8x8.

Ciekawi mnie jak długo by ten algorytm liczył drogę na mapie 100x100 kafli ;) trzeba będzie potestować...
[#28] Re: Astar w BB

@tukinem, post #27

Zalezy do jakiej gry.
Komputer tez moze sie np. czaic za skala.
Poza tym zwykle sa tez punkty ruchu gracza/komputera.
No i cala mapa nie musi byc widoczna od razu.
Wiec mozna sie przesuwac powiedzmy co 10 pol.
A po natrafieniu na przeszkode po prostu obejsc ja.
W przypadku znajdywania/wybierania najkrotszej drogi przez komputer z automatu.
To komputer bedzie mial wtedy przewage nad czlowiekiem.
[#29] Re: Astar w BB

@Don_Adan, post #28

Oto test na mapie 32x32 na 68000 cycle exact ECS 2MB chip RAM bez fastu:


Około 117 sekund, a ten wynik nie jest wyświetlony w całości, bo ekranu brakło

Przypomniały mi się czasy Heroes of Might and Magic na MS DOSie po kliknięciu "END TURN" :D

Dalsze testy:

AMIGA 1200 bez fastu: 3485 VWaitów
AMITA 1200 z fastem: 1147 VWaitów

Ostatnia aktualizacja: 21.10.2024 19:12:09 przez tukinem
[#30] Re: Astar w BB

@tukinem, post #29

jako przyszly programista BlitzBasica z gory dzieki OK

Pathfinder to absolutnie niezbedna procedurka do napisania jakiejkolwiek strategii, rpg'a czy nawet niektorych gier arcade. Dziwie sie, ze na EAB nie ma zadnego odzewu za ten niesamowicie uzyteczny programik.
1
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem