Begging for help with simple loop.
BlitzMax Forums/BlitzMax Programming/Begging for help with simple loop.
| ||
Please help me. I am so frustrated that I could shout at my screen. I am simply trying to produce a list of unique resolutions with no duplicates whatsoever. I have been playing around with this the entire night and I still end up with duplicates. I don't understand why!!! The second loop is entirely redundant. However, I am getting so desperate that I tried to break it down into two separate loops to isolate the issue. Your help would be greatly appreciated. The function to look at specifically is: Function PopulateRes() Local m:Res Local check:String[CountList(resolution.resolutionlist)] Local i:Int = 0 Local j:Int = 0 Local found:Int For m = EachIn Resolution.Resolutionlist check[i] = m.resolution i=i+1 Next For j=0 To check.length-1 found = 0 For m = EachIn Resolution.Resolutionlist If m.resolution = check[j] If found > 1 Then check[j]="" found = found + 1 End If Next Next For i=0 To check.length-1 If check[i]<>"" AddGadgetItem rescombobox, check[i] Print check[i] 'Testing EndIf Next End Function Here is the full code ' <HEADER> SuperStrict Import maxgui.drivers Import brl.Graphics Global APP_WIDTH:Int = 640 Global APP_HEIGHT:Int = 240 ' </HEADER> ' <OBJECTS> Type Resolution Global ResolutionList:TList = New TList Method New() ResolutionList.AddLast(Self) End Method End Type Type Res Extends Resolution Field Resolution:String Field Depth:String Field Hz:String Function Create:Res(r:String,d:Int,h:Int) Local ent:Res = New Res ent.Resolution = r ent.Depth = d ent.Hz = h Return ent End Function End Type ' </OBJECTS> ' <FUNCTIONS> Function PopulateRes() Local m:Res Local check:String[CountList(resolution.resolutionlist)] Local i:Int = 0 Local j:Int = 0 Local found:Int For m = EachIn Resolution.Resolutionlist check[i] = m.resolution i=i+1 Next For j=0 To check.length-1 found = 0 For m = EachIn Resolution.Resolutionlist If m.resolution = check[j] If found > 1 Then check[j]="" found = found + 1 End If Next Next For i=0 To check.length-1 If check[i]<>"" AddGadgetItem rescombobox, check[i] Print check[i] EndIf Next End Function ' </FUNCTION> ' <GUI> Local wx:Int = (GadgetWidth(Desktop()) - APP_WIDTH) / 2 Local wy:Int = (GadgetHeight(Desktop()) - APP_HEIGHT) / 2 Global window:TGadget = CreateWindow("Launcher", wx, wy, APP_WIDTH, APP_HEIGHT, Null, WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS) Global rescombobox:TGadget = CreateComboBox(4, 50, 200, 22, window) Global depthcombobox:TGadget = CreateComboBox(4, 80, 200, 22, window) Global refreshcombobox:TGadget = CreateComboBox(4, 110, 200, 22, window) ' </GUI> ' <LISTS> Local mode:TGraphicsMode For mode:TGraphicsMode = EachIn GraphicsModes() Local r:Res = res.Create(mode.width + " X " + mode.height,mode.depth,mode.hertz) Next ' </LISTS> ' <TEST> PopulateRes() 'Local m:Res 'For m = EachIn Resolution.Resolutionlist ' Print m.resolution 'Next ' </TEST> ' <BODY> While WaitEvent() Select EventID() Case EVENT_WINDOWCLOSE End Case EVENT_APPTERMINATE End End Select Wend ' </BODY> |
| ||
If found > 1This should be >=1 |
| ||
Unless my compiler is buggy, this doesn't work for me. Does it work for you? |
| ||
I dont have Max yet so excuse me if I'm daft... Where do you eliminate duplicates? Local mode:TGraphicsMode For mode:TGraphicsMode = EachIn GraphicsModes() Local r:Res = res.Create(mode.width + " X " + mode.height,mode.depth,mode.hertz) Next In that loop you should put something like Local mode:TGraphicsMode For mode:TGraphicsMode = EachIn GraphicsModes() if ResNotRegistered(r:Res) Local r:Res = res.Create(mode.width + " X " + mode.height,mode.depth,mode.hertz) end if Next of course you would need to create the ResNotRegistered function that just checks the current list of Resolutions against the incoming resolution |
| ||
For j=0 To check.length-1 found = 0 For Local jj:Int = j To check.length-1 If check[jj] = check[j] found = found + 1 If found > 1 Then check[jj]="" End If Next Next |
| ||
Oops..Local mode:TGraphicsMode For mode:TGraphicsMode = EachIn GraphicsModes() local rmode=mode.width + " X " + mode.height if ResNotRegistered(rmode) Local r:Res = res.Create(rmode,mode.depth,mode.hertz) end if Next |
| ||
Skully: Thanks for your help. I also can't get that to work. I still get duplicates on a couple of resolutions. Whatever and whichever way I try to write a function that returns True or False, I always end up with a few false negative. (Especially with the resolution 320 x 200) Zeke: I can't wait to try your version out. I cannot see in which way it is different to what I currently have. I tried it using two arrays the first time around and removing items from the first list. I will give it a go as soon as I am back in front of my screen. (Did you test it yourself?) |
| ||
Here's how I get a de-duplicated list of available graphics modes in the retroremakes framework:' Find graphics modes for all available drivers, de-duplicate ' and exclude modes that don't appear on both drivers (where ' available) Method FindGraphicsModes() 'Get the OpenGL Modes first SetGraphicsDriver(GLMax2DDriver()) graphicsModes_ = ListFromArray(GraphicsModes()) TGameEngine.GetInstance().LogInfo("OpenGL Graphics Modes Found: " + graphicsModes_.Count()) 'DirectX modes if on Windows ?win32 SetGraphicsDriver(D3D7Max2DDriver()) Local dxModes:TList = ListFromArray(GraphicsModes()) SetGraphicsDriver(D3D9Max2DDriver()) Local dx9Modes:TList = ListFromArray(GraphicsModes()) For Local mode:TGraphicsMode = EachIn dx9Modes dxModes.AddLast(mode) Next TGameEngine.GetInstance().LogInfo("DirectX Graphics Modes Found: " + dxModes.Count()) 'Remove DirectX Modes that aren't available under OpenGL For Local findMode:TGraphicsMode = EachIn dxModes Local found:Int = False For Local mode:TGraphicsMode = EachIn graphicsModes_ If findMode.width = mode.width And .. findMode.height = mode.height And .. findMode.depth = mode.depth And .. findMode.hertz = mode.hertz found = True Exit End If Next If Not found dxModes.Remove(findMode) End If Next 'Remove OpenGL Modes that aren't available under DirectX For Local findMode:TGraphicsMode = EachIn graphicsModes_ Local found:Int = False For Local mode:TGraphicsMode = EachIn dxModes If findMode.width = mode.width And .. findMode.height = mode.height And .. findMode.depth = mode.depth And .. findMode.hertz = mode.hertz found = True Exit End If Next If Not found graphicsModes_.Remove(findMode) End If Next 'Merge the lists For Local mode:TGraphicsMode = EachIn dxModes graphicsModes_.AddLast(mode) Next ? ' Now sort and deduplicate graphicsModes_.Sort(True, TGraphicsService.GraphicsModeSort) TGameEngine.GetInstance().LogInfo("Total Graphics Modes Found: " + graphicsModes_.Count()) graphicsModes_ = DeDuplicateGraphicsModes(graphicsModes_) TGameEngine.GetInstance().LogInfo("Final De-Duplicated Graphics Modes Found: " + graphicsModes_.Count()) End Method Function GraphicsModeSort:Int(o1:Object, o2:Object) Local o1mode:TGraphicsMode = TGraphicsMode(o1) Local o2mode:TGraphicsMode = TGraphicsMode(o2) Local compare:Int If o1mode.width < o2mode.width compare = -1 ElseIf o1mode.width > o2mode.width compare = 1 Else If o1mode.height < o2mode.height compare = -1 ElseIf o1mode.height > o2mode.height compare = 1 Else If o1mode.depth < o2mode.depth compare = -1 ElseIf o1mode.depth > o2mode.depth compare = 1 Else If o1mode.hertz < o2mode.hertz compare = -1 ElseIf o1mode.hertz > o2mode.hertz compare = 1 Else compare = 0 End If End If End If End If Return compare End Function Method DeDuplicateGraphicsModes:TList(modes:TList) Local deDupedModes:TList = New TList Local first:Int = True For Local mode:TGraphicsMode = EachIn modes If first deDupedModes.AddLast(mode) first = False Else If GraphicsModeSort(deDupedModes.Last(), mode) <> 0 deDupedModes.AddLast(mode) End If End If Next Return deDupedModes End Method There's a link to the framework in my sig if you want to check out the code in-situ. It's contained in the TGraphicsService.bmx file which is one of the core services of the framework. Muttley |
| ||
How about using a TMap? it sorts at insertion time and does not allow duplicates. Throw in a decent compare method, or just use strings... |
| ||
Dear grable, That looks really useful. Thanks. I would still like to figure out what is wrong with my code. I cannot get my head around what is causing the issue. It should be so simple! |
| ||
The reason it's not working is because you have your loops round the wrong way. You should iterate through the ResolutionList first and then the array. Each time it found a dupe, "j" had not increased in value so it was nulling the same string in the array each time it found one. Also, I think it should increment found before the if statement, not after. It should look like this: For m = EachIn Resolution.Resolutionlist found=0 For j=0 To check.length-1 If m.resolution = check[j] found = found + 1 If found > 1 check[j]="" End If End If Next Next Like Grable says, Tmap would be a good approach to this. Hope that helps! |
| ||
Awesome!! Can't wait to try it out and also learn about Tmap. Thanks. |
| ||
Thank you very much. I learned something new today. local i:int for i=0 to 10 print i 'result is 1 to 10 next print i 'result is 11 !! (Now that is interesting) If I print "i" after the loop, the value is 11. |
| ||
I'll recommend this idiom (used in Java/BlitzMax etc) to correctly modularize code:SuperStrict For Local i:Int = 0 To 10 Next print i ' will not work! (undefined variable) You can use another variable defined in a broader scope than the loop to save any loop-index values you might be interested in. It's (imho) a very good practice to use index variables (such as i in the example above) only within the loop, and since BMX supports isolating the variable to the loop this is really preferred. |