SRL Archive - OSR Help

Help Enums and Lists


MrMonotone

2015-02-13 09:52:32

I was trying to get around using arrays because I wanted to have my data be more dynamic. I wanted to be able to remove and insert values easily. So I made the following code. I was wondering if there was an easier way to do this but maintain the same functionality. Please comment if I need to explain further.
Thanks for the help.
MM

//TLDR : I want a list of TActivity and I think I did it in a ghetto way.


program test;
{$DEFINE SMART}
{$i AeroLib/AeroLib.Simba}
{$i Reflection/Reflection.simba}
{$i SimbaExt/SimbaExt.simba}
type TActivity = record
Name: String;
Gear: TStringArray;
end;
SkillsCanLevel = (Cooking, Fletching, Fishing, Firemaking, Woodcutting);
const
Skills : array [SkillsCanLevel] of String = ['Cooking', 'Fletching', 'Fishing', 'Firemaking', 'Woodcutting'];

var
SkillsToLevel: TStringList;
CurActivity: TActivity;
s: String;

procedure setActivity(TheSkill : String);
begin
case TheSkill of
Skills[Cooking]:
begin
with CurActivity do
begin
Name := TheSkill;
Gear := [];
end;
end;
Skills[Fletching]:
begin
with CurActivity do
begin
Name := TheSkill;
Gear := ['Knife'];
end;
end;
Skills[Fishing]:
begin
with CurActivity do
begin
Name := TheSkill;
Gear := ['Fishing Rod'];
end;
end;
Skills[Firemaking]:
begin
with CurActivity do
begin
Name := TheSkill;
Gear := ['Tinderbox'];
end;
end;
Skills[Woodcutting]:
begin
with CurActivity do
begin
Name := TheSkill;
Gear := ['Axe'];
end;
end;
end;
end;

function GearInInv() : Boolean;
begin
Result:= true;
end;

function GearInEquip() : Boolean;
begin
Result:= true;
end;

function TActivity.HasGear() : Boolean;
begin
Result:= GearInEquip OR GearInInv;
end;

procedure TActivity.DoActivity;
begin
Writeln('We are: ', Name,' with ', Gear);
case Name of
Skills[Cooking]:
begin
//cooking
end;
Skills[Fletching]:
begin
// Fletch;
end;
Skills[Fishing]:
begin
//Fish;
end;
Skills[Firemaking]:
begin
//Fire
end;
Skills[Woodcutting]:
begin
//woodcut
end;
end;
end;

begin
SkillsToLevel.Init();
SkillsToLevel.Add(Skills[Cooking]);
SkillsToLevel.Add(Skills[Firemaking]);
while (true) do
begin
setActivity(SkillsToLevel.getStrings(Random(0, SkillsToLevel.getCount - 1)));
CurActivity.DoActivity();
wait(5000);

end;
end.

Brandon

2015-02-13 13:26:26

From: MrMonotone
I was trying to get around using arrays because I wanted to have my data be more dynamic. I wanted to be able to remove and insert values easily. So I made the following code. I was wondering if there was an easier way to do this but maintain the same functionality. Please comment if I need to explain further.



The code you supplied is simulating a constant ordered map. There is no insertion or deletion from a constant map. This map also maintains order due to the enum indexing.

Basically, your code is a more efficient look-up table. You look up the enum and get the string name of it. That's it. Nothing can be changed in it because again.. it's constant.

The equivalent is to do: ToStr(Skill). This will also give you the string name of the enum and remain constant still.

The alternative is to map the enums to a function pointer then you can get rid of the switch entirely.

MrMonotone

2015-02-14 23:43:03

From: Brandon
The code you supplied is simulating a constant ordered map. There is no insertion or deletion from a constant map. This map also maintains order due to the enum indexing.

Basically, your code is a more efficient look-up table. You look up the enum and get the string name of it. That's it. Nothing can be changed in it because again.. it's constant.

The equivalent is to do: ToStr(Skill). This will also give you the string name of the enum and remain constant still.

The alternative is to map the enums to a function pointer then you can get rid of the switch entirely.


I think that I would still need a switch? https://villavu.com/forum/showthread.php?t=102800 However I really like the function pointers I never knew about them. I will update my code and repost it when I update it.

Also is there another way to create a list like container using enums or is the way I am doing that the only way?

Brandon

2015-02-15 00:26:48

From: MrMonotone
I think that I would still need a switch? https://villavu.com/forum/showthread.php?t=102800 However I really like the function pointers I never knew about them. I will update my code and repost it when I update it.

Also is there another way to create a list like container using enums or is the way I am doing that the only way?



Just because that tutorial uses a switch, doesn't mean you have to.


type
Key = (Cooking, Fletching, Fishing, Firemaking, Woodcutting);

var
Skills: array of Procedure;

procedure run(k: Key);
begin
Skills[k]();
end;


procedure cook;
begin
writeln('cooking');
end;

procedure fletch;
begin
writeln('fletching');
end;

procedure fish;
begin
writeln('fishing');
end;

begin
SetLength(Skills, 3);
Skills[Cooking] := @ cook ;
Skills[Fletching] := @ fletch ;
Skills[Fishing] := @ fish ;

run(Cooking);
run(Fletching);
run(Fishing);
end.


Even better is if you could do:


begin
Skills := [@ cook, @ fletch, @ fish];

run(Cooking);
run(Fletching);
run(Fishing);
end.

but sadly Lape cannot parse that. There might be a flag to allow it to parse it but I have no idea.. Also had to add spaces between the address operator because the forum cannot parse it lol (hooray for mention tags)..


Whether or not you need to create a list with enum indexing is an entirely different story. You haven't described the features of this list or its requirements. As far as I can tell you're looking at a map and yes you can create one but I don't see why you need it :S

MrMonotone

2015-02-15 01:45:08

From: Brandon
Just because that tutorial uses a switch, doesn't mean you have to.


type
Key = (Cooking, Fletching, Fishing, Firemaking, Woodcutting);

var
Skills: array of Procedure;

procedure run(k: Key);
begin
Skills[k]();
end;


procedure cook;
begin
writeln('cooking');
end;

procedure fletch;
begin
writeln('fletching');
end;

procedure fish;
begin
writeln('fishing');
end;

begin
SetLength(Skills, 3);
Skills[Cooking] := @ cook ;
Skills[Fletching] := @ fletch ;
Skills[Fishing] := @ fish ;

run(Cooking);
run(Fletching);
run(Fishing);
end.


Even better is if you could do:


begin
Skills := [@ cook, @ fletch, @ fish];

run(Cooking);
run(Fletching);
run(Fishing);
end.

but sadly Lape cannot parse that. There might be a flag to allow it to parse it but I have no idea.. Also had to add spaces between the address operator because the forum cannot parse it lol (hooray for mention tags)..


Whether or not you need to create a list with enum indexing is an entirely different story. You haven't described the features of this list or its requirements. As far as I can tell you're looking at a map and yes you can create one but I don't see why you need it :S


I want an easy way to select randomly between the skills a user selects. also if the user can not do a skill I want to remove it from the ones selectable.

Brandon

2015-02-15 02:19:09

From: MrMonotone
I want an easy way to select randomly between the skills a user selects. also if the user can not do a skill I want to remove it from the ones selectable.



Then you create a map like:


type
Key = (Cooking, Fletching, Fishing, Firemaking, Woodcutting);
Skill = Procedure;

TPair = record
K: Key;
V: Skill;
end;

TMap = array of TPair;

function TMap.add(K: Key; V: Skill): boolean;
var
I: Integer;
begin
for I := 0 to high(self) do
if (self[I].K = K) then
exit(false);

setlength(self, length(self) + 1);
self[high(self)].K := K;
self[high(self)].V := @V;
exit(true);
end;

function TMap.remove(K: Key): boolean;
var
I: Integer;
begin
if (self.get(K) = nil) then
exit(false);

for I := 0 to high(self) - 1 do
if (self[I].K = K) then
swap(self[I], self[I + 1]);
setlength(self, Length(self) - 1);
exit(true);
end;

function TMap.get(K: Key): Skill;
var
I: Integer;
begin
for I := 0 to high(self) do
if (self[I].K = K) then
exit(@self[I].V);
exit(nil);
end;


procedure cook;
begin
writeln('cook');
end;


var
T: TMap;
begin
T.add(Cooking, @cook);
writeln(T.get(Cooking));

T.remove(Cooking);
writeln(T.get(Cooking));
end.


The other option is to create a constant ordered map and when you want to delete from it, you set the pointer to nil..


type
Key = (Cooking, Fletching, Fishing, Firemaking, Woodcutting);
Skill = Procedure;

TPair = record
K: Key;
V: Skill;
end;

TMap = array [0..high(Key)] of TPair;

function TMap.add(K: Key; V: Skill): boolean;
begin
self[K].V := @V;
end;

function TMap.remove(K: Key): boolean;
begin
self[K].V := nil;
end;

function TMap.get(K: Key): Skill;
begin
result := @self[K].V;
end;


procedure cook;
begin
writeln('cook');
end;


var
T: TMap;
begin
T.add(Cooking, @cook);
writeln(T.get(Cooking));

T.remove(Cooking);
writeln(T.get(Cooking));
end.


In both cases you'd simply do:


if (T.get(Cooking) <> nil) then //check if it exists..
T.get(Cooking)(); //call the function.


//OR:

rand_skill := T.get(RandomRange(Ord(Low(Key)), Ord(High(Key))));
if (rand_skill <> nil) then
rand_skill();

So it's really up to you which you choose. One is ordered and doesn't require a loop for lookup. The other loops through the list. One never changes its size and just sets the index to nil for removal. The other removes by swapping the index to the end of the list then resizing by length - 1.

The one with the loop is better if you are choosing randomly because then it won't select nil functions since you remove them from existence..

MrMonotone

2015-02-20 01:51:12

Thanks for the help. I really appreciate your time and patience. Rep++. The thread can be closed if a mod wants to.