16 May 2012 @ 4:06 PM 

One of the most aggravating things when I switched to Linux Mint 12 from Mint 10 was that it seemed to offer a step backwards for a lot of functionality. I was using a program called “Desktop Drapes” to periodically cycle my wallpaper, but it no longer worked in Gnome 3. (there were some supposed plugins to fix this but they didn’t work). I tried a few others, but they universally failed.

 

So I ended up writing a python script to do the job:

 

  1.  
  2. #!/usr/bin/python
  3.  #Copyright (c) 2011 BASeCamp Corporation
  4.  # All rights reserved.
  5.  #
  6.  # Redistribution and use in source and binary forms, with or without
  7.  # modification, are permitted provided that the following conditions
  8.  # are met:
  9.  #
  10.  # Redistributions of source code must retain the above copyright notice,
  11.  # this list of conditions and the following disclaimer.
  12.  #
  13.  # Redistributions in binary form must reproduce the above copyright
  14.  # notice, this list of conditions and the following disclaimer in the
  15.  # documentation and/or other materials provided with the distribution.
  16.  #
  17.  # Neither the name of the project’s author nor the names of its
  18.  # contributors may be used to endorse or promote products derived from
  19.  # this software without specific prior written permission.
  20.  #
  21.  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22.  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23.  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24.  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25.  # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26.  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  27.  # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28.  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29.  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30.  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31.  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32.  
  33.  
  34.  
  35. import sys,os,random,ConfigParser,string
  36. from optparse import OptionParser
  37. #Wallpaper cycling script
  38. #written Sunday March 18th 2012
  39. #designed to be added to crontab with a delay
  40. #example line in crontab:
  41. #*/4 * * * * /home/bc_programming/bin/cyclebg.py
  42. #when run, it will change the wallpaper to the next one in the cycle and exit.
  43. #Author: BC_Programming
  44.  
  45.  
  46.  
  47. #location of data path. we keep track of the wallpapers we have already cycled there.
  48. datapath = os.path.expanduser("~/.cyclebg/")
  49. datafile = datapath + "cycled_data.dat"
  50. wallpaperfile = datapath + "wallpapers.dat"
  51. disablefile = datapath + "disable.dat" #if this file exists we are "disabled" and don’t change the wallpaper.
  52. #command to run to change the bg.
  53.  
  54. #following is for Gnome 2
  55. #bgchangecmd = ‘dconf gsettings set org.gnome.desktop.background picture-uri "file://%s"’
  56. #gnome 3 command…
  57.  
  58. bgchangecmd = ‘gsettings set org.gnome.desktop.background picture-uri "file:///%s"’
  59. #we need two lists: the list of possible wallpapers, and the wallpapers we’ve already listed.
  60.  
  61. def isdisabled():
  62.    return os.path.exists(disablefile)
  63. #returns the list of wallpapers we’ve already cycled through.
  64. def getusedlist():
  65.     if not os.path.exists(datafile):
  66.         #if the file doesn’t exist, then return an empty list.
  67.         return  []
  68.     else:
  69.         return list(open(datafile))
  70.  
  71. #clears the used wallpapers list.
  72. def clearused():
  73.     if os.path.exists(datafile):
  74.        os.remove(datafile)
  75.  
  76. def markused(wallpaper):
  77.     #mark a wallpaper as viewed
  78.     writelist = open(datafile,‘a’)
  79.     writelist.write(wallpaper)
  80.  
  81. #returns all the wallpapers we are to cycle through.
  82. def getwallpapers():
  83.     if not os.path.exists(wallpaperfile):
  84.        return  []
  85.     else:
  86.        return list(open(wallpaperfile))
  87.  
  88.  
  89.  
  90. #routine that changes the background.
  91. def changebackground(picture):
  92.     #changes the background to the specified image.
  93.     cmdrun =bgchangecmd
  94.     cmdrun = cmdrun.replace("%s",picture)
  95.     print " running ",cmdrun
  96.     os.system(cmdrun)    
  97.  
  98. def main():
  99.     if isdisabled(): sys.exit(2)
  100.     sys.exit(changewallpaper())
  101.  
  102. def changewallpaper():
  103.     #retrieve the wallpapers and used wallpapers…
  104.     used = getusedlist()
  105.     papers = getwallpapers()
  106.     #exit if no wallpapers in main list…
  107.     if len(papers)==0:
  108.         print "No wallpapers! add wallpaper file paths to ", wallpaperfile, "!"
  109.         return 1
  110.        
  111.     #now, remove all entries in papers that exist in used.
  112.     removethese= []  #list of items to remove
  113.     for iterateused in papers:
  114.         if iterateused in used:
  115.            removethese = removethese +  [iterateused]
  116.        
  117.  
  118.     #now, remove the items…
  119.     for iterateremove in removethese:
  120.         papers.remove(iterateremove)
  121.  
  122.  
  123.     if len(papers)==0:
  124.         #if papers list is empty, egads! clear the used list, since we’ve cycled through them all evidently.
  125.         clearused()
  126.         #and… well balls to it we’ll just call ourself.
  127.         changewallpaper()
  128.  
  129.  
  130.  
  131.     #now, the main logic. Choose a wallpaper…
  132.     choosefrom = papers
  133.     #shuffle the choosefrom listing…
  134.     random.shuffle(choosefrom)
  135.     #take one of the items from the resulting shuffled list.
  136.     chosen = choosefrom.pop()
  137.     #add it to the list of seen wallpapers…
  138.     markused(chosen)
  139.     #and attempt to change to it…
  140.     changebackground(chosen)        
  141.     return 0
  142.  
  143.  
  144.  
  145. #parse our options/arguments…
  146. parser = OptionParser(usage="usage: %prog  [options]  ",
  147.                       version="%prog 1.0")
  148. parser.add_option("-g","–gui",
  149. action="store_true", dest="gui", default=False,
  150. help="run GUI")
  151.  
  152. global options,args
  153. (options,args) = parser.parse_args();
  154.  
  155.  
  156.  
  157.  
  158. main()
  159.  
  160.  
  161.  

The script is designed to be used by adding a like to crontab.

Posted By: BC_Programming
Last Edit: 16 May 2012 @ 04:06 PM

EmailPermalinkComments (0)
Tags
Categories: Programming
 10 May 2012 @ 9:48 AM 

A Forum post I’ve decided to graduate to the enviable position of Blog post, Because it reaches my minimum de facto word count and because I haven’t had humourous stories for a while. For the record the first part is true, but I amend the story with a possible TV series adaptation.

RANDOM STORY TIME. this happened almost 10 years ago (9, really) so it might not be 100% accurate, but it was pretty epic. Though it doesn’t have much to do with this topic. Than again this is a rather odd topic to find on this forum regardless so I thought I’d give it some content. No offense.

One time I was at a grocery store. Well, that’s not true. I’ve actually been to them several times, but this was one specific instance. Anyway, what I was getting is neither important, nor do I remember it, though I do remember I also got a few peanuts. This was odd because I’m not usually a peanut person and also because it helped me in a “crowning moment of awesome” to quote tvtropes. Anyway, as luck would have it one of the registers was staffed by one of my friends I had been working up the nerve to ask out. In actual fact that was partially why I chose that store, though the main reason was it was the closest. Nonetheless, opportunity smiled upon me. As I waited in line the customers ahead of me turned out to know her. (Which isn’t surprising, they turned out to be two of those pretentious and inexplicably popular girls that every high school seems to have, though not to the scale that TV and movies seem to suggest. Nonetheless,  They were your typical shallow B-words. Anyway In typical B-word fashion their exchanges with her consisted primarily of passive-aggressive comments. Some high-school crap which I don’t remember and wasn’t important, and was certainly <highly> inappropriate given the setting, but of course being the queen B-words of the school they felt they were above all things. I saw my chance when they said something to the accord of “how do you expect guys to notice you if you don’t look beautiful ” and with that last word she did one of those idiotic things where she shook her hair around. Pretentious git. (This made no sense because the girl in question was pretty bloody good looking if you ask me) I jumped into this, much to all three of their surprise since I was usually the quiet type. “Well, let’s see, I’ve talked to both of you (addressing the “customers”) and I’ve talked to her. With her I’ve had interesting conversations on a variety of subjects and issues, some of which she is clearly my intellectual better; with you two, on the other hand, I believe I would have had an equally intellectual conversation if I was to tape two cantaloupes to a piece of cardboard. Obviously, I cannot speak for all guys, but for myself I’d much rather associate with and be seen with somebody smart like her (at which point I pointed at the girl behind the counter) than either of you two, who on a good day might be able to combine your abilities to match this container of peanuts at checkers with some extensive tutelage”.

CROWNING MOMENT OF AWESOME. When I think of school, that event is the first thing I think of. Naturally, all three of them were speechless. I remember hearing the one person who was behind me in line giggling. They were already done their transaction so they left, and she started to ring me through. “So what am I smarter than you at, exactly?”. “That, you will need to find out on your own.”.
e
After that event, which was one of those stories that just BEGS to be told, our circle of friends started referring to those other two girls as “the cantaloupes”. It was awesome. Then she moved away and I haven’t seen her since. The end. It’s beautiful. I was considering having it made into a television series. With the appropriate plot changes to incorporate explosions. My idea was that it would occur in winter and somehow in the ten minutes I was in the store the entire thing would be covered and snowed in. I’m sure I can cover that with some stupid psychobabble. Maybe I could have a robot that I built that is an expert at human-cyborg relations to explain it. Anyway basically what happens is the weight on the ceiling is intense enough to cause a rafter from the high ceiling to break loose. I would swoop in and grab all three of them and take them to safety, without breaking a sweat, thanks to being ten feet tall and built like a tank. At this point a variant of the above scenario would occur, possibly ending with the drinking of maple syrup. As time wears on the individuals locked inside form alliances and separate into different tribes. dictated mostly by which areas they occupy. For example, there would be the produce tribe, the dairy tribe, and the delicatessen tribe. I make a nemesis, Tim, too. During the second season, everything changes however as we discover that the grocery store is in fact a starship, however the bridge of the ship is in one of those “employees only” doors and as such is protected by a magical force field allowing only employees to enter. This is where my character’s love interest (my past one, but no matter) comes in.(Oh yeah all the other people working there were turned into soup late in the first season by the raiders from the noodle isle.). She’s the only one that can go through the force field, but the moment she steps through it, the U.S.S Quality goes on red alert, which alerts the manager to her presence; he’s been locked in his office since the start of the series locked in his office, because he has a rare disorder that makes him want to tie people up and take them hostage for no reason. So of course she get’s captured and I yell one of those NOOOO things. I was thinking the scene could be a Piano solo by Randy Newman, much like the series intro. Of course, because I’m 10 feet tall and built like a tank (much like my real life self, of course) I manage to use the power of love to break through the employees only force field, with a little help from a bazooka I find in the firearms isle (I guess it’s an American grocery store), and an experimental laser I find in the spice isle, which is a clear case where somebody decided they didn’t want something and just plopped it on the nearest shelf. This only makes me angrier, of course. So I manage to break through and get the Manager to surrender his prisoner. At this point there is a tearful scene:

BC Played by The Rock: I’m here to rescue you! haha, I’ve always wanted to say that. Seriously though you alright? The manager didn’t try to force you to do anything cruel or unnatural, like watch I Love Lucy or anything, did he?
BC’s old love interest whose name started with a K but I’ve embarrassingly forgotten:You’ve changed!
BC Played by the Rock: yeah, I was able to find a change of clothes. It was touch and go there for a while, glad you noticed.
K: No, I mean you’re different now. Now you use violence to solve problems instead of before, where you just sort of let other people deal with it
BC Played by the Rock: yeah, it rules
*this part would be in the spoiler commercial*
K: I’m pregnant.
BC: Cool, I don’t remember the fun part of that, though, which concerns me. Was it really that bad that I blocked it out of my memory?
K: It’s Tim’s
BC: Oh, that’s a relief. I was worried for a momen…. HEY WAIT A SECOND.

And cue ending credits of that episode. naturally played by Randy Newman.

I think it holds real promise myself. It’s better than Lost, at least.

Posted By: BC_Programming
Last Edit: 10 May 2012 @ 09:48 AM

EmailPermalinkComments (0)
Tags
Categories: Programming
 05 May 2012 @ 10:41 PM 

Every single time I write a post that contains source code, it’s a bloody struggle.

Take my previous “snippets” entry.

Normally, I draft it and plan it in advance, and use Editpad Pro on my windows machine to write it out. Now, in a ideal universe where stuff works properly, I would be able to just paste the code in without putting dumbass escapes- that’s what the CMS is supposed to do, manage my content- but no such luck. So, I replace all < with < and all > with > and all that drollish crap that people use software to avoid. It’s especially fun when the blog helpfully assumes I am using some secret tag when I use generics.

Anyway, first problem: well, some of my swapping was wrong. Second, everything was double-spaced thanks to the magic of me making the original textfile on a windows machine (crlf versus just cr).

I had to actually get the original source from the project I based the post on, perform the replacement, paste it into the proper tag, and hope the gods of blog software were smiling upon me.

Long story short- Putting code in posts is more painful than it should be. I sort of expected the add-in I use for highlighting and code blocks to have been smart enough to properly mark-up the text itself without intervention, but no such luck.

Posted By: BC_Programming
Last Edit: 05 May 2012 @ 10:41 PM

EmailPermalinkComments (0)
Tags
 04 May 2012 @ 12:25 AM 

Additional edit: This is exactly the same as what I posted on FB, so if you saw it there already, it doesn’t offer anything new

Disclaimer: Linux is fine, but sometimes the little things just piss you off cumulatively.

Linux Mint 12′s Wifi makes for an interesting case study. The connection is unstable and drops out a lot. Each time that happens it pops up a notification at the bottom of the screen. In fact it’s showing right now “Disconnected – you are now offline”. The fun part is that the notification bar thing it has will even interfere with other windows. I thought I had broken X (the windowing environment) because no menus would show, but once I closed the notification suddenly it worked again.

My favourite part is that the connection/authorization dialog exists twice. First as a standard dialog. But also as this other weird themed dialog that grays the rest of the screen for some reason. Aside from the second one looking like the text was laid out by a mentally retarded koala bear (the text doesn’t even line up with the outline of the textbox, probably because I had the utter gall to change the system font from the default). Aside from that, there is no difference.

of course they both pop up while I’m in the middle of typing something, steal the focus, and then I start typing in the password box, you know, because even though it already has the password it has to ask me again just to be sure. then I have to backspace and retype it again.

And the best part is if I leave it unattended with the wifi on.

If I leave it for a few hours, and come back, it will literally be filled with authorization required dialogs. there was one time where I actually sat there for at least a good minute cancelling those dialogs. I ended up forcing everything closed by force-quitting the X-Server. The pattern is always the same, too.

-Leave system with wifi enabled
-do something
-come back to a bajillion “authorization required” dialogs. meanwhile, the connection is still at 2 signal bars so what it is talking about I’ve no clue. Usually I cannot actually see the desktop because at least half of those bajillion dialogs are the one that fades the screen for no reason, and when you have that many of them the background is just black.

So I press OK on the one on top, which helpfully has the password filled in already, making one wonder why the hell it’s asking me in the first place. This reveals of course the bajillionty other authorization dialogs of the “standard” style, all on top of one another. However for about 5 seconds absolutely nothing responds to mouse clicks, at which point I’m suddenly looking at a desktop with nothing but my wallpaper for another 5 seconds, until suddenly all the windows reappear, in what seems to be a random order. And then I have to click on the taskbar thing at the bottom to select one of the authorization required dialogs, press ok, press another, press OK, ad infinitum. It’s downright bloody ridiculous.

The more I use it the more convinced I become that Linux is nothing more than a hodgepodge of components for which interoperability is a gamble. (Does Program X work with Gnome? with ratpoison? does it work with KDE? Roll the dice and find out, assuming you can even get the damned thing to compile with the equally random collection of libraries you have). The fact that the whole “it’s more customizable” argument is utter tosh because most Linux zealots idea of “customization” is either changing the desktop wallpaper to a single background or writing some idiotic desktop panel applet, which will break, of course, the next time the desktop environment you wrote it for updates. Much like Desktop Drapes. “oh cool,a program to slideshow wallpapers” I thought, which was nice to have, and it worked well. With Mint 12 and Gnome 3 of course that program is utterly useless. It still launches and thinks it’s doing something but the wallpaper never changes because some retard decided that Gnome 3, for whatever reason, would disregard anything coming from a program trying to access it using the Gnome 3 functionality, why? I don’t know. maybe it regards those programs as uncultured. The end result for me was that, by upgrading from Mint 10 to Mint 12, I lost the ability to have a wallpaper slideshow. A feature that should be built into the god damned operating System. So what I ended up having to do was write a python script to do it, which was not fun because programming against any desktop environment seems to involve setting random environment variables and crossing your fingers that some random daemon running on the system will do something useful with that change, then discovering that was the “old way” and Gnome 3 does it a “better way” and by better way they mean that it does the exact same thing but requires a more verbose syntax and relying on yet another external program which itself probably just sets an environment variable. meanwhile, as I write this, the authorization dialog once again jumped at me, insisting I give it information it already bloody well has, so I had to delete a entire phrase I had typed, retype the password, and press enter. Then I wrote the previous sentence, at which point the notification dialog popped up informing me that it was unable to connect. Well thanks I figured that out when you showed me that dialog designed by a banana plant, thank you very much. And the mouse was near the bottom of the screen so for reasons that are beyond the comprehension of us mere mortals the notification managed to steal the focus as well. After breaking from my chain of thought to deal with the most idiotic and pain in the ass UX I have ever had the displeasure of having to use, the authorization dialog popped up once more, even though the connection had been established (which again, flies in the face of the “connection failed” which it had JUST BLOODY TOLD ME). If you are going to notify me of something, make sure that notification is actually bloody accurate and doesn’t come ten minutes after I disconnected and reconnected, because then it makes you seem a little slow. “OH! you disconnected! your OFFLINE!” Yes, thank you Network manager, that was ten minutes ago “OH I NEED your PASSWORD for this access point even though I already have it thought I’d make sure”, “oh ok, here it is” “ok, now just enter it about 500 more times in these other dialogs I put up in the last hour while you were away.”

This all combines nicely with the absolute refusal of syndaemon to do what it is supposed to, which is make it so while I am typing taps on the touchpad don’t move the cursor. Instead what it’s function seems to be, even though I set it to disable tap-clicks for 5 seconds, is randomly make it so the mouse doesn’t move. I’ve had to kill X to get the mouse working, and sometimes that doesn’t work. The word “working” in my last sentence was helpfully inserted into the authorization dialog that decided to steal the damned window focus for the millionth bloody time.

Of course, the answer in the Linux community is to move to another upstream. “Oh, Mint is going to go with Debian instead of Ubuntu as a base”. Well, that’s great, but I don’t see how that solves the elementary UX problems like notifications and random unnecessary dialogs stealing the bloody keyboard focus for no good reason at all, or popping up the same dialog a MILLION BLOODY TIMES. How hard was it to put in a bit of code to check if you were already asking for a password? Actually, how about if you already have a saved password, you don’t prompt at all, that would be great. And it would be just awesome if it actually tried to connect to the access point I told it to and for which I’ve given it the password, instead of going “OH I found this other access point with a higher signal so I’ll just give it the password you gave me for the other one” and then it comes back with a look of surprise when it discovers the password isn’t in fact a skeleton key for all the access points in the area but only for the one access point I told it to bloody connect to.

Posted By: BC_Programming
Last Edit: 05 May 2012 @ 10:21 PM

EmailPermalinkComments (0)
Tags
Categories: Programming
 03 May 2012 @ 3:58 PM 

Naturally, as we write programs we create a small set of useful functions. BASeBlock has been no exception. I’ve created quite a few functions that offer generic functionality that could be used elsewhere. Here, I share some of them.

Value Clamping

Clamping values is a very common activity. It started to get on my nerves, repeating code to make sure a given value was within a range. As a result I conceived of a generic function that could be used for any IComparable.

  1.  
  2.  
  3.  public static T ClampValue<T> (T Value, T min, T max)  where T:IComparable
  4.     {
  5.             //cast to IComparable
  6.         IComparable cvalue = (IComparable)Value;
  7.         IComparable cmin = (IComparable)min;
  8.         IComparable cmax = (IComparable)max;
  9.             //return (T)(cvalue.CompareTo(cmin)< 0 ?cmin:cvalue.CompareTo(cmax)>0?max:Value);
  10.         if (cvalue.CompareTo(cmin) < 0)
  11.         {
  12.             return min;
  13.         }
  14.        else if (cvalue.CompareTo(cmax) > 0)
  15.         {
  16.             return max;
  17.         }
  18.             return Value;
  19.     }
  20.  
  21.  

The basic idea is fairly simple. First, in order to clamp the value, we will need to be able to compare them, so we constrain the function to accepting only type T’s that implement that interface. The first step is casting each value to an IComparable; then we use those variables to compare and return the appropriate value. if the value is larger than max, max is returned; if it is smaller than min, min is returned. otherwise, value is returned unchanged. This function is most useful for numbers, but it can also have interesting implications and usage cases for other classes that are comparable, even strings.

choosing N items from a Enumerable list of S

This also came up quite a lot- some parts of the game needed to randomly choose some set of values from a larger set of values. Naturally this gave birth to another generic routine for the purpose:

  1.  
  2.  
  3. public static T []  Choose<T>(IEnumerable<T> ChooseArray, int numselect)
  4.  
  5. {
  6.     Random rgen = new Random();
  7.     T []  returnarray = new T [numselect] ;
  8.     SortedList<double , T> sorttest = new SortedList<double, T>();
  9.     foreach (T loopvalue in ChooseArray)
  10.          sorttest.Add(rgen.NextDouble(), loopvalue);
  11.        
  12.  
  13.     var usearray = sorttest.ToArray();
  14.    for (int i = 0; i < numselect; i++)
  15.     {
  16.         returnarray [i]  = usearray [i] .Value;
  17.     }
  18.  
  19.     return returnarray;
  20.  
  21.  
  22.  
  23.  
  24.  
  25. }
  26.  
  27.  

The idea is simple- make a SortedList that sorts the given listing using a random value as a key, then take the top numselect items off the top. This code will not work properly if numselect is larger than the size of the enumeration, but using count to clamp the size of the array would enumerate twice.

It’s probably possible to make this faster- possibly much faster- since we only need numselect elements. The core idea here is to shuffle the input array and choose two elements. One flawed approach for shuffling an array is to choose a random index and swap it with another random index, but this has myriad problems since it doesn’t really guarantee that everything is shuffled, and the result could very well have runs of the original card order.

Now, what if we had three objects we wanted to randomly choose from, and we wanted one of them to be chosen more frequently? One way of doing this is to use the above choose function and add duplicate entries. However, this could be tricky if you had odd requirements. This is where the Select<T> function would come in. this function is designed to accept an array and a corresponding array of probability weightings; if all the weightings are equal, than the result should be similar to what we get from Choose. Select accomplishes this by keeping it simple. each array element is essentially assigned a given range within the total, and a random number is generated from the complete total of all weightings. For example, if we had the following elements:

# Name Weight
1 Billy 15
2 Thomas 35
3 Jack 70
4 Selmac 40
5 Patrick 80

We can see that if we generate a value between 0 and 240, than if it is between 0 and 15, we choose Billy, if it is between 15 and 50, we choose Thomas, etc.

Here is the code for the Select Function:

  1.  
  2.  
  3.         public static T Select<T>(T []  items, float []  Probabilities)
  4.        {
  5.     return Select(items,Probabilities,new Random());
  6.        }
  7.  
  8.         public static T Select<T>(T []  items, float []  Probabilities,Random rgen)
  9.         {
  10.             //first, sum all the probabilities.
  11.             //we do this manually because we will also build a corresponding list of the sums up to that element.
  12.             float getsum = 0;
  13.             float []  sumulations = new float [Probabilities.Length + 1] ;
  14.             for (int i = 0; i < Probabilities.Length; i++)
  15.             {
  16.                 sumulations [i]  = getsum;
  17.                 getsum += Probabilities [i] ;
  18.             }
  19.  
  20.  
  21.  
  22.             sumulations [sumulations.Length-1]  = getsum; //add this last value in…
  23.             //get a percentage using nextDouble. we use doubles, just in case the probabilities array uses rather large numbers to attempt to prevent
  24.             //abberations as a result of floating point errors.
  25.             double usepercentage = rgen.NextDouble();
  26.             //convert this percentage into a value we can use, that corresponds to the sum of float values:
  27.             float searchtotal = (float)(usepercentage * getsum);
  28.             //now find the corresponding index and return the corresponding value in the items array.
  29.             for (int i = 0; i < Probabilities.Length; i++)
  30.             {
  31.                 if (searchtotal > sumulations [i]  && searchtotal < sumulations [i + 1] )
  32.                     return items [i] ;
  33.             }
  34.             return default(T);
  35.         }
  36.  

A short test Main() routine that can be used to… test it:

  1.  
  2.  
  3.         static void Main(string []  args)
  4.  
  5.         {
  6.  
  7.             int totalcount = 50000;
  8.  
  9.             String []  names = new string []  { "Bill", "Tom", "Dick" };
  10.  
  11.             float []  probability = new float []  { 50, 20, 30 };
  12.  
  13.             Dictionary <string , int>  countrunner = new Dictionary </string>  <string , int> ();
  14.  
  15.             Console.WriteLine("running simulations…");
  16.  
  17.             for (int i = 0; i > totalcount; i++)
  18.  
  19.             {
  20.  
  21.                 String Selected = Select(names, probability);
  22.  
  23.                 if (!countrunner.ContainsKey(Selected)) countrunner.Add(Selected, 0);
  24.  
  25.                 countrunner [Selected] ++;
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.             }
  34.  
  35.             Console.WriteLine("Completed. Results:");
  36.  
  37.             foreach (var iterate in countrunner)
  38.  
  39.             {
  40.  
  41.                 Console.WriteLine(iterate.Key + "\t\t\t" + iterate.Value.ToString() + " " + ((float)iterate.Value)/(float)totalcount);
  42.  
  43.  
  44.  
  45.  
  46.  
  47.             }
  48.  
  49.  
  50.  
  51.             Console.ReadKey();
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.         }
  64.  
  65.  </string>  

The test is created in such a way that the values can be thought of directly as percentages. The resulting output shows that after a run the occurences of each lie around the percentages as given; Bill appears 50 percent of the time on average, Tom 20 percent, Dick 30 percent, etc. Obviously there is no requirement that the values add up to 100, but the values end up as percentages anyway. (choosing the values 100,40, and 60 for the probability array results in similar results).

This particular method has a bit of a “problem”; what if we run it repeatedly on the same array? Then we are constantly recreating the sumulations array and calculating the totals. How can we cache it? Easy- we use a Dictionary and keep weak references to the given array.

But all is not that simple! This is a generic method and the type T could easily change between calls- so what do we do? Well, it is possible to create a static object that contains a Dictionary indexed by a Type that has a value that is a KeyValuePair<weakreference ,List<T>>, and then inspect the Dictionary for the appropriate values, make sure the cache doesn’t get to big, dispose ofthe WeakReferences that point to arrays that have since been destroyed, blah blah, tricky business. We don’t want that, because for one thing it will be a pain to write- and for another, it will probably be slower overall to begin with. Instead, how about absolving the method itself from the responsibility, and having a ref parameter that can accept a calculated sum array.

For me, the above testing Main() routine took 200ms to execute, on average (I placed calls to System.Diagnostics.Stopwatch members before and after the loop). There was no appreciable difference in speed. Thnakfully, however, the extra logic did not slow it down, either.

The speed improvement can be seen when we have a lot more members. With 5000 members in the probability and Values arrays, and executing a Select on them 50,000 times, the average time was around 5-6 seconds. When the Main function instead gave a float [] ref as the third parameter, the average time dropped to one second. The code for the revised version of the procedure. This also adds some overloads:

  1.  
  2.         public static T Select<T>(T []  items, float []  Probabilities)
  3.  
  4.         {
  5.  
  6.             return Select(items, Probabilities, new Random());
  7.  
  8.  
  9.  
  10.         }
  11.  
  12.         public static T Select<T>(T []  items, float []  Probabilities, Random rgen)
  13.  
  14.         {
  15.  
  16.             float []  sumulator = null;
  17.  
  18.             return Select(items, Probabilities, rgen, ref sumulator);
  19.  
  20.  
  21.  
  22.         }
  23.  
  24.         public static T Select<T>(T []  items, float []  Probabilities, ref float []  sumulations)
  25.  
  26.         {
  27.  
  28.             return Select(items, Probabilities, new Random(), ref sumulations);
  29.  
  30.  
  31.  
  32.         }
  33.  
  34.         public static T Select<T>(T []  items, float []  Probabilities,Random rgen, ref float []  sumulations)
  35.  
  36.         {
  37.  
  38.            
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.             //first, sum all the probabilities; unless a cached value is being given to us.
  47.  
  48.             //we do this manually because we will also build a corresponding list of the sums up to that element.
  49.  
  50.             float getsum = 0;
  51.  
  52.             if(sumulations ==null)
  53.  
  54.             {
  55.  
  56.                 sumulations = new float [Probabilities.Length + 1] ;
  57.  
  58.                 for (int i = 0; i < Probabilities.Length; i++)
  59.  
  60.                 {
  61.  
  62.  
  63.  
  64.                     sumulations [i]  = getsum;
  65.  
  66.                     getsum += Probabilities [i] ;
  67.  
  68.                 }
  69.  
  70.  
  71.  
  72.                 sumulations [sumulations.Length-1]  = getsum; //add this last value in…
  73.  
  74.             }
  75.  
  76.             else
  77.  
  78.             {
  79.  
  80.                 getsum = sumulations [sumulations.Length-1] ;
  81.  
  82.             }
  83.  
  84.  
  85.  
  86.             //get a percentage using nextDouble. we use doubles, just in case the probabilities array uses rather large numbers to attempt to prevent
  87.  
  88.             //abberations as a result of floating point errors.
  89.  
  90.             double usepercentage = rgen.NextDouble();
  91.  
  92.  
  93.  
  94.             //convert this percentage into a value we can use, that corresponds to the sum of float values:
  95.  
  96.             float searchtotal = (float)(usepercentage * getsum);
  97.  
  98.  
  99.  
  100.             //now find the corresponding index and return the corresponding value in the items array.
  101.  
  102.             for (int i = 0; i < Probabilities.Length; i++)
  103.  
  104.             {
  105.  
  106.  
  107.  
  108.                 if (searchtotal > sumulations [i]  && searchtotal < sumulations [i + 1] )
  109.  
  110.                     return items [i] ;
  111.  
  112.  
  113.  
  114.             }
  115.  
  116.             return default(T);
  117.  
  118.         }
  119.  
  120.  

A lot of the above could even be implemented as Extension methods to the appropriate classes, making it seamless.

Since I am working on a game, dealing with vectors and speeds and whatnot is common. One frequent requirement is for items to move at a random angle at a random speed within a given range. The obvious base case here is creating a Vector given a angle and a magnitude:

  1.  
  2.  
  3.  public static PointF GetVelocity(double speed, double angle)
  4.  
  5.  {
  6.  
  7.        return new PointF((float)(Math.Cos(angle) * speed), (float)(Math.Sin(angle) * speed));
  8.  
  9.  
  10.  
  11.  }
  12.  
  13.  

This uses standard trigonometry to calculate what would be the X and Y axes of a fictitious triangle with the given direction as it’s hypoteneuse. Extending from this, we simply create a few extra routines that perform the randomizations:

  1.  
  2.  
  3. public static PointF GetRandomVelocity(double minspeed, double maxspeed, double angle)
  4.  
  5. {
  6.  
  7.     return GetRandomVelocity(minspeed,maxspeed,angle,new Random());
  8.  
  9.  
  10.  
  11. }
  12.  
  13. public static PointF GetRandomVelocity(double minspeed, double maxspeed, double angle, Random rgen)
  14.  
  15. {
  16.  
  17.     return GetVelocity(minspeed + (rgen.NextDouble() * (maxspeed-minspeed)),angle);
  18.  
  19.  
  20.  
  21. }
  22.  
  23. public static PointF GetRandomVelocity(double minspeed, double maxspeed, Random rgen)
  24.  
  25. {
  26.  
  27.    return GetRandomVelocity(minspeed,maxspeed, Math.PI*2*rgen.NextDouble(),rgen);
  28.  
  29.  
  30.  
  31. }
  32.  
  33.  

easy as 3.1415926!

Another interesting endeavour is simplifying the otherwise messy world of Object serialization, such as easily converting a Serializable Object to and from a Stream:

[code]

public static void ObjectToStream<T>(T saveme, Stream outstream) where T : ISerializable

{

BinaryFormatter bf = getFormatter();

using(GZipStream gz = new GZipStream(outstream,CompressionMode.Compress))

{

bf.Serialize(gz, saveme);

}

}

public static T StreamToObject<t>(Stream instream) where T : ISerializable

{

BinaryFormatter bf = getFormatter();

using(GZipStream gz = new GZipStream(instream,CompressionMode.Decompress))

{

return (T)bf.Deserialize(gz);

}

}

[/code]

This also plonks in a bit of compression through the use of a GZipStream.

Anyway, that’s a quick sampling of a few snippets of possible usefulness :)

Posted By: BC_Programming
Last Edit: 05 May 2012 @ 10:35 PM

EmailPermalinkComments (0)
Tags
 29 Apr 2012 @ 8:50 AM 

So I read the paper today. One of the letters to the editor was possibly the stupidest thing I had read in quite a long while, and required a response. I considered writing to the editor myself, but a newspaper is hardly the best place to conduct a flamewar. Besides, no doubt other people would be searching for their cited evidence and come up empty, just as I had. Anyway, here it is.

As someone who is electro-hyper-sensitive, I’m really angry that yet another public service is being denied to me.

That’s right- in the first sentence they essentially claim to have super-powers.

Public buildings – libraries, universities, government offices, hospitals, medical clinics, community centres – and privately-owned restaurants and coffee shops are all infested with “wireless connectivity syndrome”: microwave-emitting cellphones, i-Somethings, Blue Whatevers, Wi-Fi, cordless phones, wireless spy cameras, smart meters, etc.

“Microwave” is a broad term, used to indicate any EM emission between 300Mhz and 300Ghz. This causes confusion amongst those intend on spreading Feay r, Uncertainty, and Doubt because they either do not realize that the spectrum used for cooking and heating items in a Microwave oven are in fact a tiny subset, and are far more powerful than anything emitted by devices such as cellphones or 802.11 networking devices. The common refutation is that Microwaves are “cumulative”. But this is simply false; the specific wavelength used for microwave ovens is designed (or rather discovered by accident) to excite water molecules, which is how it achieves the desired effect of heating or cooking food.

The World Health Organization classified microwave radiation from these gadgets as a Class 2B carcinogen.

What the writer isn’t mentioning here is that “Class 2B” carcinogens are “possible causes”; not verified. More importantly, it is in good company as a class 2B carcinogen; pickled vegetables are in the same category, but anybody crusading against the use of pickles and olives would be classified as insane.

I can’t access those services because my body literally feels microwave radiation inside those buildings. First I itch, then get dizzy and nauseated, lose focus and memory, develop headaches.

the idea of electro-sensitivity is absurd, double-blind studies have shown that proclaimed “electro-sensitive” people report discomfort when they think there is an EM field. It comes as no surprise that these people were crusaders against the evils of newer technology long before they got their “super-powers”.

but long-term effects – DNA damage (cancer, sterility), immune system failure, neurological disorders –will affect us equally.

We have been exposed to various forms of electromagnetic radiation, and in more powerful amounts, for over a hundred years. Power lines, electrical equipment (toasters, ovens, etc) all emit Electromagnetic radiation; junction boxes, light-bulbs, flourescent lights, Television screens, etc all emit EM radiation in similar wavelengths to those used by these later technologies that are being crusaded against. I often wonder why it is only the newer devices being singled-out, particularly since they use far less powerful emissions than those devices we have used for many years without ill effects.

Metal doesn’t always reflect radio waves and EM emissions, for move wavelengths, it absorbs them, because metals have free electrons they absorb EM emissions of most spectral frequencies. (how do you think antennas work?). devices designed to reflect EM emissions need to be designed to do so, and even then will only work at specific wavelengths, such as those- again- used with Microwave ovens.

It’s fun to overgeneralize and assume that because the frequencies emitted by a Microwave oven’s magnetron are reflected by metal, that all EM emissions are, but it’s patently false. Only specific frequencies of EM radiation are reflected by Metals; Microwave ovens happen to use one of this subset specifically because of that property. However, Wireless-G, 802.11, and similar EM devices use wavelengths that are absorbed by metals.

I don’t understand why WorkSafeB.C. allows such gross violations of their own regulations (employees may not be exposed to Class 2B carcinogens if safer options are available) and why our provincial government knowingly microwaves its employees and taxpayers.

Once more, the alarmist jumps out, using the term “microwave” in order to try to connect 802.11g radiation with the EM radiation used for cooking in microwave ovens, the disparity is alarming between these, however; the former- particularly with cellphones and 802.11- are far lower power and of a completely different frequency than the latter, so creating any sort of connection between them is pure FUD. Additionally, I was unable to find any citation as to the regulations stating anything like that; probably because that “regulation” doesn’t exist. Considering such a regulation would be required to prevent employees from eating pickles or olives on the job I’m inclined to believe it’s invented.

The curious thing about this is that the spreaders of such Dark-Age insipid FUD on this issue simply don’t understand some basic principles; first, the EM radiation that they are crusading against is about a million times weaker than that used in a microwave, and the radiation used in a microwave is about a million times weaker than the radiation we are exposed to in direct sunlight. And yet, they seem to have no problems with sunlight.

I propose that the entire thing is based in unfamiliarity and resistance to newer technologies, rather than any genuine concern for health; The sun can cause health problems, but even a second’s worth of exposure is more powerful than a lifetime of using cellphones and other devices. The primary difference is that the Sun has “been there”; it’s an established element. Cellphones and other devices, to many people, are new, unfamiliar, and intrinsically dangerous, not because people don’t understand them, but because those people don’t understand them, nor do they usually understand the principles of electromagnetism, deriving their arguments instead from google searches and unbibliographically sound sources.

Here is an interesting link about “electro-sensitives” and their crusade:

http://www.skepdic.com/electrosensitives.html

My favourite is still the bit about Class 2B carcinogen, and how they said it like it meant it was a deadly poison to be avoided; meanwhile, other things that are classified as Class 2B carcinogens include pickled vegetables. OOOOH SCARY.

Posted By: BC_Programming
Last Edit: 29 Apr 2012 @ 08:50 AM

EmailPermalinkComments (0)
Tags
 17 Apr 2012 @ 4:46 PM 

A quick update on the functionality I was trying to use ReferenceCounted List for in BASeBlock.

I ended up not using the class at all. I actually ended up just using a different method- instead of the powerup changing the drawattributes when it starts and ends, instead it is simply called each frame- basically the character is like “OK, before I draw- you abilities got anything to add” and it will change what it wants as needed. The gamecharacter resets it after drawing so if the ability is removed it will “revert” to normal appearance.

Also, this is possibly my shortest blog post ever. In order to bulk it up- I made some changes to the main page as well as the theme of the blog. The main page’s various images were tweaked, and the blog has had it’s font’s changed because the font it was using was annoying. (Windows Vista and later will be unaffected by the change). BASeBlock now has a “BuilderShotPowerup” thingamajig that let’s you shoot blocks and build stuff, which I think will be useful for building a “bridge” for the GameCharacter, and other purposes. (This idea was Mulreay’s, btw, he has great ideas). I tweaked a lot of stuff such as the editor’s sound data list editor now showing progress and being less annoying to use, and a few general tweaks and minor fixes here and there. I documented it all in the changelog which I will post when I finally upload the new version.

Posted By: BC_Programming
Last Edit: 17 Apr 2012 @ 04:46 PM

EmailPermalinkComments (0)
Tags
Categories: .NET, C#, Personal, Programming
 12 Apr 2012 @ 7:52 PM 

BASeBlock – Music Manipulation Lessons

As with most games, BASeBlock has music. Originally, I implemented a naive approach to have “Multiple music” playing; a simple stack. The multiple music idea is sort of like
how games might change the music to a boss music when a boss appears, and change it back when they die, or how a certain powerup might change the music while you have it.

This implementation sat for a while. it used a stack based approach- the Sound manager had PushMusic and PopMusic methods.

However, several critical flaws in this approach became clear after I added an invulnerability powerup. Everything seemed to work fine, (get the powerup, you’re invulnerable and while you are there is different music) however, the problem became clear when I, while still invulnerable, released a boss. The boss music would start playing; however, while the boss was alive, the invincible power would run out; it would “PopMusic” which would revert the music from the boss music to the starman music, and then only when the boss died would it go back to normal. This is obviously not intended. The ideal case would be:

  1. Player starts level. Level Music is playing.
  2. Player gets invulnerability powerup; invincible powerup music plays.
  3. While invincible, the player, or something causes a boss to spawn.
  4. when the boss is spawned, the invulnerable music can continue until the power runs out; at which point it plays the boss music, or, the boss music can replace the invincible music. The former is probably overall a better idea.
  5. Either way: the music must fit. Invincible music should only play while the player has said powerup; and boss music should only play when there is a boss.

Obviously, my approach failed miserably; it worked fine, but I had only had a single “active” piece of music at a time; how do you manage multiples?

After some thought, I considered the idea of “reference counting” or keeping track of how many times a given piece of music was requested to play. a boss spawning would increment the boss music by one, a second one with the same music would make it two; each time this happens, the sound manager could re-evaluate which piece of music to play based on finding the maximum reference count.

With this idea, I rearchitected some of the code within the SoundManager. The SoundManager (technically cNewSoundManager, since it was a rewrite of a strongly coupled version I had before) is essentially a class that, well, manages sound and music. I have a interface class that allows for different actual implementations of the details of playing sound (“Driver” classes, of you will) The Manager class itself merely deals with the details based on that basic functionality, which exposes a few critical events, such as music stopping and whatnot. The original “PushMusic” and “PopMusic” stack based approach used a small data class, shown here:

  1.  
  2.  
  3.  private class ActiveMusicData
  4.  
  5.         {
  6.  
  7.             public string Name;
  8.  
  9.             public iActiveSoundObject ActiveSound{get;set;}
  10.  
  11.             public iSoundSourceObject Source { get; set; }
  12.  
  13.             public ActiveMusicData(String pName,iActiveSoundObject pActiveSound, iSoundSourceObject pSource)
  14.  
  15.             {
  16.  
  17.                 ActiveSound = pActiveSound;
  18.  
  19.                 Source = pSource;
  20.  
  21.                 Name = pName;
  22.  
  23.  
  24.  
  25.             }
  26.  
  27.  
  28.  
  29.         }
  30.  
  31.  

A minor explanation may be necessary; iActiveSoundObject is an interface class that is implemented by the “driver”; same for iSoundSourceObject; the details of how they work isn’t important, just that their interface methods do what the interface definition says. A Active Sound object is something that is “active” usually, this means it is playing, but it could also be paused. A Sound Source object can be used to “spawn” Active Sound Objects; in order to actually play music or sound, a iActiveSoundSource object is required. Rather than discard this class I extended from it. Arguably, I could have simply changed the actual class itself but that could always be done later:

  1.  
  2.  
  3.         private class TemporaryMusicData:ActiveMusicData,IComparable<TemporaryMusicData>
  4.  
  5.         {
  6.  
  7.             public TemporaryMusicData(String pName, iActiveSoundObject pActiveSound, iSoundSourceObject pSource):base(pName,pActiveSound,pSource)
  8.  
  9.             {
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.             }
  18.  
  19.             public int Occurences; //reference count; we add one to this when a "temporary" music is played. and subtract one when it is "stopped".
  20.  
  21.             //we play the music with the highest "reference count"; items are removed when their "reference count" is zero.
  22.  
  23.  
  24.  
  25.  
  26.  
  27.          
  28.  
  29.             public int CompareTo(TemporaryMusicData other)
  30.  
  31.             {
  32.  
  33.                 return Occurences.CompareTo(other.Occurences);
  34.  
  35.             }
  36.  
  37.         }
  38.  
  39.  

Again, another private class. The Implementation of IComparable is vestigial from when I was flailing around trying to shoehorn the old stack-based approach into the new reference counted method using a SortedDictionary. Then I realized it was stupid and just made the data structure a normal dictionary.

Dictionary<String,TemporaryMusicData> to be precise; This indexes the TemporaryMusicData instances by Name (Key); the Name/Key is used by the sound Manager to index Sound sources, so getting the appropriate source is easy given a name, and it’s guaranteed to be unique since the listing is taken from the file system itself, and the loading routine has other considerations to prevent duplicate entries (and error handling for duplicate key Exceptions if they do occur). The Occurences field is basically the entire purpose here; when “Temporary” music is told to play, it merely increments the field for the appropriate entry at the Named Index; then both the Stop and Play routines will call another routine that Ensures that the item with the maximum occurences is playing. The implementation for the relevant routines:

  1.  
  2.  
  3.  private String OriginalSoundName; //allocated when TemporaryMusicData is empty when music is pushed.
  4.  
  5.         private iSoundSourceObject OriginalSoundObject = null;
  6.  
  7.         //private SortedList<TemporaryMusicData, TemporaryMusicData> TempMusicData = new SortedList<TemporaryMusicData, TemporaryMusicData>();
  8.  
  9.         private Dictionary<String, TemporaryMusicData> TempMusicData = new Dictionary<string, TemporaryMusicData>();
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.         /// <summary>
  18.  
  19.         /// stops music played with the PlayTemporaryMusic function.
  20.  
  21.         /// </summary>
  22.  
  23.         /// <param name="MusicName"></param>
  24.  
  25.         public iActiveSoundObject StopTemporaryMusic(String MusicName)
  26.  
  27.         {
  28.  
  29.             MusicName = MusicName.ToUpper();
  30.  
  31.             if (!TempMusicData.Any()) return mPlayingMusic; //no elements in Temporary Music Dictionary, so nothing to stop.
  32.  
  33.  
  34.  
  35.  
  36.  
  37.             TemporaryMusicData incrementData = getTemporaryMusicData(MusicName);
  38.  
  39.             incrementData.Occurences–; //add one to occurences.
  40.  
  41.  
  42.  
  43.             if (incrementData.Occurences == 0) TempMusicData.Remove(MusicName);
  44.  
  45.             return PlayMax(1.0f, true);
  46.  
  47.  
  48.  
  49.  
  50.  
  51.         }
  52.  
  53.  
  54.  
  55.         /// <summary>
  56.  
  57.         /// Plays "temporary" music; for example the music from a power up.
  58.  
  59.         /// </summary>
  60.  
  61.         /// <param name="MusicName"></param>
  62.  
  63.         public iActiveSoundObject PlayTemporaryMusic(String MusicName,float volume, bool loop)
  64.  
  65.         {
  66.  
  67.             MusicName = MusicName.ToUpper();
  68.  
  69.             //the idea is simple, we want to allow for the following:
  70.  
  71.             //Player starts game. Music playing is standard level music or something.
  72.  
  73.             //player get’s a power up, which has it’s own music. this powerup is timed.
  74.  
  75.             //player causes something else to have different music; for example, they could spawn a boss or something.
  76.  
  77.             //when the powerup runs out, the music will revert to the normal game music; and when the boss is killed, it will go back to the
  78.  
  79.             //music that was playing from the powerup.
  80.  
  81.  
  82.  
  83.  
  84.  
  85.             //This attempts to mitigate this behaviour.
  86.  
  87.  
  88.  
  89.             //step one: if the list is empty…
  90.  
  91.             if (!TempMusicData.Any())
  92.  
  93.             {
  94.  
  95.                 //empty list. Initialize OriginalSoundName…
  96.  
  97.                 OriginalSoundObject = mPlayingMusicSource;
  98.  
  99.                 OriginalSoundName = scurrentPlayingMusic;
  100.  
  101.  
  102.  
  103.  
  104.  
  105.             }
  106.  
  107.             //step two: is there an element in the sorted list for MusicName?
  108.  
  109.             TemporaryMusicData incrementData = getTemporaryMusicData(MusicName);
  110.  
  111.             incrementData.Occurences++; //add one to occurences.
  112.  
  113.  
  114.  
  115.  
  116.  
  117.             return PlayMax(volume, loop);
  118.  
  119.         }
  120.  
  121.  
  122.  
  123.         private TemporaryMusicData getTemporaryMusicData(string MusicName)
  124.  
  125.         {
  126.  
  127.             MusicName=MusicName.ToUpper();
  128.  
  129.             TemporaryMusicData incrementData;
  130.  
  131.             if (TempMusicData.ContainsKey(MusicName))
  132.  
  133.             {
  134.  
  135.                 incrementData = TempMusicData [MusicName] ;
  136.  
  137.             }
  138.  
  139.             else
  140.  
  141.             {
  142.  
  143.                 incrementData = new TemporaryMusicData(MusicName, null, mSoundSources [MusicName] );
  144.  
  145.                 TempMusicData.Add(MusicName, incrementData);
  146.  
  147.             }
  148.  
  149.             return incrementData;
  150.  
  151.         }
  152.  
  153.  
  154.  
  155.         private iActiveSoundObject PlayMax(float volume, bool loop)
  156.  
  157.         {
  158.  
  159. //now, find the one with the maximum occurences.
  160.  
  161.            
  162.  
  163.  
  164.  
  165.             if (!TempMusicData.Any())
  166.  
  167.             {
  168.  
  169.                 mPlayingMusic.Stop();
  170.  
  171.                 //play default.
  172.  
  173.                 scurrentPlayingMusic = OriginalSoundName;
  174.  
  175.                 mPlayingMusic = OriginalSoundObject.Play(loop,volume);
  176.  
  177.  
  178.  
  179.                 return mPlayingMusic;
  180.  
  181.  
  182.  
  183.  
  184.  
  185.             }
  186.  
  187.  
  188.  
  189.             int currentmax = int.MinValue;
  190.  
  191.             TemporaryMusicData tmduse = null;
  192.  
  193.             foreach (var iterate in TempMusicData)
  194.  
  195.             {
  196.  
  197.                 if (iterate.Value.Occurences > currentmax)
  198.  
  199.                 {
  200.  
  201.                     currentmax = iterate.Value.Occurences;
  202.  
  203.                     tmduse = iterate.Value;
  204.  
  205.                 }
  206.  
  207.             }
  208.  
  209.             if (scurrentPlayingMusic != tmduse.Name)
  210.  
  211.             {
  212.  
  213.                 mPlayingMusic.Stop();
  214.  
  215.                 scurrentPlayingMusic = tmduse.Name;
  216.  
  217.                 mPlayingMusic = tmduse.Source.Play(loop, volume);
  218.  
  219.                 return mPlayingMusic;
  220.  
  221.             }
  222.  
  223.  
  224.  
  225.             return mPlayingMusic;
  226.  
  227.         }
  228.  
  229.  
  230.  
  231.  

So far, this has worked well.

However, more recently I found that I also need the same sort of “reference count” management for other things related to powerups, such as the “DrawAttributes” of various objects. But it would be foolish to clutter up that code with this sort of thing. Surely there is some way that I can add the feature with little to no changes to existing code? Turns out, that leveraging a few C# features, this is relatively easily accomplished.

Consider the Nullable<T> class. Any struct or value type can be made “Nullable” using it; there is even a shortcut in the language syntax for type definitions to use it, by appending a question mark, (Nullable is equivalent to int?). What we want is a way to- generically- make a class “reference counted” so that only the value that has the highest reference count “is” the value. The Nullable<T> type can be implicitly cast to type T in most contexts; so you can change a T to a Nullable<T> type with few code changes, which is what we are after.

Enter ReferenceCounted<T>

ReferenceCounted<T> is the name of the class that I created (or, as I write this, am creating) for this purpose. My original idea was to use implicit cast operators to make it a simple type change; assignments to the object of the “old type” (type T) would “automatically” be added to the reference list; going the other way, the ReferenceCounted<T> Type would be implicitly cast to T by way of taking the T value it currently has with the highest reference Count. This hit a snag, however; the second cast, thankfully, would work fine, but the first would not have the proper information; the cast operator is a static routine and wouldn’t have access to the ReferenceCounted<T> Object that is being assigned.

somewhat miffed but not surprised (it would be silly to provide for overloading of the assignment operator, but in this case I wish there was an exception), I didn’t give up; I just thought about it a little. And it hit me- I don’t need to overload the assignment operator to overload assignment; I could overload the addition operator and implement the “assignment” code there; this is what the Event classes do for event hooking; and I could use -= to remove “references”. Arguably, this would take more code and wouldn’t be quite as clean as I was hoping, but for the most part the actual reference counting logic would be out of the way, handled mostly by the implicit cast to T.

After some effort… it was made. Here is the source code:

  1.  
  2.  
  3. using System;
  4.  
  5. using System.Collections.Generic;
  6.  
  7. using System.Diagnostics;
  8.  
  9. using System.Drawing.Imaging;
  10.  
  11. using System.Linq;
  12.  
  13. using System.Text;
  14.  
  15.  
  16.  
  17. namespace System.Collections.Generic
  18.  
  19. {
  20.  
  21.  
  22.  
  23.  
  24.  
  25.    
  26.  
  27.  
  28.  
  29.     /// <summary>
  30.  
  31.     /// Implements a reference counted list of T, allowing for implicit conversion to type T.
  32.  
  33.     /// A "Reference counted list" keeps track of both the items in the list as well as a reference count for each.
  34.  
  35.     /// When an item is added, it’s reference count is incremented. If the item already exists, the existing item has it’s reference count incremented.
  36.  
  37.     /// Equality is determined by default using the Equals Method, but a predicate can be assigned.
  38.  
  39.     /// </summary>
  40.  
  41.     /// <typeparam name="T"></typeparam>
  42.  
  43.     class ReferenceCounted<T>
  44.  
  45.     {
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.         private T lastitem = default(T);
  54.  
  55.         private Dictionary<T, int> ReferenceDictionary= new Dictionary<T, int>();
  56.  
  57.         /// <summary>
  58.  
  59.         /// Returns the Dictionary holding the Elements.
  60.  
  61.         /// </summary>
  62.  
  63.         /// <returns></returns>
  64.  
  65.         public Dictionary<T, int> getReferenceDictionary() { return ReferenceDictionary; }
  66.  
  67.         /// <summary>
  68.  
  69.         /// creates a new ReferenceCounted List Object.
  70.  
  71.         /// </summary>
  72.  
  73.         public ReferenceCounted()
  74.  
  75.         {
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.         }
  84.  
  85.         /// <summary>
  86.  
  87.         /// creates a new ReferenceCounted List Object, with the given IEqualityComparer as the comparison predicate.
  88.  
  89.         /// </summary>
  90.  
  91.         /// <param name="compareobject"></param>
  92.  
  93.         public ReferenceCounted(IEqualityComparer<T> compareobject)
  94.  
  95.         {
  96.  
  97.             //initialize Dictionary with given IEqualityComparer interface.
  98.  
  99.             ReferenceDictionary = new Dictionary<T, int>(compareobject);
  100.  
  101.            
  102.  
  103.  
  104.  
  105.         }
  106.  
  107.         /// <summary>
  108.  
  109.         /// adds the given element to this list; which will either add an nonexistent item to the list and set it’s reference count to 1 or
  110.  
  111.         /// increment the value of the existing element for the given value, as determined by any IEqualityComparer predicate given in the constructor.
  112.  
  113.         /// </summary>
  114.  
  115.         /// <param name="value">Value to add or increment in the list.</param>
  116.  
  117.         public void AddElement(T value)
  118.  
  119.         {
  120.  
  121.             //adds an element to this ReferenceCounted object.
  122.  
  123.             //remove the previous item… or dereference it, rather.
  124.  
  125.  
  126.  
  127.             if (!ReferenceDictionary.Comparer.Equals(lastitem, default(T)))
  128.  
  129.             {
  130.  
  131.                 RemoveElement(lastitem);
  132.  
  133.                 lastitem = default(T);
  134.  
  135.             }
  136.  
  137.             //first, does the given item exist in our dictionary already?
  138.  
  139.             if (!ReferenceDictionary.ContainsKey(value))
  140.  
  141.             {
  142.  
  143.                 //if not, we add it. Add it with a value 0, since it will be incremented after this if.
  144.  
  145.                 ReferenceDictionary.Add(value, 0);
  146.  
  147.  
  148.  
  149.                
  150.  
  151.                
  152.  
  153.             }
  154.  
  155.             //due to the above condition we know the element exists; increment it’s reference count.
  156.  
  157.             ReferenceDictionary [value] ++;
  158.  
  159.             _Dirty = true;
  160.  
  161.  
  162.  
  163.         }
  164.  
  165.         /// <summary>
  166.  
  167.         /// "removes" the given element from this list. This is accomplished by decrementing the appropriate keyed item in the dictionary.
  168.  
  169.         /// If the element is not in this dictionary, this method has no effect.
  170.  
  171.         /// </summary>
  172.  
  173.         /// <param name="value"></param>
  174.  
  175.         public void RemoveElement(T value)
  176.  
  177.         {
  178.  
  179.             if (!ReferenceDictionary.ContainsKey(value))
  180.  
  181.                 return; //nothing to do if no item.
  182.  
  183.  
  184.  
  185.             ReferenceDictionary [value] –;
  186.  
  187.             //if reference count is zero: remove it.
  188.  
  189.             if (ReferenceDictionary [value]  == 0) ReferenceDictionary.Remove(value);
  190.  
  191.             _Dirty = true;
  192.  
  193.  
  194.  
  195.         }
  196.  
  197.         T _CurrentMaximum=default(T);
  198.  
  199.         bool _Dirty = true; //whether the max is out of date.
  200.  
  201.         /// <summary>
  202.  
  203.         /// retrieves the item in this list with the maximum reference count.
  204.  
  205.         /// If multiple items have the maximum, only the first one encountered will be returned.
  206.  
  207.         /// This method also caches the result; calls only calculate a new maximum if necessary. (if the list was changed since the last one was cached).
  208.  
  209.         ///
  210.  
  211.         /// </summary>
  212.  
  213.         /// <returns></returns>
  214.  
  215.         public T getMaxReferenced()
  216.  
  217.         {
  218.  
  219.             //find the item with the maximum value and return it’s key.
  220.  
  221.  
  222.  
  223.             if (!_Dirty) return _CurrentMaximum;
  224.  
  225.  
  226.  
  227.  
  228.  
  229.             //otherwise, we’re "dirty" and need to re-find the maximum again.
  230.  
  231.             int maxfound_int = int.MinValue;
  232.  
  233.             T maxfound_T = default(T);
  234.  
  235.             foreach (var iterate in ReferenceDictionary)
  236.  
  237.             {
  238.  
  239.                 if (iterate.Value > maxfound_int)
  240.  
  241.                 {
  242.  
  243.                     maxfound_int = iterate.Value;
  244.  
  245.                     maxfound_T = iterate.Key;
  246.  
  247.  
  248.  
  249.                 }
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.             }
  260.  
  261.             _CurrentMaximum = maxfound_T;
  262.  
  263.             _Dirty = false;
  264.  
  265.             return _CurrentMaximum;
  266.  
  267.  
  268.  
  269.  
  270.  
  271.         }
  272.  
  273.         //Operator+; designed to be used like events- rather than code using = to "assign" a ReferenceCounted<T> value,
  274.  
  275.         //it will use +=
  276.  
  277.     public static ReferenceCounted<T> operator+(ReferenceCounted<T> firstvalue, T secondvalue)
  278.  
  279.     {
  280.  
  281.         firstvalue.AddElement(secondvalue);
  282.  
  283.        
  284.  
  285.         return firstvalue; //return the ReferenceCounted<T> object.
  286.  
  287.        
  288.  
  289.     }
  290.  
  291.         /// <summary>
  292.  
  293.         /// Operator that calls RemoveElement. The result will be the ReferenceCounted object itself.
  294.  
  295.         /// </summary>
  296.  
  297.         /// <param name="firstvalue"></param>
  298.  
  299.         /// <param name="secondvalue"></param>
  300.  
  301.         /// <returns></returns>
  302.  
  303.     public static ReferenceCounted<T> operator -(ReferenceCounted<T> firstvalue, T secondvalue)
  304.  
  305.     {
  306.  
  307.         firstvalue.RemoveElement(secondvalue);
  308.  
  309.        
  310.  
  311.         return firstvalue;
  312.  
  313.  
  314.  
  315.     }
  316.  
  317.         /// <summary>
  318.  
  319.         /// implicitly converts this list to the type of it’s component.
  320.  
  321.         /// </summary>
  322.  
  323.         /// <param name="value"></param>
  324.  
  325.         /// <returns></returns>
  326.  
  327.     public static implicit operator T(ReferenceCounted<T> value)
  328.  
  329.     {
  330.  
  331.  
  332.  
  333.         return value.getMaxReferenced();
  334.  
  335.  
  336.  
  337.  
  338.  
  339.     }
  340.  
  341.  
  342.  
  343.  
  344.  
  345.      
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.     }
  356.  
  357. }
  358.  
  359.  
  360.  
  361.  

Aftermath

Pleased I had created a nice implementation, I set about creating the Comparison routine. Unfortunately, to my horror and surprise, the class which I wanted to use in conjunction with this class in one instance, ImageAttributes, had no way of getting it’s ColorMatrix. This presented an issue since I didn’t want added ColorMatrix values to mess about with the image, and the results could be less than extraordinary unless I cached each ImageAttributes.

And that was the entire purpose. However I decided to consider how else to acheive my goal; the goal here was to prevent powerups from changing the state of GameObject’s appearance in a manner that prevented them from undoing it. So, for example, powerups might have a limited duration, and the results from a overlap of two powerups could result in a confusing ending state for the object. The idea was to replace the GameObject class’s “DrawAttributes” field with a ReferenceCounted ; then in it’s draw routine, it would assign use that in the appropriate method which would implicitly cast it to the maximum referenced item in the list. All I needed was a way to compare DrawAttributes aside from as references; but the ImageAttributes class, sadly, does not provide this functionality.

So how do I address this?

I considered possibilities, and the problem, a bit more thoughtfully. Evidently, the ReferenceCounted<T> class would be very useful for it, but what would I use it for.

I’ve decided- though not yet attempted to implement- that I would use the ReferenceCounted class to keep track of The powerups themselves rather than a few fields of the gameobject. Since the powerup classes are what would result in the unwanted behaviour, it makes sense. So how does it work? Well, the framework basically allows a GameCharacter to have a list of GameCharacterAbilities; the GameCharacter calls the draw function of each when it draws, and it calls a frame function when it’s own frame function is called. My idea is to change that to a ReferenceCounted<GameCharacterAbility>. The code could then be changed to only call PerformFrame and Draw for the one with the highest reference count, or something similar.

The other possibility is to change the GameObject’s DrawAttributes field to a read-only property that is created “on the fly” from another new ColorMatrix field; the ColorMatrix item could be a ReferenceCounted object and therefore the use of that object in the property would use the implicit conversion operator. I’m trying to avoid this, even though I cannot foresee a circumstance where the ImageAttributes class provides something that I can’t do with a ColorMatrix (oh it does, but nothing I know how to do) I prefer to keep all my roads open, so to speak. If there was a way to compare the innards of the ImageAttributes, I could just change the DrawAttributes field to a ReferenceCounted object and make a new comparer, but it’s unfortunately not that simple.

Posted By: BC_Programming
Last Edit: 12 Apr 2012 @ 07:52 PM

EmailPermalinkComments (0)
Tags
 03 Apr 2012 @ 9:58 PM 

Well, my posts keep getting deleted off the MC forums (arguably mostly because they are responses to a troll, but damn, trolls can be amusing).

Anyway, there was a discussion where some members seemed to agree that RAM never equals performance. My post on the matter was:

What the hell is wrong with you people?

Run Vista/7 on a system with 512MB of RAM.

Upgrade that system to 4GB. The performance improves. If RAM doesn’t increase performance, than this is only explanable because of MAGIC.

RAM improves performance, but only to a certain point. (which is what you guys are saying, just not very well).

For example, even for Minecraft, RAM matters; less physical memory means more swapping means more jerkiness loading chunks. But beyond 4GB, I doubt MC would see any performance improvement, at least not directly; superfetch might cache chunk file data, which would increase chunk loading, and it can only do that with extra memory which wouldn’t otherwise exist, so there is that; but there is a point of diminishing returns. However to state that those returns do not exist is foolish. MC would run better with 32GB of RAM than with 16 or 8; but the difference would be nearly inperceptible, and certainly not worth the massive price difference.

In response, I got the following:

Hey look dumbo fumbo is back…
YOU ARE STUPID!
READ THE POSTS
IT SAYS: Ram isn’t everything, though each system should get a fair amount of it.
CentrallyProcessed just said that.
No one mentioned 512mb of ram, what are you 2002?
No one needs a 10 minute wall of text…
You probably got that off WIkipedia, since that is pure bs in there.
The only time you need 16gb of ram for minecraft is using a biomebuster…
Plus Minecraft only takes up 912mb of ram…
Press f3 and see that…
Unless you change it of course.
If Notch made it so that minecraft takes 912mb of ram, then you can’t argue with him.

Which though an obvious troll, could not go unpunished:

Hey look dumbo fumbo is back…

AHHH MY FEELINGS!

YOU ARE STUPID!

Well that’s not very nice, but I suppose a true friend would be honest. Perhaps everybody else is just trying to protect me from that truth. I commend you on being a true friend and pointing out where I falter. Thank you.

READ THE POSTS

I did. In fact, the one I was responding to- which was echoed in a few other posts, was quoted quite clearly in my posts.
[quote] IT SAYS: Ram isn’t everything, though each system should get a fair amount of it. [/quote]
I find this curious. You say I am stupid, but you are unable to use the appropriate pluralizations. You speak of “posts” (plural) but then you say “it says”. Obviously this is just a slip-up, easily forgiven, but it makes it difficult to understand what specifically you mean, since I wasn’t addressing all the posts, only those that shared in the thought that I felt was mistaken that more RAM never speeds up a PC. One could argue also that I was attempting to dissolve what certainly looked to be a circle-jerk, too.

CentrallyProcessed just said that.

He also said:

“It entirely depends on the CPU and GPU” <

And others said:
“RAM does not equate to performance.” << it does. always.

No one mentioned 512mb of ram, what are you 2002?

They didn’t have computers in 10 A.D so I don’t follow your logic. If I was that old I’d probably be pretty famous.

People mentioned Memory. are you arguing then, that 512MB of memory is not memory? At what size does RAM become RAM? 512MB is a valid amount of memory, and when you add memory to a system with 512MB of memory using a modern OS, performance improves. This is an undeniable fact. replacing 4GB of memory in a system with 8GB will improve performance as well; same with 16GB over 8GB. Whether it improves to a point that makes it worth that investment is questionable, but the improvements do exist.

No one needs a 10 minute wall of text…

Actually, the length of text is typically measured in characters, or words- not time.

You probably got that off WIkipedia, since that is pure bs in there.

Possibly; I am certainly open to refutations of that which I said that are based on intelligent arguments, observations, and other such evidence. Unfortunately, calling me a “dumbo fumbo” does not constitute either an intelligent argument, and observation, or evidence, so I cannot rightly accept that as a valid refutation.

The only time you need 16gb of ram for minecraft is using a biomebuster…

I never said anything about minecraft needing any particular amount of Memory. I said performance would be better, for the most part because of the better utilization of the memory in most cache schemes for keeping file data- in minecraft’s case chunk information- in the standby pool. Whether that increase is negligible was not debated; in fact I specifically pointed out that the difference would not be worth the investment. However whether something is worth the investment and whether there is a difference that exists are two separate points.

Plus Minecraft only takes up 912mb of ram…
Press f3 and see that…

The minecraft F3 debug screen displays the size of the java heap, which directly relates to the size of data that is being used by the uncollected game objects, but has no bearing on the other structures used by the Virtual Machine, nor does it contain memory consumed by objects resurrected during finalization (which hopefully doesn’t happen). The real information on the memory usage can be readily seen using task manager, process explorer, or, on linux, ps -a -v. I started minecraft on my windows system when I started this post, about 5 minutes ago at this point, though don’t put too much weight on that, I’m also conversing in IRC and uploading a few files via FTP); it has been paused since. it’s virtual memory usage- according to process explorer- is now idling at 1.2GB; This was sitting in one place, so that is essentially the minimum it will probably use, at least at the various settings I’ve chosen. if I was to play the game, memory usage would undoubtedly go up as new objects were created, and more chunks were kept in memory and lazily unloaded. However, whether Minecraft uses more memory than is installed cannot be used as the single judge of whether it would improve performance.

You see, Windows, like all modern operating systems, is a protected mode, pre-emptive multi-tasking environment. Processes share memory; this is done by mapping physical memory into the virtual address space of each process, so they all think they “own” memory. this also isolates the memory of each process (‘protecting’ the memory of each application from other applications, giving us the moniker “protected mode”.). Of course, in order to act on memory, it needs to be in physical memory. Memory data in is swapped to and from physical memory as needed by way of a pagefile; if you run an application that allocated over 2 gigabytes of memory, but leave it sitting there, eventually none of it’s data will be in physical RAM, instead replaced by the data of other applications that needed it, and entirely swapped into the pagefile. If you then switch to that application and it accesses some of what it allocated, the required pages will fault, and the memory manager will swap that data back into physical memory.

The advantage here is that because various applications, services, and other applications run at the same time, you cannot think in terms of what a single application would need, because you never have a single application running.

Also, of particular note is that much of the performance improvement from more memory on modern systems is seen by way of disk caching technologies such as Superfetch; more memory means that more of the “unloaded” chunks that minecraft has saved to disk will in fact be saved in memory, meaning that reloading that data from the disk (from the perspective of the game) will occur much faster. These benefits can be seen by comparing a 4GB and a 8GB system; wandering around a world, chunk loading will be slowed by I/O, but returning to some areas will load faster, because those chunk files’ data is still in the cache. with more memory, more of that data can be cached for faster access. Chunk management is a central task performed by minecraft; it is indisputable that improving the speed of that chunk management would improve the overall performance of the game itself. The fact that the memory that is used to create that increased performance isn’t mapped into the virtual address space of the game is not relevant.

If Notch made it so that minecraft takes 912mb of ram, then you can’t argue with him.

Notch didn’t make it that way. that is how the Java Virtual Machine manages the default java heap size. However, as I noted, the java heap size in no way reflects either the total commit charge of the process nor does it have any bearing on the availability of memory for use in tasks such as Superfetch. While I was amused by your attempts at derogatory comments toward me, I refuse to respond in kind. Which is most certainly a benefit in your favour, for my ability with language would certainly come up with something more creative than “dumbo fumbo” which in no way makes sense.

See, the best way to insult somebody is to take advantage of their weaknesses. At the moment, I am unemployed, (well, not legally, but let’s not confuse the issue, we’re trying to insult me, not write a book) so if I may suggest, you should certainly make light of that. Perhaps an insult such as “if you’re so smart why don’t you have a job” or if you want to condense it, “dumbo jobless”. however I think we might be best to eliminate the “dumbo” element altogether, particular since it, at least in my case, provides the image of elephants with big ears, which is actually kind of funny. My ears are not of a disproportionate size, either, so it doesn’t really fit, nor am I sensitive about the size of my ears. However, I’m sure you can think of something! Good luck. I look forward to your intelligent witticisms. Or perhaps you will simply make light of how long my post is! You could surely do that, and it saves you even reading. the bad part is that if somebody does read it, they will see this last part, see your reply, and realize that I in fact predicted your behaviour, which could reflect poorly on your character as being far too predictable.

Unfortunately the post was deleted, both mine and the trolls, which was sort of shame. Good thing I drafted it in gedit. Past here for posterity. Also because it has some interesting info on memory management.

Posted By: BC_Programming
Last Edit: 03 Apr 2012 @ 09:58 PM

EmailPermalinkComments (0)
Tags
Categories: Programming
 25 Mar 2012 @ 1:34 PM 

AMD, like Cyrix VIA, and Nextech (I believe was the name) were all clone makers, they made pin compatible processors for PCs. Their primary advantage was their lower cost. the AMD k5, designed to compete with the Pentium, as a Socket 5 processor just like the Pentium. The idea was that as a lower cost alternative their processors could be used in machines instead of Intel's. AMD, specifically, excelled in integer operations, doing them a lot faster than the equivalent Intel Processor. So in some cases the AMD processor was not only cheaper but also a better choice, if it was for use in applications that did a lot of integer arithmetic. Nextech was working on a new processor to compete with the Pentium and the K6; AMD bought the company and relabelled the in-development Nextech chip the K6-2; the K6 and K6-2 are completely different processors, and not in any way the same (they were basically designed by two different companies). The K6-2 supported a set of 3-D extensions (much like MMX)- whether this was Nextech or AMD that implemented it, I don't remember- at the same time it supported MMX, and it's floating point performance no longer sucked ass, and was very nearly comparable to Intel's offering.

Over time, all the other clone vendors died, or were purchases; VIA, to my recollection, bought Cyrix, made a few processors (the VIA Samuel C3 being the only one I distinctly recall) and then killed their processor division entirely, focusing on their motherboards and embedded solutions. AMD became the only competitor to intel that had any “weight”. Also, as their processors became equal to Intels both in performance and price, they started being made using different Pin designs. I believe this was originally because the socket or slot for some Pentium processor was patented so AMD couldn't make a compatible equivalent; at the very least, the Pentium itself was named the Pentium- rather than the 586- in order to prevent other vendors from using the same name.

One interesting thing about the Pentium Processor is that it is the first CISC instruction set processor to be considered SuperScalar. This is because of it's pipeline architecture which allows it to, in many cases, execute two instructions per clock cycle. The Pentium came in two revisions; the earlier versions didn't have things like MMX, and in many cases had the infamous FPU issue (Intel Errata #23). The second generation came in higher clock speeds (90Mhz, 100Mhz,and 133Mhz, as opposed to the 50 and 75Mhz of their original incarnations), as well as any number of improvements, such as a smaller die size and an on-chip APIC. It didn't have MMX, that was the third revision, which came in even higher clock speeds, FSB/Clock:66/166,66/200,66/233,66/266 (mobile only for the last one). the third revision had MMX, a smaller still die size, lower voltage requirements, a 16KB write-back cache (compared to the earlier versions 8KB). The interesting thing about some pentium boards, including those designed for slot CPUs, is that a lot of them actually had two processor slots. Usually the second one was labelled “for testing only” but you could literally plug in another processor and have dual processors. The only downside is that you pretty much required Windows NT to use them (9x doesn't support multiple cores or processors). Heck that wouldn't even work with XP Home, which only supports a single physical processor.

AMD's lower cost offerings impacted Intel's market, so they came up with their own low-cost alternatives. Which isn't too surprising given they'd been doing that for years, with the 386SX and 486SX, The 386SX being a slower variant of the 386DX, whereas the 486SX was a 486DX with it's FPU disabled. Installing the companion “co-processor”, the 487SX was actually installing a 486DX, which then took over all system operations from the SX. In addition, they created lower-cost upgrade capabilities for the 486, since the k5 was almost feature par with the pentium (and better in some ways, with 6 5-stage instruction pipelines rather than 2). To compete with this they created the Pentium “Overdrive” chip, which would be installed in a 486DX board, and take over all operations from the installed 486DX. Naturally, it was on a 486 board so some operations would still be slow, particularly bus transfers and DMA, but it sped up processor intensive tasks, and sped up a lot of tasks because of that. Later, with the K6 and K6-2 eating into their Pentium II Market share, they came up with another lower cost segment, the Pentium Celeron.

sidebar:*technically, the first Intel 6th generation processor was not the Pentium II, but rather the Pentium Pro*

Of important note is that the first Celerons were not Pentium processors, but rather Pentium II processors; it took a generation for Intel to catch on to AMD's low-cost niche tactic and come up with a response in the celeron. The Celeron was typically a slotted processor, at least all that I've seen are. The basic difference is that it has less on-die cache, and no L2 cache (some revisions had 128KB, compare to the Pentium II's standard 512KB). Ironically, the Celeron usually performed much worse than the K6 and K6-2 it was designed to compete with; Not to mention the awkwardness of the slotted processor design. Even so, and particularly through partnerships with retail computer manufacturers, Intel was able to squeeze the Celeron boards into the market. (the “Barbie” and “Hot wheels” machines from mid to late 1998 are a good example of this, since they sported celeron processors). The Celeron Brand lives on, but it is still a lower cost alternative to their other offerings, and is almost never a wise choice for a desktop machine. Many users are woo'd by the higher clock speed, but with so little cache, the clock speed barely compensates.

The 6th generation gave us the above Pentium II's, Celerons and K6-2s; the seventh gave us Pentium 2s…. Wait? P2s? What about Pentium III's and K6-2s? Well, they aren't 7th gen processors, since they are based on the same die as the sixth gen chips (for Intel, this was the Pentium Pro, for AMD, the K6-2).

The Original Pentium III was practically a Pentium 2 with SSE (MMX2) and a higher clock speed. An interesting sidebar is that the P6 chips from intel (pentium Pro, Pentium II, and Pentium III) are only fully utilized by NT versions of windows; since the Microops that the CISC instructions are reduced to are optimized for use with 32-bit code. windows 9x executes a good half of the time in 16-bit mode (for compatibility with older software, mostly) so you don't get the biggest improvement with it.

Intel failed miserably on their first attempts at a consumer-appealing x64 architecture. The Itanium was 64-bit, but it's execution of 32-bit code had to be fully emulated. It found some uses in business and servers, but it's limited ability with 32-bit code abhorred it's adoption in the consumer sector.

AMD created it's own 64-bit processors, but made it so that 64-bit was just another “mode” of the processor. In this way, 32-bit code could be run quite easy with minimal virtualization. Intel followed suite with their own extensions that implemented the same instruction set as AMD, making it compatible.

I'm not nearly as familiar with their history after around the Pentium III/Athlon XP area.

The two are practically the same now. They offer consumers a choice, but at the same time that choice is practically useless. The fact is that we've pretty much hit the architectural limit that different die configurations can give us, and we are not easily able to reduce the process further without invoking the dangers of quantum tunnelling. The best considerations for the future is to add more processor cores, and, even more important, have software that is better able to extort the best power from those cores. My opinion is that the big problem right now is not the hardware, or the software, but rather the programming languages that are dominant in the industry today, largely C/C++. What is needed is the adoption of one of the myriad languages that have built in support for concurrent execution of constructs; for example, some languages are able to compile a simple for iterative construct in a way that it can execute on separate cores. This approach is particularly powerful in a stateless environment, such as a functional language. to that end many functional languages include built-in concurrency support. What makes this particularly interesting is that most programmers think of “concurrency” and immediately think of threads; but threading is only one of the ways that concurrency can be achieved, and it is one of the least powerful, as well. Erlang, for example, takes the approach of sending messages between processes, instead of having different threads. Since Erlang is a functional' language, most of it's constructs are largely stateless; this is as opposed to most imperative languages which are typically state-heavy. It is the abundance of state in our standardized' programming languages that is causing the difficulties we are seeing with concurrency, not the cores or the implementations thereof. Consider for a moment that most of the benchmarking tools being used to compare processors are he written in C/C++. In order to trust the performance results, you have to trust that the code is making the best use of the available hardware. But the fact is that imperative stateful programming abhors concurrency; threads deadlock, and you have data synchronization issues and race conditions to deal with. So, while processor performance benchmarks might state that a Bulldozer is “worse” than another CPU, I move that that result is as much a testament to weaknesses in the program and the stateful imperative programming paradigm at least with regards to it's use with concurrent solutions. This is why I have never put faith in benchmarks; the fact is that any weakness being shown could easily be an oversight or problem with the software being used to test. If a benchmark tool only uses two threads, how can you trust it's result when it runs on 6 cores? And even if it was to use more, you're still placing your trust in how the program was written. And while one could argue that the test will show how a lot of current software and games run on a given system, it doesn't test the actual potential of that system; a properly written game could be written to take advantage of 6 cores and it would scream compared to running that program with fewer cores. At this point, concurrency is the answer to improving system speed, and in order to properly leverage concurrency, we don't just need more cores, but we need software and programming languages that provide built-in support for concurrency constructs. C/C++ simply does not offer this, and while I'm sure a library could be written that does, there are already loads of languages that provide built-in support for concurrency in any number of different ways; either through C# and .NET's addition of parallel constructs in C# 5.0, or the ability of functional languages to make assumptions because the code is primarily stateless and thus easier to make parallelize.

Personally I don't have a preference for either. I used a K6-2 for nearly 5 years, a Pentium 4 for about a year, and am now using Intel Q8200 and a laptop with a Intel T3200 (I think). Maybe my next build wilent l be AMD, I don't know. Either way, I'm not going to base any of my choices on how a given system performed with a piece of software. The heart of the matter is that I never trust software. I don't even trust software I wrote half the time. Software is a loose thread on a sock. If you pull out the thread, the sock is going to fall down regardless of how well formed the ankle is, and you cannot declare “this ankle sucks, because my sock keeps falling down” just as you cannot say “This hardware sucks, because this piece of software says so”.

Posted By: BC_Programming
Last Edit: 25 Mar 2012 @ 02:45 PM

EmailPermalinkComments (0)
Tags

 Last 50 Posts
 Back
Change Theme...
  • Users » 737
  • Posts/Pages » 112
  • Comments » 38
Change Theme...
  • VoidVoid « Default
  • LifeLife
  • EarthEarth
  • WindWind
  • WaterWater
  • FireFire
  • LightLight

PP



    No Child Pages.

Windows optimization tips



    No Child Pages.