Recent

Author Topic: Generate every possible string combination from TStringLists  (Read 3945 times)

FiftyTifty

  • Jr. Member
  • **
  • Posts: 56
Generate every possible string combination from TStringLists
« on: April 23, 2017, 01:41:53 am »
As a wee bit of background on my conundrum, I'm making a script that generates all possible armour combinations for a few base NPC "types", for Oblivion. I'm able to generate all accumulative combinations, but not all possible combinations.

Here's the script:

Code: [Select]
unit userscript;
var
fileFranLite: IInterface;
strGoblinPath: string;
tstrlistGoblinHead, tstrlistGoblinShoulders: TStringList;



procedure GenerateGoblinVariables;
begin

//Begin Goblin
  strGoblinPath := ProgramPath + 'Edit Scripts\FyTy\Fran Variants\Goblin02\';
tstrlistGoblinHead := TStringList.Create;
tstrlistGoblinHead.LoadFromFile(strGoblinPath + 'Head.txt');
tstrlistGoblinShoulders := TStringList.Create;
tstrlistGoblinShoulders.LoadFromFile(strGoblinPath + 'Shoulders.txt');
//End Goblin

end;

function Initialize: integer;
begin

GenerateGoblinVariables;

end;



procedure GenerateGoblinVariants(eGoblinBase: IInterface);
var
iCounterSuper, iCounterSub: Byte;
iEDIDSuffix: integer;
eGoblinNew, eAdded: IInterface;
strEDID, strNewEDID: string;
begin

strEDID := GetEditValue(ElementBySignature(eGoblinBase, 'EDID'));


//Generate combinations with head armour
for iCounterSuper := 0 to tstrlistGoblinHead.Count - 1 do begin

inc(iEDIDSuffix);

eGoblinNew := wbCopyElementToFile(eGoblinBase, fileFranLite, true, true);
eAdded := ElementAssign(ElementBySignature(eGoblinNew, 'NIFZ'), HighInteger, nil, false);

SetEditValue(eAdded, tstrlistGoblinHead[iCounterSuper]);

strNewEDID := strEDID + '_' + IntToStr( Format('%.3d', [iEDIDSuffix]) );
SetElementEditValues(eGoblinNew, 'EDID', strNewEDID);


for iCounterSub := 0 to tstrlistGoblinShoulders.Count - 1 do begin

inc(iEDIDSuffix);

eGoblinNew := wbCopyElementToFile(eGoblinNew, fileFranLite, true, true);

eAdded := ElementAssign(ElementBySignature(eGoblinNew, 'NIFZ'), HighInteger, nil, false);
SetEditValue(eAdded, tstrlistGoblinShoulders[iCounterSub]);

strNewEDID := strEDID + '_' + IntToStr( Format('%.3d', [iEDIDSuffix]) );
SetElementEditValues(eGoblinNew, 'EDID', strNewEDID);

end;


end;


end;


function Process(e: IInterface): integer;
var
strName: string;
begin
 
if Signature(e) <> 'CREA' then
exit;

  AddMessage('Processing: ' + FullPath(e));

fileFranLite := GetFile(e);

strName := GetElementEditValues(e, 'FULL - Name');

//Begin creature name check
if strName = 'Goblin' then
GenerateGoblinVariants(e);
//End creature name check


end;


function Finalize: integer;
begin
  Result := 0;
end;

end.

It works, in so far that it creates the following:

Goblin - Helmet01
Goblin - Helmet01 + R Shoulder
Goblin - Helmet01 + R Shoulder + L Shoulder
Goblin - Helmet 01 + R Shoulder + L Shoulder + R Leg
Goblin - Helmet 02
Goblin - Helmet 02 + R Shoulder
...

But I want to generate combinations such as:

Goblin - Helmet01
Goblin - Helmet01 + L Shoulder
Goblin - Helmet01 + R Leg + R Shoulder
Goblin - Helmet01 + R Shoulder + L Leg
...


How would I do this?

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Generate every possible string combination from TStringLists
« Reply #1 on: April 23, 2017, 02:57:08 am »
you need to provide the data for the string lists. I guess that some data (eg shoulder, leg etc) are part of the same list?
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

FiftyTifty

  • Jr. Member
  • **
  • Posts: 56
Re: Generate every possible string combination from TStringLists
« Reply #2 on: April 23, 2017, 03:29:12 am »
you need to provide the data for the string lists. I guess that some data (eg shoulder, leg etc) are part of the same list?

Aah yeah, my bad. At the moment, it's just got the one character. There'll be others with a different number of text files, due to the way the armour's done. To explain:

Chest pieces shouldn't be mixed with other chest pieces, helmets shouldn't be mixed with other helmets. There would be one Chests.txt, and one Helmets.txt, and these wouldn't be mixed.

Left hand gloves should be mixed with right hand gloves, left pauldrons, right pauldrons, left arm guards, right arm guards. There would be one big txt file containing these.

Figured that would be the best way to organize it all.


Anyway, here's the Head.txt file:

Code: [Select]
goblinarmorhelm01.nif
goblinarmorhelm02.nif
goblinarmorhelm03.nif
goblinarmorhelm04.nif

And here's the Shoulders.txt file:

Code: [Select]
goblinarmorpauldronl.nif
goblinarmorpauldronr.nif
goblinarmorupperl.nif
goblinarmorupperr.nif

The Heads.txt is not to be, err, "intra-mixed", so I put that in the first loop. In plain English, I was aiming "For each helmet, get every possible shoulder combination."

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Generate every possible string combination from TStringLists
« Reply #3 on: April 23, 2017, 06:28:59 am »
yeah sorry it does not help at all. The data are there but I do not see any foolproof way to get them. You need to first write a couple of helper functions
1) function GetArmorType(aArmor:String):TArmorType;
2) Function AllowedPiece(const aCombination:array of TArmortype; aNewPiece:TArmortype):Boolean;
TArmorType should be something along the lines of
Code: Pascal  [Select][+][-]
  1. TArmorPiece = (chest, shoulder, Leg, head);
  2. TPiecePlacement=(Left, right, none);
  3. TArmorType = record
  4.   Armor :String;
  5.   ArmorPiece:TArmorPiece;
  6.   PiecePlacement:TPiecePlacement;
  7. end;
  8.  
Given any description you should be able to create a record and check it against the records already selected in the current list.
After that you create a recursive procedure that will drill down the same list over and over again, something along the lines of
Code: [Select]
//pseudo Code
procedure Combine(const CurrentCombination:array of TArmorType; Const OutList:TStringList; const ArmorPieces:TStringList);
var
  vType:TArmorType;
  vCntr:Integer;
  vNewCombination:Array OF TArmorType;
begin
  if assigned(CurrentCombination) then begin
    setLEngth(vNewCombination, length(CurrentCombination)+1);
   copyData to vNewCombination from CurrentCombination;
  end else
    SetLength(vNewCombination, 1);
  for vCntr := 0 to ArmorPieces.Count-1 do begin
     vType := getArmorType(ArmorPieces.Strings[vCntr]);
     if AllowedPiece(CurrentCombination,vType) then begin
         change the last item in vCurrentCombination to  vType;
         outlist.add(convertToString(vNewCombination));
         Combine(vNewCombination, outlist, ArmorPieces);
     end;
  end;
end;
//outlist holds the accepted combinations.
//ArmorPieces has all the Armor pieces you can combine.
This way should produce the most complete list, you use a lot of memory and cpu time. there are ways to make it faster but implement the simplest case first and ask again if you need more speed.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Generate every possible string combination from TStringLists
« Reply #4 on: April 24, 2017, 12:22:19 am »
I want to generate combinations such as:

Goblin - Helmet01
Goblin - Helmet01 + L Shoulder
Goblin - Helmet01 + R Leg + R Shoulder
Goblin - Helmet01 + R Shoulder + L Leg
...

How would I do this?

Simple ansistrings of 7-bit characters are actually good data containers for processing combinations of items because they are easily indexed, self-adjusting in length, and have good built-in suppport for Copy/Delete/Length functions.
The attached example works out all combinations of the numerals in the string '0123' (according to your criteria) and then maps those numerals to the enumerated type
Code: Pascal  [Select][+][-]
  1. TShoulderLeg = (slLeftShoulder, slRightShoulder, slLeftLeg, slRightLeg);
and prints out the mapped combinations. Part of the output is shown for the first two helmets.
You can adapt the example to your needs.

 

TinyPortal © 2005-2018