Type in a type

Blitz3D Forums/Blitz3D Beginners Area/Type in a type

(tu) ENAY(Posted 2005) [#1]
Heh. I've got more silly type problems.
I can't figure out the syntax for creating a type within a type.
I'm trying something like this:-

Type badger
field var
End Type

Type sheep
field var2
End Type

s\sheep = new sheep

s\var2.badger = new badger

Basically I want multiple badgers inside a sheep. Can someone please assist? :)


GitTech(Posted 2005) [#2]
Type sheep 
     field var2.badger
End Type



(tu) ENAY(Posted 2005) [#3]
> field var2.badger

AAAAAAAAAARRGGGGGGGGH!!!!!!! It's always so obvious when someone shows you.

Thanks very much GitTech. That's a great help :)


(tu) ENAY(Posted 2005) [#4]
EEK!

Ok, I've got even more
Or perhaps I'm totally misusing the reason for types.

Well ok. I'm got my badgers inside my sheep.
Trouble is when I create two sheeps any new badgers that I create appear in both sheep instances. Infact no matter where I create badgers in my entire program, they all appear in

I'm basically trying to do something like this

       |- badger1
       |
sheep1 --- badger2
       |
       |- badger3


       |- badger4
       |
sheep2 --- badger5
       |
       |- badge6


At the moment it's like this:-
       |- badger1
       |
sheep1-| badger2
       |
       |- badger3
       |
       |- badger4
       |
sheep2-|- badger5
       |
       |- badge6


Also I can't create any badgers at all inside functions, only globally otherwise it tells me off for using my type incorrectly.

So I can't do b\sheep.badger = new badger

What in the hell is going wrong? I am so thick! HELP ME!! :)


GitTech(Posted 2005) [#5]
Type badger 
	Field var 
	Field sheepFlag
End Type 

Type sheep 
	Field var2.badger
End Type 

global sheep1.sheep = New sheep 

sheep1\var2.badger = New badger
sheep1\var2\sheepFlag=1

sheep1\var2.badger = New badger
sheep1\var2\sheepFlag=1

sheep1\var2.badger = New badger
sheep1\var2\sheepFlag=1




global sheep2.sheep = New sheep 

sheep2\var2.badger = New badger
sheep2\var2\sheepFlag=2

sheep2\var2.badger = New badger
sheep2\var2\sheepFlag=2

sheep2\var2.badger = New badger
sheep2\var2\sheepFlag=2


For b.badger=Each badger
	If b\sheepFlag=1 Then 
		;do something
	EndIf
Next

For b.badger=Each badger
	If b\sheepFlag=2 Then 
		;do something
	EndIf
Next



(tu) ENAY(Posted 2005) [#6]
Hi again GitTech. Just looking at your code, I'm guessing that it's impossible to prevent merging types within types? Just like C++ objects


GitTech(Posted 2005) [#7]
No, afaik, every type is ONE big list. So, with your types, you have two lists: a "sheep" list, and a "badger" list.


NewtSoup(Posted 2005) [#8]
You can do exactly what you are trying to do. Heres an example now. I have made a flock of 3 sheep (an array) and each sheep contains exactly 3 distinct badgers
Dim flock.sheep(3)
Type sheep
	Field b1.badger
	Field b2.badger
	Field b3.badger
End Type

Type badger
	Field name$
End Type

Function makeBadger.badger()
	Local name$
	Read name$
	b.badger=New badger
	b\name=name	
	Return b
End Function

Function makeSheep.sheep()
	s.sheep=New sheep
	s\b1=makeBadger()
	s\b2=makeBadger()
	s\b3=makeBadger()
	Return s
End Function

Function initFlock()
	Restore names
	For f=1 To 3
		flock(f)=makeSheep()
	Next
End Function

Function describeFlock()

	For f= 1 To 3
		out$="Sheep"+f+" ("+flock(f)\b1\name+","+flock(f)\b2\name+","+flock(f)\b3\name+")"
		Print out$
	Next
End Function

initFlock()
describeFlock()
WaitKey

.names
Data "Ralph","Oswald","Brian","Gertrude","Emily","Frank","William","Sharon","Barry"


hope this helps :)


NewtSoup(Posted 2005) [#9]
You cant do

sheep\b1.badger = new badger

because if your sheep is

Type sheep
Field b1
field b2
Field b3
End type

you have already declared b1 to be an int

if however the fields were
Field b1.badger

you still cant do that because you have already declared the field type to be a badger and therefore dont need to
*edit* oh apparently you can becuase gitTechs code does exactly that, however you dont need to */edit*
the correct syntax in this instance would be

sheep\badger = new badger
(because the compiler already knows that sheep contain badgers)

Types can quite happily be created inside functions as I have already demonstrated and you dont need to rely on the internal lists of types provided by blitz

my code above is quite elaborate but its like that to show you that you can reduce the main program to just a few function calls. Yes, I am breaking my own rules on "good form here" (posted in another thread) but umm who in the world strictly practices what they preach :D


NewtSoup(Posted 2005) [#10]
Final Word


Basically I want multiple badgers inside a sheep. Can someone please assist? :)



You're very strange. Good work.


(tu) ENAY(Posted 2005) [#11]
Thanks LukeSkywalker,

That's a great help.
I have discovered that I could have an array of badgers inside each sheep, which is kind of what I'm trying to get away from.
I don't want to have any arrays at all if I can help it. But I will look at your code and I shall be having a right old fiddle with it this morning.

> You're very strange.

Thanks :)

> Bannana

Banana! ;)


GitTech(Posted 2005) [#12]
Try this:

Type badger 
	Field var 
	Field nextBadger.badger
End Type 

Type sheep 
	Field firstBadger.badger
	Field lastBadger.badger
End Type 


Function AddBadger.badger(sheep.sheep)
	badger.badger=New badger
	
	If sheep\firstBadger=Null Then
		sheep\firstBadger=badger
	Else
		sheep\lastBadger\nextBadger=badger
	EndIf
	sheep\lastBadger=badger
	
	Return badger
End Function


sheep1.sheep=New sheep
newbadger.badger=AddBadger(sheep1)
newbadger.badger=AddBadger(sheep1)
newbadger.badger=AddBadger(sheep1)


sheep2.sheep=New sheep
newbadger.badger=AddBadger(sheep2)
newbadger.badger=AddBadger(sheep2)
newbadger.badger=AddBadger(sheep2)


currentBadger.badger=sheep1\firstBadger
While currentBadger<>Null
	;do something
	currentBadger=currentBadger\nextBadger
Wend


currentBadger.badger=sheep2\firstBadger
While currentBadger<>Null
	;do something
	currentBadger=currentBadger\nextBadger
Wend



NewtSoup(Posted 2005) [#13]
Enay Please do because Im not using an array within a type :)

I simply used an array to make a "flock" of sheep

However look at gittechs code.. you could mod that to have a linked list of sheep each containing 3 badgers

although, GitTech, you dont need to keep doig newbadger.badger= after declaring newbadger as a type badger also why return the badger when you pass in a sheep to store the reference anway and then never use the return value ("because you can" is an acceptable answer, its possible you may which to simultaneously store and return a reference to the last badger created)


GitTech(Posted 2005) [#14]
Because you can :P


NewtSoup(Posted 2005) [#15]
Dont be afraid of arrays tho enay, arrays can be your friend even if they do have to be global and fixed size. But no not a lot of use for storing an arbitraty number of objects at runtime. For that a linked list is far more useful.

Hope Marc isnt offended by this but I have some old LL code too with loads of convenience functions added.
it was written for someone trying to create a card game but Im sure you will see how it can be adapted ( change deck to sheep and your halfway there)

Type element
	Field value
	Field linkedelement.element
	;add in any other data you feel is necessary
End Type

Type list
	Field Total
	Field start.element
	Field finish.element
End Type

Function prependList(elmnt.element, lst.list)
	
		elmnt\linkedelement=lst\start
		lst\start=elmnt
		If lst\Total=0 Then lst\finish=elmnt
		lst\Total=lst\Total+1
End Function

Function appendList(elmnt.element,lst.list)
		If lst\Total=0
			lst\start=elmnt
		Else
			lst\finish\linkedElement=elmnt
		End If
		lst\finish=elmnt
		lst\Total=lst\Total+1

End Function


Function insertElement( elmnt.element,lst.list,index)
	Local current.element=lst\start
	;if we are adding the element at position 1 then we need to change the
	;list's starting element
	If index<=1 Then
		prependList(elmnt,lst)

	Else If index>lst\Total
		appendList(elmnt,lst)
	Else
		;iterate through the list untill we reach
		;the position _before_ we want to insert the element
		For f=2 To index-1
			current=current\linkedelement
		Next
		;insert the element into the list
		elmnt\linkedelement=current\linkedelement
		current\linkedelement=elmnt
		lst\Total=lst\Total+1
	End If
	
End Function

Function removeElementFromList.element(lst.list,index)
	Local current.element=lst\start
	Local previous.element
	count=1
	While count < index
		previous=current
		current=current\linkedelement
		count=count+1
	Wend

	;special case if the element is the starting element of the deck
	If current=lst\start Then
		;set the start element of the list to the element
		lst\start=current\linkedelement
		lst\Total=lst\Total-1
	Else
		;make the previous element in the list link to the element which the current element links to
		previous\linkedelement=current\linkedelement
		;break the chain on the current element to stop cross linking, this is now an orphaned element
		current\linkedelement=Null
		lst\Total=lst\Total-1
	End If

	;return the element we have just removed
	Return current

End Function
 
Function shuffleList(lst1.list)
	;create a temporarly linked list to use as a holder
	Local lst2.list=New list
	;take a random element from lst1 and and put it at the start of lst2
	;keep doing this untill lst1 is empty
	While lst1\Total >0
		insertElement(removeelementFromList(lst1,Rand(1,lst1\Total)),lst2,1)
	Wend
	;now do it again but the other way around
	While lst2\Total >0
		insertElement(removeelementFromList(lst2,Rand(1,lst2\Total)),lst1,1)
	Wend
	;lst 1 is now shuffled
	
End Function


;this is just a convenient way of viewing the whole list and its contents
;best only use it with short lists as long ones will be wider than the screen
Function showlist$(lst.list)
	ret$="("+lst\Total+" elements) Values {"
	elmnt.element=lst\start
	ret=ret+elmnt\value
	While elmnt\linkedelement<>Null
		elmnt=elmnt\linkedelement
		ret=ret+","+elmnt\value
	Wend
	ret=ret+"}"
	Return ret
End Function

;****************   TEST CODE ****************************************
Graphics 800,600,32,2
deck.list=New list

Print "Creating 10 elements and adding them to the list"
Print
For f=1 To 20
	c.element=New element
	c\value=f
	insertElement(c,deck,-100)
Next

Print "List is now: "+ showlist(deck)
Print
Print "Removing element with index 3"
Print
removed.element=removeelementFromlist(deck,3)

Print "Removed element's value is: "+ removed\value
Print
Print "List is now: "+showlist(deck)
Print
Print "Adding the removed element back in at index 7"
Print
insertElement(removed,deck,7)
Print "List is now: "+showlist(deck)
Print
Print "Shuffling list"
Print
shuffleList(deck)
Print "List is now: "+showlist(deck)

WaitKey

;*********************************************************************




Stevie G(Posted 2005) [#16]
A bit ot .. but check this out ...

www.badgerbadgerbadger.com


GitTech(Posted 2005) [#17]

Hope Marc isnt offended by this but I have some old LL code too with loads of convenience functions added.



No problemo Luke :)


(tu) ENAY(Posted 2005) [#18]
Thanks for all the help guys. I think I'm starting to get my head around this stuff.

> Dont be afraid of arrays tho enay, arrays can be your
> friend even if they do have to be global and fixed size.

That's the thing, I'm the array master. I love them. My last 5 blitz games have all been created using arrays.
But I felt like having a go with types for a change since I've recently mastered the art of OOP in C++ and I kind of want to design my code better.

Unfortunately I've now get myself stuck a bit, well not stuck. But I feel I'm doing things wrong.

So onto my next quick questions :)

Can I loop backwards like

for loop = 2000 to 1 step -1

I've seen all this Insert Before and After commands but I can't figure out how to start at the back of a list. In my code I want to start at the last entry. Like a LIFO badger.

But at the moment I have to do this:-
moo=0

For b.badger Each badger
moo=moo+1
Next

spamflan = 0
For b.badger Each badger
if moo=spamflan then
endif
Next

Like:-

For Last b.badger To First b.badger

Next

Also I want to do the same but start in the middle. With a normal for loop and an array I'd just do this:-

for loop=low_num to high_num
badgers(loop)
next

Or something.

for loop =high_num to low_num step -1
badgers(loop)
next

Basically, I want to access a group of badgers inside a sheep with a pointer and then scan consecutive badgers in either direction, just like I've shown above with my array of badgers.

Anyway, thanks in advance for trying to help (again) :)
I appreciate it.


big10p(Posted 2005) [#19]
To access your badgers in reverse order (LIFO), you can:

this.badger = Last badger
while this<>Null
  ;do stuff to badger!
  this = Before this
wend


To access badgers 'somewhere' in the middle of the list, you need the handle of the badger you want to start with, and the use Before and After to access the ones connected to it.


NewtSoup(Posted 2005) [#20]
Dont forget tho that while you are using the internal collections of Badger you are accessing ALL the badgers in the order they were created (first to last ) regardless of which sheep contains references to them. To see which sheep contains which badgers you must ask the sheep.
eg
print sheep\badger1\name

fetches the variable value of the field "name" in the type badger (assuming you gave it one in the first place)