Posted: Sat Feb 22, 2014 1:50 am Post subject: Advice on how to organize my class's?
What is it you are trying to achieve?
I'm working on my overhead civilization-like game after taking a break for a little while. I've decided to rewrite my code again completely, switching certain aspects of it into functions, classes and modules.
What is the problem you are having?
My problem is that I am unsure of how to organize my code. Before my rewrite I had a large class which contained cities, along with the units (and soon to be farms) that belong to the city. It doesn't seem proper to have two separate sets of objects in the same class, but the units belong to the cities. I originally had an array of a custom record type called cityType; containing the cities x, y, maxUnits etc. along with an array of another custom type called units; containing an x and y. This large class was called playerObjects, however I was also going to use it in the long run for the enemy units.
This was working fine but like I said seems somewhat improper.
So it's kind of like the units are a child of the cities, they are reliant on the cityType and it's information.
I have no Idea how to separate them into different classes, or if I even should. Any input would be appreciated.
Describe what you have tried to solve this problem
<Answer Here>
Post any relevant code (You may choose to attach the file instead of posting the code if it is too long)
<Answer Here>
Turing:
<Add your code here>
Please specify what version of Turing you are using
4.1.1
Sponsor Sponsor
Insectoid
Posted: Sat Feb 22, 2014 12:36 pm Post subject: RE:Advice on how to organize my class\'s?
You could include a pointer to city in the unit class, which points to the parent city. Any information the units need from the city should be available in the public functions of the city, which are accessed via the pointer. The city needs only an array of units.
GreatPumpkin
Posted: Sat Feb 22, 2014 7:21 pm Post subject: RE:Advice on how to organize my class\'s?
So the unitsClass holds only the variables of the stats, methods of interaction and a pointer to the citiesClass, with no arrays inside?
and by pointer do you mean the "pointer to" or a variable that holds the number of the city it belongs to ?
evildaddy911
Posted: Sat Feb 22, 2014 7:41 pm Post subject: RE:Advice on how to organize my class\'s?
you could probably do either one. however, insectoid most likely meant "pointer to"
Insectoid
Posted: Sat Feb 22, 2014 8:53 pm Post subject: RE:Advice on how to organize my class\'s?
Quote:
So the unitsClass holds only the variables of the stats, methods of interaction and a pointer to the citiesClass, with no arrays inside?
The unit class contains any variables and functions that it requires. The pointer gives it access to all of the city class's public variables and functions.
GreatPumpkin
Posted: Sat Feb 22, 2014 10:40 pm Post subject: Re: Advice on how to organize my class's?
I don't understand what you mean by an array of units in the city in your first post.
If my citiesClass comes before my unitsClass, and the record for the type unitsType is within the unitsClass, how do I make an array of unitsType? Also if theres only a pointer from unitsClass to citiesClass, how do I manipulate the array of units in the city with methods in unit's class?
Nor do I understand what you mean by "a pointer to city in the unit class, which points to the parent city"
Is the pointer to the citiesClass? or is it a pointer to the array of cityTypes inside the citiesClass?
I really don't understand at all, can you give me an example ?
Here is the code for my unitsClass I've made.
Turing:
class citiesClass
import cursor, pics
export addCity, drawCities
var cityTiles :array0.. 59, 0.. 59ofint for x :0.. 59 for y :0.. 59
cityTiles (x, y):=0 endfor endfor
type cityType : record
cityNo :int%City No./ Active Flag
x :int%X
y :int%Y
adjLand :int
maxUnits :int
units :array1.. 8ofint endrecord var cities :array1.. 15of cityType
var selectedCity :int:=1 var openCityPointer :int:=1
for i :1.. 15
cities (i).cityNo :=0%City No./ Active Flag
cities (i).x :=0%X
cities (i).y :=0%Y
cities (i).adjLand :=0%Number of adjacent land tiles
cities (i).maxUnits :=0%#of units endfor
procedure checkForOpenCity
openCityPointer :=1%variable to check through attackArray for i :1.. 15%cityInfo (selectedCity).maxCitys if cities (openCityPointer).cityNo =0then%if pointing to open space exit, openCityPointer will = open unit exit else
openCityPointer := openCityPointer + 1 endif endfor%%% openCityPointer will now be pointing t0 the first available unit space. end checkForOpenCity
proc adjustCityTiles
for i :1.. 15 if cities (i).cityNo > 0then
cityTiles (cities (i).x, cities (i).y):= cities (i).cityNo
endif endfor end adjustCityTiles
proc drawCities
for x :0.. 60 - 1 for y :0.. 60 - 1 if cityTiles (x, y) > 0then Pic.Draw(pics (8), x *10 - 10, y *10 - 10, picMerge) endif endfor endfor end drawCities
end citiesClass
var playerCities : ^citiesClass
new citiesClass, playerCities
class unitsClass
import cursor, pics
export addUnit, drawUnits
var unitTiles :array0.. 59, 0.. 59ofint for x :0.. 59 for y :0.. 59
unitTiles (x, y):=0 endfor endfor
type unitType : record
unitNo :int%City No./ Active Flag
x :int%X
y :int%Y endrecord
var selectedUnit :int:=1 var openUnitPointer :int:=1 var units :array1.. 8of unitType
for i :1.. 8
units (i).unitNo :=0%City No./ Active Flag
units (i).x :=0%X
units (i).y :=0%Y endfor
procedure checkForOpenUnit
openUnitPointer :=1%variable to check through attackArray for i :1.. 8%unitInfo (selectedCity).maxCitys if units (openUnitPointer).unitNo =0then%if pointing to open space exit, openCityPointer will = open unit exit else
openUnitPointer := openUnitPointer + 1 endif endfor%%% openCityPointer will now be pointing t0 the first available unit space. end checkForOpenUnit
proc addUnit
checkForOpenUnit
units (openUnitPointer).unitNo := openUnitPointer
units (openUnitPointer).x :=(cursor.adjustXdiv)
units (openUnitPointer).y :=(cursor.adjustYdiv)
unitTiles (units (openUnitPointer).x, units (openUnitPointer).y):= openUnitPointer
end addUnit
proc adjustUnitTiles
for i :1.. 8 if units (i).unitNo > 0then
unitTiles (units (i).x, units (i).y):= units (i).unitNo
endif endfor end adjustUnitTiles
proc drawUnits
for x :0.. 60 - 1 for y :0.. 60 - 1 if unitTiles (x, y) > 0then Pic.Draw(pics (7), x *10, y *10, picMerge) endif endfor endfor end drawUnits
end unitsClass
Dreadnought
Posted: Sun Feb 23, 2014 2:20 am Post subject: Re: Advice on how to organize my class's?
GreatPumpkin wrote:
I don't understand what you mean by an array of units in the city in your first post.
If my citiesClass comes before my unitsClass, and the record for the type unitsType is within the unitsClass, how do I make an array of unitsType? Also if theres only a pointer from unitsClass to citiesClass, how do I manipulate the array of units in the city with methods in unit's class?
I'll get to this in a bit.
GreatPumpkin wrote:
Nor do I understand what you mean by "a pointer to city in the unit class, which points to the parent city"
Is the pointer to the citiesClass? or is it a pointer to the array of cityTypes inside the citiesClass?
You want the unit to know which city it is in, so it should have a pointer which points to it (or some of its data)
GreatPumpkin wrote:
I really don't understand at all, can you give me an example ?
I'll try, but first, how does one have classes which mutually reference one another? (your first question)
Well in the ugly beast that is Turing's OOP that's not very obvious since we can't use forward declarations for types. So we get
Turing:
class A
import B % this will fail (undeclared)
end A
class B
import A
end B
Putting each class in its own unit doesn't get us much farther since Turing will complain about circular dependency. So what can we do?
My solution (and I encourage anyone else with a nice solution to post it) is to have some kind of type that will store sufficient information about B so that A can use it. Like a parent class for B that contains everything A will need. (I don't really find this to be an elegant solution but I can't come up with something better for now)
Here's an example (in multiple files)
CityData.tu
Turing:
unit class CityData
% Contains what Citizen needs to know about a city exportvar Name
var Name :string
end CityData
Citizen.tu
Turing:
unit class Citizen
import CityData
exportvar Name, SetParentCity, Action
var parentCity : ^CityData :=nil
var Name :string
proc SetParentCity (p : ^CityData)
parentCity := p
end SetParentCity
proc Action () if(parentCity ~=nil)then put" Action() was called on " + Name + ", citizen of " + parentCity -> Name + "." else put" Action() was called on " + Name + ", which is not a citizen of any city" endif end Action
end Citizen
City.tu
Turing:
unit class City
inherit CityData
import Citizen
export AddCitizen, PerformActionOnAllCitizens, ListCitizens, ClearCitizens
% I use a flexible array but you can use any container you want var citizens :flexiblearray1.. 0of ^Citizen
var citizenCount :int:=0
proc AddCitizen (c : ^Citizen) if(upper(citizens) <= citizenCount)then if(upper(citizens) < 1)then new citizens, 1 else new citizens, upper(citizens)*2 endif
assert(upper(citizens) > citizenCount) endif
citizenCount +=1
citizens (citizenCount):= c
c -> SetParentCity (self) end AddCitizen
proc PerformActionOnAllCitizens () for i :1.. citizenCount
citizens (i) -> Action () endfor end PerformActionOnAllCitizens
proc ListCitizens () put" --- Citizens of " + Name + " ---" for i :1.. citizenCount
put citizens (i) -> Name
endfor end ListCitizens
proc ClearCitizens () for i :1.. citizenCount
free citizens (i) endfor
citizenCount :=0 end ClearCitizens
end City
main.t (main program, call the file what you want)
city2->AddCitizen(MakeCitizen("Steven Harper"))
city2->AddCitizen(MakeCitizen("Jim Flaherty"))
city2->AddCitizen(MakeCitizen("Mike Duffy"))% Is he still a senator?
city2->AddCitizen(MakeCitizen("Justin Trudeau"))
city2->AddCitizen(MakeCitizen("Tom Mulcair"))
% Now the fun stuff put"city1->ListCitizens()" put""
city1->ListCitizens() put"" put"===================================" put"city2->ListCitizens()" put""
city2->ListCitizens() put"" put"===================================" put"city1->PerformActionOnAllCitizens()" put""
city1->PerformActionOnAllCitizens() put"" put"===================================" put"city2->PerformActionOnAllCitizens()" put""
city2->PerformActionOnAllCitizens() put"" put"==================================="
% Clean up
city1->ClearCitizens()
city2->ClearCitizens() free city1
free city2
Note that this is an example of how I might do it (although I split City into two pieces you might find it easier to split Citizen or do something else entirely). Another way would be using implement instead of inherit for the relation of CityData (or whatever we want to call it) and City.
Basically, this is the nicest thing I can come up with for now, but I find it clunky.
GreatPumpkin
Posted: Sun Feb 23, 2014 2:36 pm Post subject: Re: Advice on how to organize my class's?
Dreadnought @ Sun Feb 23, 2014 2:20 am wrote:
Well in the ugly beast that is Turing's OOP that's not very obvious since we can't use forward declarations for types.
This makes me feel alot better about not understanding this.
Dreadnought @ Sun Feb 23, 2014 2:20 am wrote:
Basically, this is the nicest thing I can come up with for now, but I find it clunky.
Your example and solution make a bit of sense to me, I'll play around with it later, but it seems somewhat straightforward.
Do you think it would be poor practice to continue with a single class that encompasses an individual players (user/ai enemy/second player) cities, units, and farms?
Sponsor Sponsor
Tony
Posted: Sun Feb 23, 2014 3:07 pm Post subject: Re: Advice on how to organize my class's?
GreatPumpkin @ Sun Feb 23, 2014 2:36 pm wrote:
Do you think it would be poor practice to continue with a single class that encompasses an individual players (user/ai enemy/second player) cities, units, and farms?
Posted: Sun Feb 23, 2014 6:56 pm Post subject: Re: Advice on how to organize my class's?
So the majority of methods for the citizens are actually held in the city.tu class is your example ?
Theres some vocabulary I haven't encountered there, and was wondering if you could give me a run down of what happens during a few parts:
Turing:
proc AddCitizen (c : ^Citizen) if(upper(citizens) <= citizenCount)then if(upper(citizens) < 1)then new citizens, 1 else new citizens, upper(citizens)*2 endif
assert(upper(citizens) > citizenCount) endif
citizenCount +=1
citizens (citizenCount):= c
c -> SetParentCity (self) end AddCitizen
self and assert
Turing:
var parentCity : ^CityData :=nil
var Name :string
proc SetParentCity (p : ^CityData)
parentCity := p
end SetParentCity
proc Action () if(parentCity ~=nil)then put" Action() was called on " + Name + ", citizen of " + parentCity -> Name + "." else put" Action() was called on " + Name + ", which is not a citizen of any city" endif end Action
nil.
I will research them when I get back home though.
evildaddy911
Posted: Sun Feb 23, 2014 7:32 pm Post subject: RE:Advice on how to organize my class\'s?
self: when you use self, you are referencing the object you are in. in this case, you are saying Set Parent City to "this city"
assert: this checks to see if the following statement is true. if it is false (if upper(citizens) < citizenCount), then the program will crash. its purpose is for detecting exactly where a problem originated
nil: its a null reference. it tells the program that parentCity doesnt have any data yet
GreatPumpkin
Posted: Sun Feb 23, 2014 10:16 pm Post subject: Re: Advice on how to organize my class's?
Ok I think my problems are coming from not understanding pointers.
I've looked up as many tutorials and guides about them but I just can't grasp them and it's really starting to bug me. All I know is that they're a variable that holds the information of the address of another variable. I don't really understand how it ties into all of this or how it's used.
Could somebody give me as simple dumbed down explanation of pointers with an example of how and where they'd be used? Like I said I have looked up tutorials and I'm still extremely lost.
If you had a string that read "text" and a pointer to the string, put both the string and the pointer they should both put out as "text" ?
I tried that but it can only be used with collection's, class's, and types.. So I made a little object named textContainer. Pretty much it's just a string of text that has a method to write the text into the string and to put the string.
Turing:
class textContainer
export getContainedText, putContainedText
type textContained : record
text :string endrecord var firstTextContainer : textContained
proc getContainedText (TEXT :string)
firstTextContainer.text := TEXT
end getContainedText
proc putContainedText
put firstTextContainer.text
end putContainedText
end textContainer
var myTextContainer : ^textContainer
new textContainer, myTextContainer
myTextContainer -> getContainedText ("This is my text")
myTextContainer -> putContainedText
Can somebody please dissect and explain this part for me :
var myTextContainer : ^textContainer
new textContainer, myTextContainer
the pointer to and the new, I just don't understand those concepts, I've tried to but I can't.
If the pointer just points to the address of the class, and not the class and information in it, how is it put to use?
I really need somebody to help me understand this, because I'm clearly not going to get anywhere by myself.
Also, if somebody could show me how I could complete my bolded example above using the textContainer I've made, it might help me? I'm feeling extremely lost and like quitting all together if I can't grasp these obviously important concepts soon.
Raknarg
Posted: Sun Feb 23, 2014 10:36 pm Post subject: RE:Advice on how to organize my class\'s?
Well I can give it a go. Correct me if I'm wrong.
So you have things like int, real, char, etc. Those all take a very tiny amount of information. So, variables can actually store the info. Think of these like a box that you put stuff in. You just look at the box, and there it is. However, these boxes can only hold one item at a time.
A pointer is different. Imagine your box still only holds one item, but inside your box there's a card that tells you where you can find a warehouse full of other boxes that store information. These are what pointers are (things like arrays and objects). The primitive data types are a box which holds info, and the pointers are boxes that hold the info of where you can find all the other boxes (those boxes being items in your array, or data fields in a class). This is because, like I said, your box can only hold one item at a time. You can't cram in all those pieces of info together, so instead you just store it somewhere else.
In this case, you're creating an item which holds direction for the computer to find all the information of that object. Lets take your example:
var myTextContainer : ^textContainer
new textContainer, myTextContainer
First, you make a pointer to a text container. This means that myTextContainer is going to hold info for the directions of where the computer can find a copy of textContainer. It doesn't yet, but the program is saying that's what it will be.
Then you initialize it. Now textContainer is actually pointing to that information.
Understanding pointers is important when managing your information. You're used to doing this:
var x : int := 5
var y : int := x
x := 7
Normally this would mean that y copies whatever is in x's box and put it in its own. In this case, x is now 7 and y is now 5. However, you cannot do the same things with pointers, because they don't contain the object itself, they contain directions to the object. So:
var x : ^SomeObject := makeNewObject()
new SomeObject, x
x -> someNumberInSomeObject := 5
var y : ^SomeObject := x
x -> someNumberInSomeObject := 7
that data field, someNumberInSomeObject is now the same for x and y, because they're both actually using the same object, as they both have the same directions.
Dreadnought
Posted: Sun Feb 23, 2014 11:47 pm Post subject: Re: Advice on how to organize my class's?
Raknarg wrote:
So you have things like int, real, char, etc. Those all take a very tiny amount of information. So, variables can actually store the info.
There isn't really a problem with variables taking up space in Turing (but it is an issue in other languages like C), for example this runs fine on my computer
Turing:
var s :string putsizeof(s)% 256 var as :array1..5000000ofstring putsizeof(as)% 1280000000 (yes, that's 1,280,000,000 bytes or 1.28 GB)
Here's my "concrete" example of the difference between a value and a pointer. (Raknarg's example with boxes works too but this one feels more intuitive to me)
If I tell Alice "Your number is 5." and tell Bob "Your number is 5.", then tell Alice "Double your number.", Bob's number is still 5 but Alice's is 10
Now, lets say I tell Alice "Your table is this" (as I point my finger at a table) then tell Bob "Your table is this" (pointing my finger at the same table), then I tell Alice "Paint your table red". Now Bob's table is red and Alice's table is red (since they are the same table).
The idea is that in Object Oriented Programming, objects represent some kind of entity. So if I give Alice and Bob the same object, then any changes Alice makes to her object affect Bob's object (since they are the same object).
So how do we translate that into a computer program? (this is where Raknarg's example with boxes is more intuitive)
You create new objects by setting aside space in memory (making room in your warehouse) for the object you want (box of the right size). In Turing this is done using new.
Then you have pointers which tell you where the object is in memory (cards telling you where to look in the warehouse).
This means that if Alice and Bob have cards that tell them to look at the same spot in the warehouse, and Alice paints the object in her box there red, Bob's object will also be red (again, it's the same object).
Raknarg wrote:
var x ^SomeObject = makeNewObject()
new SomeObject, x
x -> someNumberInSomeObject = 5
var y ^SomeObject = x
x -> someNumberInSomeObject = 7
I assume the "makeNewObject()" is not intended to be there since there is a new right after.
I'd like to add a few things:
nil: Basically an invalid location in memory (usually 0), think of it as a blank card (in Raknarg's warehouse of boxes example).
It's good practice to set pointers to nil when they do not point to a valid object.
free: So you set aside all this space in memory for objects, but when you're done with objects you should call free on a pointer to tell the computer you no longer need that space in memory (so the computer can reuse it). Otherwise the computer will continue to assume you are using it, even if you don't have a pointer pointing to that location in memory.
You should always free objects, otherwise you might "leak memory". (Note that when your program finished all memory set aside for it is returned to the OS, but it's still good practice to avoid memory leaks)
Raknarg
Posted: Mon Feb 24, 2014 12:16 am Post subject: RE:Advice on how to organize my class\'s?
>I assume the "makeNewObject()" is not intended to be there since there is a new right after.