Jump to content

Parsing theory.


irswat

Recommended Posts

OK. I'm in the process of attempting to write a voice command engine for Skyrim. The basic data flow is:

A button is pressed in game and you speak into the microphone.

Windows voice recognition translates voice to text.

A tandem c++ app saves the text file and does some light formatting like adding literal null characters "/n".

Skyrim quest script dumps the text file to a string, parses the string into individual words, and stores them in an array.

The script then detects one of several commands. The one I am working on now is "Equip". It will probably be the hardest of the commands. Here is where I am hoping for some input.

Currently I am designing the engine to expect input in the form of "Equip Materialtype Weapontype/Armortype Uniqueattributes." For example "Ebony blade of woe."

Here is the code I am using to accomplish this:


 

	endCMD=SVE_DumpArray.Find("Quick", iCMDFound)
	CMDLength=endCMD-iCMDFound
	(while CMDParserCounter<=CMDLength)
		iToParse=SVE_DumpArray[iCMDFound+CMDParserCounter]
		iItemFound=MaterialList.Find(iToParse)
		if iItemFound>0
			MaterialType=iItemFound
		elseif iItemFound<0
			iItemFound=WeaponType.Find(iToParse)
		elseif iItemFound>0
			WeaponType=iItemFound
		elseif iItemFound<0
			iItemFound=ArmorType.Find(iToParse)
		elseif iItemFound>0
			ArmorType=iItemFound
		elseif iItemFound<0
			iItemFound=WeaponNames.Find(iToParse)
		elseif iItemFound>0
			WeaponName=iItemFound
		elseif iItemFound<0
			iItemFound=ArmorNames.Find(iToParse)
		elseif iItemFound>0
			ArmorName=iItemFound
		else
			ItemNotFound==true
		endif
	endWhile
	
	if MaterialType
		Formulator[0]=MaterialType
	elseif WeaponType
		Formulator[1]=WeaponType
	elseif ArmorType
		Formulator[2]=ArmorType
	elseif WeaponName
		Formulator[3]=WeaponName
	elseif ArmorName
		Formulator[4]=ArmorName
	endif
	
	Formulator[5]=Formulator[0]+Formulator[1]+Formulator[2]+Formulator[3]+Formulator[4]

 



In theory Formulator [5] should yield something like a weapon or armor name. Please keep in mind I forgot to add equip slot. I then will search a pre filled formarray.GetName() and try to determine the percentage of match there is between the highest matching formlist and if it is sufficiently high, say 90%, will assume this is the correct item being requested.

for example A command might be "Equip Nightingale Bow quick". This will trigger the weapon type and weapon name to fill. The result will be Bow Nightingale which should yield a near perfect match to the Nightingale Bow. In theory anyhow.

Does anyone have any better theoretical ideas about how to about determining what a person wants using simple, or even more advanced parsing techniques? Again keep in mind I've never done this before, but I am eager to learn!

Edited by irswat
Link to comment
Share on other sites

Good news: I have a proof of concept done.

 

	;fills string array with DUMP
	while (LoopCounter<=DumpLineCount)
		CurrentLine=GetLine(CurrentDump, LoopCounter, DumpLineCount)
		;debug.trace("Current Line: " + CurrentLine)
		
		WordsOnCurrentLine=GetNumWords(CurrentLine)
		;debug.trace("Number of words on current line: " + WordsOnCurrentLine)
		
		CurrentWordIndex=1
		while (CurrentWordIndex<=WordsOnCurrentLine)
;			;Get word y on line x
			CurrentWord=GetWord(CurrentLine, WordsOnCurrentLine, CurrentWordIndex)
			;debug.notification("Word " + CurrentDumpWordIndex + ": " + CurrentWord)
			debug.trace("Word " + CurrentDumpWordIndex + ": " + CurrentWord)
;			;store word y in array
			SVE_DumpArray[CurrentDumpWordIndex]=CurrentWord
			CurrentWordIndex+=1
			CurrentDumpWordIndex+=1
		endWhile
		debug.trace("Line " + LoopCounter + " complete")
		LoopCounter=LoopCounter+1
		
	endWhile 
	LoopCounter=0
	debug.trace("SVE DUMP COMPLETE.")

	;right now it is only parsing the last line.
	while (FindCommandCounter<=7)
		currentCMD=CommandList[FindCommandCounter]
		iCMDFound=SVE_DumpArray.Find(currentCMD)
		debug.trace("Searching SVE Dump for executable")
		
		if (iCMDFound>=0)
			CurrentCMD=SVE_DumpArray[iCMDFound]
			debug.trace("Command found: " + SVE_DumpArray[iCMDFound] + " in index " + iCMDFound)
			FindCommandCounter+=1
		else
			FindCommandCounter+=1
		endif
		
		if CurrentCMD=="Thuum"
			;search next three indices for thuum words against Thuum formlist
			;do all three words belong to the same thuum?
			;how many words does the player know?
			;shout
		elseif CurrentCMD=="Equip"
			debug.notification("Equip CMD detected")
			endCMD=SVE_DumpArray.Find("QUICK", iCMDFound)
			CMDLength=endCMD-iCMDFound
			while (CMDParserCounter<=CMDLength)
			break=false
				iToParse=SVE_DumpArray[iCMDFound + CMDParserCounter]
				iItemFound=MaterialList.Find(iToParse)
				
				if ((iItemFound>=0) && (break==false))
					MaterialType=SVE_DumpArray[iCMDFound + CMDParserCounter]
					break=true
					debug.notification("Material type detected in index " + CMDParserCounter)
				elseif iItemFound<0
					iItemFound=WeaponTypes.Find(iToParse)
				endif 
				
				if ((iItemFound>=0) && (break==false))
					WeaponType=SVE_DumpArray[iCMDFound + CMDParserCounter]
					debug.notification("Weapon type detected in index " + CMDParserCounter)
					break=true
				elseif iItemFound<0
					iItemFound=ArmorTypes.Find(iToParse)
				endif
				
				if ((iItemFound>=0) && (break==false))
					ArmorType=SVE_DumpArray[iCMDFound + CMDParserCounter]
					debug.notification("Armor type detected in index " + CMDParserCounter)
					break=true
				elseif iItemFound<0
					iItemFound=WeaponNames.Find(iToParse)
				endif
				
				if ((iItemFound>=0) && (break==false))
					WeaponName=SVE_DumpArray[iCMDFound + CMDParserCounter]
					debug.notification("Unique weapon modifier detected in index " + CMDParserCounter)
					break=true
				elseif iItemFound<0
					iItemFound=ArmorNames.Find(iToParse)
				endif
				
				if ((iItemFound>=0) && (break==false))
					ArmorName=SVE_DumpArray[iCMDFound + CMDParserCounter]
					debug.notification("Unique armor modifier detected in index " + CMDParserCounter)
					break=true
				else
					ItemNotFound==true
				endif
				
				CMDParserCounter+=1
			endWhile
			
			if MaterialType
				Formulator[0]=MaterialType
			endif
			if WeaponType
				Formulator[1]=WeaponType
			endif
			if ArmorType
				Formulator[2]=ArmorType
			endif
			if WeaponName
				Formulator[3]=WeaponName
			endif
			if ArmorName
				Formulator[4]=ArmorName
			endif
		
			Formulator[5]=Formulator[0]+" "+Formulator[1]+" "+Formulator[2]+" "+Formulator[3]+" "+Formulator[4]
			debug.notification(Formulator[5])
			
			;weapon or armor?
			;armor/clothing
			;should look for keywords like armor, breastplate, helmet, boots, gauntlets, cloaks, etc.
			;this will be called piece
			;modifier type will be called piecetype, this will be mostly materials
			;expecting form "equip ebony armor", "equip dragonbone helmet", etc
			
			;weapon
			;name (staff of magus)	
			;material
			;type (e.g. dagger, sword, greatsword, staff, bow, gloves)
			;equipping hand
			;expecting form "ebony bow and arrows", "or ebony bow and ebony arrows"
			;expecting form "equip dragonsting dagger in left hand"
			;expecting form "equip staff of magus in right hand", etc.
			
		elseif CurrentCMD=="Unequip"
			
		elseif CurrentCMD=="Use"
			;potion formlist
		elseif CurrentCMD=="Cast"
			;spell formlist
		elseif CurrentCMD=="Map"
			int MapKey = Input.GetMappedKey("Quick Map",0x00)
			Input.TapKey(MapKey)
		elseif CurrentCMD=="Save"
			int SaveKey = Input.GetMappedKey("Quicksave",0x00)
			Input.TapKey(SaveKey)
			debug.trace("save")
		elseif CurrentCMD=="Exit"
			;Debug.QuitGame()
		endif
		
	endWhile

 



The code detects Equip Staff of Magnus, and then parses the line into weapon type and special weapon modifier ("of magnus"). Next step is to fill a formlist with weaponforms. Anyone want to help me write a tes5edit script that will fill formlists dynamically? Ideally I could have WeaponFormList, and a seperate WeaponNamesFormList that mirrors the former. Then I'll simply do WeaponCommand=Formulator[5]. I will then search WeaponsNameFormList for a match on WeaponCommand, when it is found I'll get the index, then I'll get the weapon form from that index from the weaponformlist, parse the equipping hand if applicable, and voila, I'm ready to start issuing commands.

The implications of this are a dynamic and robust voice command engine that is compatible with 3rd party mods. Pretty cool stuff.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...