<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-20019204</id><updated>2011-07-07T19:08:02.514-07:00</updated><title type='text'>Q is for Heat</title><subtitle type='html'>James Q. Murphy's notes and observations about .NET programming, astronomy, television, and other facets of life.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>52</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-20019204.post-5125479500938113040</id><published>2011-04-17T19:14:00.001-07:00</published><updated>2011-04-18T06:48:38.531-07:00</updated><title type='text'>"Atlas Shrugged" - The Obligatory Review</title><content type='html'>&lt;p&gt;Shame on you, Paul Johansson.&lt;/p&gt;&lt;p&gt;Many of you saw my brief posting about &lt;em&gt;Atlas Shrugged&lt;/em&gt;.  And most of you knew how much I was looking forward to finally seeing my favorite book portrayed on the big screen.  The previews looked fantastic.  The casting looked great. I couldn't wait.  Then, about halfway through, I realized I was watching the &lt;em&gt;real&lt;/em&gt; train wreck unfolding right before my eyes.&lt;/p&gt;&lt;h1&gt;No Passion&lt;/h1&gt;&lt;p&gt;If I could sum up the movie in one word, it would be "dull."  Most of the characters were flat. The plot was hurried, confusing, and downright nonsensical in places.  The primary conflict of the first part of &lt;em&gt;Atlas&lt;/em&gt; - the race to complete the John Galt line - lacked the sense of urgency that the book portrayed so well.  In the movie, it looked like Dagny was completing the railroad on her own schedule, and that it was smooth sailing. Far from it! Her whole reason for breaking away from Taggart Transcontinental and forming the John Galt line - to complete the line without damage to TT - was depicted as an entrepreneur's indulgence, not as an answer to a crisis. When the first train finally ran, the audience was supposed to feel the triumph and exaltation of overcoming impossible odds. What I felt was more like, "So what?"&lt;/p&gt;&lt;p&gt;Ellis Wyatt's importance was not stressed enough. In the story, his oil company is what keeps the nation afloat.  Without his oil, there would be no gasoline, and no cars on the road.  This is not made clear. When the flat monotone Dagny (played by Taylor Schilling) yells "Noooooo!!!" at the end, it just looks stupid.&lt;/p&gt;&lt;p&gt;And speaking of Dagny, what the heck was that love scene about? Forget about the fact that she threw herself at Rearden, which is &lt;em&gt;not&lt;/em&gt; how it happened in the book.  I think Ned Flanders from &lt;em&gt;The Simpsons&lt;/em&gt;  could have written a steamier scene.  It was completely emotionless and mechanical.  It would have been far better to cut the scene entirely and let our imaginations do the rest.&lt;/p&gt;&lt;h1&gt;A Jumbled Mess&lt;/h1&gt;&lt;p&gt;Actually, they should have cut a lot more, rather than try to cram in as many details.  The film was a jumble of non-sequiturs that confused the audience. It was almost as if the producers were saying, "Hey look! We've included this part! We're staying true to the book!" &lt;/p&gt;&lt;p&gt;The biggest problem I had with the movie was that John Galt showed up at the wrong times.  In the book, he revealed himself to a person at a a critical time, when they realized that the world was against them. Although I could forgive the initial appearance to Midas Mulligan, and maybe even his later appearance to Dick McNamara, I had a big problem with his visit to Ellis Wyatt on the night of the John Galt Line's first run.  That is &lt;em&gt;absolutely&lt;/em&gt; the wrong time to show up.  He was supposed to show up after they passed the legislation that penalized Colorado.  A big miss.&lt;/p&gt;&lt;p&gt;When Rearden was introduced, he was portrayed as the president of Rearden Steel, but you had no idea that he owned his own ore company, coal company, or any of his other enterprises.  Thus, the passage of the Equalization Of Opportunity Bill seems irrelevant, until they show Rearden selling off his businesses.  I'm sure the audience was thinking, "Oh, he owned all that?"&lt;/p&gt;&lt;p&gt;Another example is when Dagny goes to visit Dr. Robert Stadtler at the State Science Institute to ask about their article condemning Rearden Metal, he tells her about his three students at the Patrick Henry University. And I mean, just like that, out of the blue. Why? Even Dagny didn't know why he was telling it ("Dr. Stadtler, I don't see what any of this has to do with Rearden Metal.")  It did &lt;em&gt;nothing&lt;/em&gt; to move the story, and would have been better saved for Part II.&lt;/p&gt;&lt;p&gt;And what's with the ending? Having John Galt show up and announce that he and his buddies have a secret location? Ellis Wyatt announcing to the world that he is on strike?  Maybe Johansson realized near the end that his audience would be totally confused, so rather than fix the film, he would reveal the mystery. I guess Parts II and III aren't coming.&lt;/p&gt;&lt;h1&gt;What They Did Right&lt;/h1&gt;&lt;p&gt;I guess a review wouldn't be complete (or fair) without mentioning what was good about the movie. The most entertaining aspect about the movie was Graham Beckel's portrayal of Ellis Wyatt.  Although physically he looked nothing like the character, his acting was spot-on.  He was outspoken, confident, obnoxious - and fun! &lt;/p&gt;&lt;p&gt;The way they modernized the movie was clever.  The plot starts on September 2, 2016, five years into the future - enough for a looter-driven society to take hold.  The Dow Jones has fallen to 4,000, and is steadily decreasing.  Gasoline is at $37 a gallon - a little too unbelievable, but it gives a nice explanation as to why rail travel has supplanted air travel.  For starters, they modernized it, and it worked.  Atlas Shrugged was published in 1957, when televisions were just becoming mainstream, and long before the age of cell phones and computers.  The movie makes use of news reports to provide backstory, and cell phones to allow the characters to communicate across the continent.&lt;/p&gt;&lt;p&gt;I also liked Patrick Fischler's portrayal of Paul Larkin. He made the most of a secondary character, and it worked well.&lt;/p&gt;&lt;p&gt;All in all, if you are an &lt;em&gt;Atlas&lt;/em&gt; geek like me, by all means, see it, but wait for the DVD. Watch it once, then bury it and forget about this embarrassment of a film.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-5125479500938113040?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/5125479500938113040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=5125479500938113040' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/5125479500938113040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/5125479500938113040'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2011/04/shrugged-obligatory-review.html' title='&amp;quot;Atlas Shrugged&amp;quot; - The Obligatory Review'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-3681547449970869878</id><published>2010-08-11T09:59:00.000-07:00</published><updated>2010-08-11T11:17:15.333-07:00</updated><title type='text'>How not to buy a condo</title><content type='html'>I don't usually do this.  I don't make it a point to dump my personal business online.  It's nobody's business but my own, and most of us have bigger problems anyway.  Besides, most of the time, my life is just not that interesting.  Of course, I usually blog about programming, which is even less interesting, but you know what I mean.  So bottom line -- if you don't care to hear about my personal trials and tribulations, you can safely skip the rest of this post.&lt;br /&gt;&lt;br /&gt;Most of my friends and family know that I'm going through a divorce.  I won't get into that, except to say two things:  (1) it's been going on for a year and a half, and (2) it's what you call an "amicable" divorce.  "Amicable" sounds like it means "friendly," but when it comes to divorces, it more closely means "boring."  And, especially when there are kids involved, "boring" is the best you can hope for.&lt;br /&gt;&lt;br /&gt;Anyway, my wife and I agreed that she would buy out my share of our house, and that I would move to another place in town, in the same school district.  So I looked around, and found a great condo.  How great?  How about a complete finished basement with two extra rooms?  How about a stone's throw from the town's largest park?  How about close enough to my (former) house so that our son could easily bounce between the two places?  I fell in love with this condo, which of course in business is a no-no.  But suffice it to say, it was perfect.  And of course, that's a sure sign that something is too good to be true.&lt;br /&gt;&lt;br /&gt;I actually met my realtor during the showing of the condo.  He was showing the place for someone else in his office.  He's a great guy, a 40-something bachelor-for-life who wasn't pushy and who also showed me some other condos.  But it kept coming back to this place.  He also recommended my real estate attorney to me, another 40-something bachelor-for-life who -- get this -- lives in the same development.  Too perfect, indeed.&lt;br /&gt;&lt;br /&gt;Both my realtor and my attorney recommended a mortgage company called Gateway Funding.  (Actually, another realtor also recommended them to me, but that's another, less interesting story.)  So I went to Gateway and filled out the paperwork and gave them copies of my tax return and let them run my credit.  I should mention that, and I say this with no hint of &lt;em&gt;braggadocio&lt;/em&gt;, that my credit is damn near perfect.  My wife and I scrimped and saved for years.  We didn't go on extravagant trips, we rarely ate out, and we pretty much plowed all of our extra cash (when we had it) into reducing the principal of our house.  And lo and behold, we actually managed to pay it off.  Yep, we owned it free and clear.  Which means it was really easy to execute the buyout.&lt;br /&gt;&lt;br /&gt;So there I am, not a homeowner anymore, but sitting on a pile of cash.  (Don't get me wrong -- I'm still living in my former house, I have plenty of time before I have to move out.  Plus, it's an "amicable" divorce, remember?  Nobody is going to kick anyone out.)  You would think that a former homeowner, with near-perfect credit and a 40% down-payment, would be able to secure a mortgage.  Yeah, I thought so, too -- right up until two days before the closing.&lt;br /&gt;&lt;br /&gt;It started when the mortgage company said they had contacted my condo association, asking for the "deliquency rate;" i.e., the percentage of owners who are late paying their condo association fees.  The number came in at 16%, which was a little high.  In the condo mortgage business, that's a red flag.  Note that 15% is not a red flag, but &lt;em&gt;greater than 15%&lt;/em&gt; is.  So they asked for a little more information, including proof of fidelilty bond insurance.&lt;br /&gt;&lt;br /&gt;And just what is fidelity bond insurance?  It's basically insurance that a company can take to protect itself from theft, etc.  Gateway Funding -- or at least, the underwriter behind Gateway -- wanted to see it.  And guess what?  They didn't have it.  So, two days before closing, after the moving trucks have been ordered (on both sides), the insurance obtained, and all that other good stuff, I was told that they couldn't give me the loan.&lt;br /&gt;&lt;br /&gt;I did wind up calling the condo association and spoke with the manager.  He told me that this was the first time that a mortgage company asked for proof of fidelity bond insurance.  He also told me that, a few months ago, he recommended to the board that they get it, but it was voted down.  I asked if I could show up at the board meeting and tell my story -- but he told me he would tell them the story.  I also suggested he ask the board how it felt that their condos were unsellable.  He laughed. They are definitely pursuing the bond insurance now.&lt;br /&gt;&lt;br /&gt;What makes things worse was that apparently, the 16% deliquency rate wasn't really that accurate.  Although association fees are due by the 1st, they aren't considered delinquent unless unpaid by the 15th.  So the actual number was 7%.  So the mortgage company told me, "good news.  We can get you the loan."&lt;br /&gt;&lt;br /&gt;But the next day, the story changed again.  Apparently when the mortgage company told their underwriter about the discrepancy, the underwriter said, "well now you are changing the information.  This is an even bigger red flag, so tell the association that they need all this additional documentation."&lt;br /&gt;&lt;br /&gt;The mortgage company told me to wait a few weeks while the association was getting their fidelity bond insurance.  I told them I was tired of being jerked around, and told them to go to hell.&lt;br /&gt;&lt;br /&gt;So... the following day, my wife gave me the number of one of her friends, who works at a mortgage company.  By the end of the day, I was preapproved at a different mortgage company.  For a better rate, I should add.  See?  I told you it was amicable.&lt;br /&gt;&lt;br /&gt;But what about the deal?  Well, obviously, the closing is now moved for at least a month.  You would think the sellers would be pissed -- and indeed they were.  But they called me -- that's right, the sellers called me directly,which is also a no-no, but it was a sincere gesture.  I had met them twice before, once during a showing , and a second time during a private inspection.  They are nice people, and they wanted to know if I would be interested in moving in and renting the place from them.&lt;br /&gt;&lt;br /&gt;Of course, I still don't want to cancel my moving truck, and for many reasons, I need to move out of my (former) house and into a place of my own.  So as we speak, our lawyers are drafting up a rent and occupancy agreement.  This takes the time pressure off, and with any luck, I'll be moving into my new place soon, even if the closing doesn't take place for another month.&lt;br /&gt;&lt;br /&gt;And one last note:  Gateway called me back and told me that, assuming the association got the fidelity bond insurance, they would still grant me the mortgage.  Gee, where have I heard that before?  They even told me they would lower my rate (which still wasn't as good as the other rate).  What fun to tell them to go to hell a second time.&lt;br /&gt;&lt;br /&gt;These loan conditions regarding the association were not in my contract -- at least, not that I could find.  That's what annoyed me the most.  That, and the fact that I didn't know about the problem until two days before closing.  I am a little mad at the association, but most of my anger is at the mortgage company.&lt;br /&gt;&lt;br /&gt;The moral of the story?  If you're going to buy a condo, ask about the things they want to see in the association.  And find out yourself, first.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-3681547449970869878?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/3681547449970869878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=3681547449970869878' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/3681547449970869878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/3681547449970869878'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2010/08/how-not-to-buy-condo.html' title='How not to buy a condo'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-1783371414515486388</id><published>2009-11-07T06:43:00.000-08:00</published><updated>2009-11-07T07:38:07.032-08:00</updated><title type='text'>The Secret to a Great Cartoon</title><content type='html'>&lt;a href="http://2.bp.blogspot.com/_a1hW33LXt50/SGYF7N7Z8TI/AAAAAAAAAkw/64J15GERP1o/s320/paf.jpg"&gt;&lt;img style="WIDTH: 320px; HEIGHT: 239px; CURSOR: hand" border="0" alt="" src="http://2.bp.blogspot.com/_a1hW33LXt50/SGYF7N7Z8TI/AAAAAAAAAkw/64J15GERP1o/s320/paf.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;"Dad, why don't we have a panic room?"&lt;/div&gt;&lt;br /&gt;&lt;div&gt;When it comes to questions from kids, I consider myself well prepared. If they want to know why the sky is blue, I can give an age-appropriate description of Rayleigh scattering. If they want to know about the "birds and the bees," I'm ready for that talk too. Nothing is taboo; good, honest, unbiased information is what kids need.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;But this question from Nicholas threw me. "Where did you hear about panic rooms?" I asked, wondering if the kids at his school were watching a Jodie Foster marathon and if I'd have to explain what exactly Hannibal Lecter was trying to smell in that one scene.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;"It was on &lt;em&gt;Phineas and Ferb&lt;/em&gt;. Candace said she was going down to the panic room for a while."&lt;/div&gt;&lt;br /&gt;&lt;div&gt;"Oh!" I said with relief. "Basically, it's because it's too expensive. We're saving for your college first. And frankly, our house will need a new roof before it needs a panic room." Truth is, I'd love having a panic room, but I would make mine look more like a finished game room, complete with TV, pool table, and fridge. (Wouldn't a fridge stocked with glucagon have come in handy during the movie!)&lt;/div&gt;&lt;br /&gt;&lt;div&gt;If you've never seen &lt;em&gt;Phineas and Ferb&lt;/em&gt;, you are missing out on a great show. I've known and watched all the shows that Nicholas has been into, ever since Elmo and the Playhouse Disney days. I'm a fan of &lt;em&gt;SpongeBob Squarepants&lt;/em&gt; (although I didn't see the latest special yet), I can quote episodes of &lt;em&gt;Chowder&lt;/em&gt;, I love &lt;em&gt;Penguins of Madagascar&lt;/em&gt; and &lt;em&gt;Back at the Barnyard&lt;/em&gt;, and I can even identify a good number of Pokémon. So when Nicholas was getting bored with TV, I suggested to him what some of my coworkers suggested: switch over to the Disney channel (of all things!) and give &lt;em&gt;Phineas and Ferb&lt;/em&gt; a try. We both love the show! I won't go into too many details about the show -- you can read about it anywhere on the web -- but believe me, you are in for a treat.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;So I got to thinking of what makes a great cartoon. And when I mean great, I mean timeless. Every once in a while, I'll pop a Warner Brothers DVD in and watch "Baseball Bugs." ("Wham! A homer! Wham! Another homer!") Still great stuff, but why?&lt;/div&gt;&lt;br /&gt;&lt;div&gt;The obvious answer is, well it's because of all the adult humor. But it's more than that. True, you do need humor in a cartoon, as well as good strong characters. I think the main measure of a cartoon's staying power is &lt;strong&gt;how well it relates to the real world&lt;/strong&gt;. If a cartoon is grounded in real-world references, it will appeal to adults as well as children and it will be talked about by everyone. &lt;em&gt;Phineas and Ferb&lt;/em&gt; references a lot of cultural icons, like 80's hair bands ("Love Handel"), monster trucks, and, of course, panic rooms. The same thing can be said of &lt;em&gt;SpongeBob Squarepants&lt;/em&gt;; one episode ("The Krusty Sponge") actually mocked SpongeBob merchandising itself. And you can't help but laugh at the &lt;em&gt;American Idol&lt;/em&gt; parody "Do You Gots It?" found in an episode of &lt;em&gt;Back at the Barnyard&lt;/em&gt;.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Contrast this with shows like &lt;em&gt;Ben Ten&lt;/em&gt;. Oh it's a good show, don't get me wrong, but it has limited appeal. It just doesn't tie into &lt;em&gt;anything&lt;/em&gt; in the real world. And I challenge you to look at &lt;em&gt;Chaotic&lt;/em&gt; or &lt;em&gt;Bakugon&lt;/em&gt; and pick out anything "real" about them. You'll hear very few adults yelling "Bakugon Brawl!" in the workplace, and those that do will get very strange looks.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;But sing "Agent P!" in the office, and watch how many parents will sing back "Doofenshmirtz Evil Incorporated!" (Of course, you have to sing it the &lt;em&gt;right&lt;/em&gt; way...)&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-1783371414515486388?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/1783371414515486388/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=1783371414515486388' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/1783371414515486388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/1783371414515486388'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2009/11/secret-to-great-cartoon.html' title='The Secret to a Great Cartoon'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_a1hW33LXt50/SGYF7N7Z8TI/AAAAAAAAAkw/64J15GERP1o/s72-c/paf.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-3543386991961829012</id><published>2009-09-06T15:01:00.000-07:00</published><updated>2009-09-06T15:38:12.673-07:00</updated><title type='text'>Did 1996 music really suck that much?</title><content type='html'>I don't have satellite radio.  So whenever I drive to other cities, I have to use the seek button and look for good stations.  Ok, it's a bit of a pain, but I do love it when I find a good station.  And when I went to Baltimore last week, I found one of those "play whatever we want" stations.  In this case, it was WQSR 102.7 -- or as they say it, &lt;a href="http://www.1027jackfm.com/"&gt;102.7 JACK FM&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It was Monday morning, around 9am.  They had a segment where they would play 15 songs from a given year, and that day, they chose 1996.  So I turned my personal wayback machine to 1996, and got myself back into that state of mind.  It was the year that Lisa and I bought our house.  I was working at Betz Laboratories, at my first "real" programming job.  Cool!  So what was playing?  Here's what I heard:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;"Missing" by Everything but the Girl (you know, "... like the deserts miss the rain")&lt;/li&gt;&lt;li&gt;"Change The World" by Eric Clapton&lt;/li&gt;&lt;li&gt;"It's All Coming Back To Me" by Celine Dion (all 7:36 of it).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Then it was time for a commercial.&lt;br /&gt;&lt;br /&gt;Good God, I thought.  Did all the music from 1996 suck that much?  There had to be &lt;em&gt;something&lt;/em&gt; good from that year.  It was the year after Alanis Morissette released "Jagged Little Pill", so maybe one of those songs would be there, hopefully?  And what about "I Love You Always Forever" by Donna Lewis?  That was a cute little song, and I remember it was playing the night when Lisa and I drove to our new house.  So even though we had almost arrived at the Baltimore Aquarium, I thought I'd give it a few more minutes, hoping that a "good" song from 1996 would be played after the commercial break.&lt;br /&gt;&lt;br /&gt;It was "Macarena" by Los Del Rios.  What's even sadder is that I like that song more than the first three!&lt;br /&gt;&lt;br /&gt;So I made a note to check with the Internet.  I said to the Internet:  Hey Internet!  What were the popular songs from 1996?  And by using a clever little query, Google gave me &lt;a href="http://www.infoplease.com/ipea/A0150434.html"&gt;this site&lt;/a&gt;.  And I was right.  The music from 1996 did suck, at least in my opinion.  Go have a look!&lt;br /&gt;&lt;br /&gt;Well, not all of it.  Two songs from Jagged Little Pill did make the list:  "Ironic" and "You Learn", which are two of the better songs (especially"You Learn.")  "I Love You Always Forever" was there as well.  And I could only find two other songs that didn't suck:  "1979" by Smashing Pumpkins, and "Name" by the Goo Goo Dolls.  Too bad "Name" was overplayed -- it became the "tired song" on the "tired radio."&lt;br /&gt;&lt;br /&gt;Even Rush's album "Test for Echo" wasn't &lt;em&gt;that&lt;/em&gt; great, although I love "Half the World."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-3543386991961829012?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/3543386991961829012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=3543386991961829012' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/3543386991961829012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/3543386991961829012'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2009/09/did-1996-music-really-suck-that-much.html' title='Did 1996 music really suck that much?'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-2584553346906212170</id><published>2009-08-10T18:00:00.000-07:00</published><updated>2009-08-10T19:03:48.910-07:00</updated><title type='text'></title><content type='html'>And now for something unexpected... coding!  Since this is the first time that my blog is hooked to my FaceBook account, I feel I should give this warning:  Geeky article ahead!  Seriously, if you're not a programmer, you won't find this article very interesting.&lt;br /&gt;&lt;br /&gt;In this case,  I'm talking about SharePoint -- not just SharePoint, but a SharePoint publishing site that we recently deployed.  I won't bore you with the details on how we settled on SharePoint.  But I will share a little story about how I forgot the finer details of thread synchronization.  I spend way too much time on nontechnical tasks, but that's another article.&lt;br /&gt;&lt;br /&gt;Here's a quick overview of our publishing site.  Think of it as a knowledge base.  Each article gets its own page (e.g., /Pages/Abc.aspx).  Each article also gets a folder with the same name (/Documents/Abc).  On the page, we have a web part that displays a list of the documents in the folder, as well as some custom properties.   So far, so good.  For performance reasons, once the list of documents is read, the web part caches it inside the HttpRuntime cache.  (The cache gets invalidated if a new document is published, and once each night during the app pool recycle.)&lt;br /&gt;&lt;br /&gt;To further increase performance, I intended to use a lock so that if 50 users request a page, the web part would only build the list once, and the other 49 users would simply wait for the list.  Simple locking scheme, eh?  I thought so.  Remember, I said it's what I &lt;em&gt;intended&lt;/em&gt; to do.  What follows is a reasonable representation of my code.  Here I show a DataSet used as a cached object, but in reality I used a custom data structure.  Plus, I'm leaving a lot out.  Anyway, here's the first pass:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;private static object _lockObj = new object;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DataSet ds = HttpRuntime.Cache.Get(key) as DataSet;&lt;br /&gt;if ( ds == null )&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;lock ( _lockObj )&lt;br /&gt;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ds = HttpRuntime.Cache.Get(key) as List&lt;Material&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( ds == null )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ds = FetchDataSet(...);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HttpRuntime.Cache.Insert(key, ds);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch ( Exception e )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LogException(e);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Great, except for one problem.  See that static object used as a lock?  Well it can't be a local object, that's for sure -- each page request would get a brand new local object, which would be useless for locking purposes.  But the problem with a static object is that it is common for the entire application.  Which means, that if 10 users are querying 10 different pages, each page would encounter the same lock and wait for the previous one to finish!  As you can imagine, performance was dreadful.  Even worse, our performance tests did not account for this use case -- which was, in some ways, a more serious flaw than the code itself.&lt;br /&gt;&lt;br /&gt;What I wanted was page-level locking.  So what to do?  Well, I remembered an article I had read waaay back in MSJ -- but I can't seem to find it (and I've looked!)  The article was written back in the days of C++ and Win32 critical sections.  It explained a technique that let you have thousands of objects appear to each have its own private critical section.  The idea was simple -- create a fixed pool of critical sections, store them in an array, then have each object always use a dedicated critical section.  The odds that two objects would use the same critical section were low.  A well-written, reliable hash function would do the trick.&lt;br /&gt;&lt;br /&gt;So I adopted this technique to our web part.  The code remained relatively unchanged, except for the part that determined which object to use as a lock.  In this case, I took the key and used its hash code to determine which lock was used.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;private const int LOCK_POOL_SIZE = 50; &lt;br /&gt;private static object[] _lockPool = new object[LOCK_POOL_SIZE]; &lt;br /&gt;static Class1() &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;for (int i = 0; i &lt; LOCK_POOL_SIZE; i++) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_lockPool[i] = new object(); &lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;DataSet ds = HttpRuntime.Cache.Get(key) as DataSet;&lt;br /&gt;if ( ds == null )&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;int lockIdx = Math.Abs(key.GetHashCode()) % LOCK_POOL_SIZE;&lt;br /&gt;&amp;nbsp;&amp;nbsp;object lockObj = _lockPool[lockIdx]; &lt;br /&gt;&amp;nbsp;&amp;nbsp;lock ( lockObj )&lt;br /&gt;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ds = HttpRuntime.Cache.Get(key) as List&lt;Material&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( ds == null )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ds = FetchDataSet(...);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HttpRuntime.Cache.Insert(key, ds);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch ( Exception e )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LogException(e);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This worked well enough -- except for one further problem.  What if, for some reason, the code that loaded the data failed?  What if FetchDataSet throws an exception?  Well, the cache would never be filled -- which would result in many requests waiting, waiting for a cache that would never fill, essentially backing up the requests until ASP.NET started queueing requests.&lt;br /&gt;&lt;br /&gt;My solution to that was to insert a "poison" object into the cache -- but for only a few minutes.  In this case, the "poison" object was an empty DataSet, but you could put in whatever you need.  This would alleviate the lock condition, allow the code to display an error, but also allow the problem to be addressed and the code to self-correct.  (Sidebar: When dealing with SharePoint, 99% of the time, these "problems" are permissioning setup problems.  And yes, we developer have had to solve a fair number of these.)&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;private const int LOCK_POOL_SIZE = 50; &lt;br /&gt;private static object[] _lockPool = new object[LOCK_POOL_SIZE]; &lt;br /&gt;static Class1() &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;for (int i = 0; i &lt; LOCK_POOL_SIZE; i++) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_lockPool[i] = new object(); &lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;DataSet ds = HttpRuntime.Cache.Get(key) as DataSet;&lt;br /&gt;if ( ds == null )&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;int lockIdx = Math.Abs(key.GetHashCode()) % LOCK_POOL_SIZE;&lt;br /&gt;&amp;nbsp;&amp;nbsp;object lockObj = _lockPool[lockIdx]; &lt;br /&gt;&amp;nbsp;&amp;nbsp;lock ( lockObj )&lt;br /&gt;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ds = HttpRuntime.Cache.Get(key) as List&lt;Material&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( ds == null )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ds = FetchDataSet(...);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HttpRuntime.Cache.Insert(key, ds);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch ( Exception e )&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LogException(e);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HttpRuntime.Cache.Insert(key, new DataSet(), null, DateTime.UtcNow.AddSeconds(120), System.Web.Caching.Cache.NoSlidingExpiration);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And there you have it.  Note that you can change the lock pool size to fit your own needs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-2584553346906212170?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/2584553346906212170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=2584553346906212170' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/2584553346906212170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/2584553346906212170'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2009/08/and-now-for-something-unexpected.html' title=''/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-3418273534707753350</id><published>2009-01-27T19:32:00.000-08:00</published><updated>2009-01-27T19:43:04.892-08:00</updated><title type='text'>She's coming back!</title><content type='html'>Yep, she's back.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/presspass/images/features/2007/04-24AsliBilgin-color_sm.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 184px; height: 207px;" src="http://www.microsoft.com/presspass/images/features/2007/04-24AsliBilgin-color_sm.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I'm talking about Asli Bilgin, of course.  A few years ago, she (along with some other Microsofties) came to Merrill Lynch and &lt;a href="http://jamesqmurphy.blogspot.com/2007/01/occasionally-we-have-presenters-from.html"&gt;talked about .NET 3.5&lt;/a&gt;.  Well now she's back and she's going to be talking about .NET 4.0.  Can you tell I'm excited!  What's not to love... a cute babe talking about technology.&lt;br /&gt;&lt;br /&gt;This time, however, I won't be asking about the Gaming Engine.  For the moment, I've lost the passion for the Gaming Engine.  Hopefully, it will return someday.&lt;br /&gt;&lt;br /&gt;But for now, I'll just enjoy the talk from Ms. Bilgin.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-3418273534707753350?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/3418273534707753350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=3418273534707753350' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/3418273534707753350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/3418273534707753350'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2009/01/shes-coming-back.html' title='She&apos;s coming back!'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-7745366065324449163</id><published>2008-12-27T08:17:00.000-08:00</published><updated>2008-12-27T13:43:48.856-08:00</updated><title type='text'>Lazer Tag is Tres Cool!</title><content type='html'>I have a love-hate relationship with Hasbro.  For a while there, it seemed the company had lost its creative edge, and only made lame toys or re-hashed versions of older toys.  Being a fan of the old Worlds Of Wonder Lazer Tag from the late 80's, I was reasonably suspicious of the new Lazer Tag game by Hasbro.  But oh was I pleasantly surprised... this new version is a cool product, and in my opinion is &lt;b&gt;way superior&lt;/b&gt; to the WOW version.&lt;br /&gt;&lt;br /&gt;Nicholas got it for Christmas.  Naturally, guess who he's playing it with?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_zPXCucVdm2g/SVZb1fO5AHI/AAAAAAAAAD8/UHylQGWeruQ/s1600-h/IMG_2378.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_zPXCucVdm2g/SVZb1fO5AHI/AAAAAAAAAD8/UHylQGWeruQ/s400/IMG_2378.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5284512187241005170" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is what you get in the box (plus instructions):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_zPXCucVdm2g/SVaXmQokcaI/AAAAAAAAAGg/NolrIk33kbg/s1600-h/IMG_2381.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_zPXCucVdm2g/SVaXmQokcaI/AAAAAAAAAGg/NolrIk33kbg/s400/IMG_2381.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5284577896321806754" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You can see that the guns (or "taggers", as they are called) have the target mounted right on the guns themselves (the red dome at the top).  The guns also come with the ability to add attachments.  The big attachment shown above is the "Shot Blast" attachment, which adds grenade-throwing ability.  (More on this in a sec.)  Instead of the Shot Blast, you can attach the video game module (that blue thing on the right) instead.  Alas, the video game module only works with old-fashioned CRT televisions, and you need a video attachment as well.  The other little attachment that goes on top of the gun is a scope, which displays a little green dot to help you aim better.  Each gun takes six AA batteries.&lt;br /&gt;&lt;br /&gt;The first thing you notice is the array of switches all over the gun.  Here are the various switches:&lt;ul&gt;&lt;li&gt;The power switch, which also can select solo mode (free-for-all), Team 1, or Team 2.  During team play you cannot hit your own team members.&lt;/li&gt;&lt;li&gt;A 10-or-25 strength setting (i.e., hit points)&lt;/li&gt;&lt;li&gt;An indoor/outdoor switch (presumably affects accuracy)&lt;/li&gt;&lt;li&gt;A small lever which releases the ammo clip (not all the way).  The lever is present on both sides, to accommodate right- or left-handed individuals.&lt;/li&gt;&lt;li&gt;Two triggers; one for firing and one to activate the shields.  Yes, shields.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;There are also two gauges on the rear of the pistol.  The one on the left shows your strength (i.e., health or hit points), the one on the right displays your ammo:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_zPXCucVdm2g/SVabGTz1l1I/AAAAAAAAAGo/d7T-F1ua658/s1600-h/IMG_2384.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_zPXCucVdm2g/SVabGTz1l1I/AAAAAAAAAGo/d7T-F1ua658/s400/IMG_2384.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5284581745465071442" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It's one thing when you hold one of these pistols in your hand.  But when you fire it -- wow!  Inside the gun there is a recoil mechanism, which gives a satisfying kick to your hand and an even more satisfying clicking sound.  It actually feels like you fired a round.   And the speed!  You can easily shoot 3 rounds a second.  (The old WOW pistols could barely shoot once per second.)  If you have the Shot Blast attachment on, then you have grenade-launcher ability.  Simply pump the gun, then fire, and you essentially do a triple-shot.  The gun also rumbles when you are hit.&lt;br /&gt;&lt;br /&gt;One big difference is the reload feature.  After six shots, you have to reload.  But Hasbro took this potentially annoying feature and made it &lt;b&gt;fun&lt;/b&gt;.  You hit the lever with your thumb, which extends the "clip" out about half an inch (it also lights up).  A quick, satisfying slap with your free hand, and you're good to go.  The grenade launcher does not use any ammo.&lt;br /&gt;&lt;br /&gt;Another difference is the shield.  During a game, you get 10 seconds of health during a 10-strength game, 25 seconds during a 25-strength game.&lt;br /&gt;&lt;br /&gt;I've been playing this with Nicholas, and I cannot wait to introduce this to my friends.&lt;br /&gt;&lt;br /&gt;I'm still lukewarm on Hasbro's online presence.  If you go to &lt;a href="http://www.lazertag.com"&gt;LazerTag.com&lt;/a&gt;, it simply redirects to Hasbro's site.  According to the directions, the site would list the products that Lazer Tag was compatible with.  Yeah, at the bottom of the "Game Tips" section, I found a paragraph that states the game is compatible with Lazer Tag Team Ops, an earlier Hasbro product.  The rest of the site has a few interesting things (like various ideas of games you can play).&lt;br /&gt;&lt;br /&gt;Ok, but is the game compatible with the old WOW Lazer Tag?  No, it isn't -- I tried.  That would have been nice.  But after playing with these pistols, I don't even want to &lt;b&gt;touch&lt;/b&gt; my old Lazer Tag.  Seriously.  It's that good.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-7745366065324449163?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/7745366065324449163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=7745366065324449163' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7745366065324449163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7745366065324449163'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/12/lazer-tag-is-tres-cool.html' title='Lazer Tag is Tres Cool!'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_zPXCucVdm2g/SVZb1fO5AHI/AAAAAAAAAD8/UHylQGWeruQ/s72-c/IMG_2378.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-6027465660133803217</id><published>2008-12-04T18:59:00.001-08:00</published><updated>2008-12-04T19:01:28.864-08:00</updated><title type='text'>Gotta get in the picks</title><content type='html'>Here's what my program picked for week 14.  And I swear it didn't know that San Diego is currently killing Oakland:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;OAK at  SD:  SD&lt;br /&gt;JAC at CHI:  CHI&lt;br /&gt;CLE at TEN:  TEN&lt;br /&gt;PHI at NYG:  NYG&lt;br /&gt;MIN at DET:  MIN&lt;br /&gt;HOU at  GB:  GB&lt;br /&gt;ATL at  NO:  NO&lt;br /&gt;CIN at IND:  IND&lt;br /&gt;MIA at BUF:  BUF&lt;br /&gt; NE at SEA:  NE&lt;br /&gt; KC at DEN:  DEN&lt;br /&gt;NYJ at  SF:  NYJ&lt;br /&gt;STL at ARI:  ARI&lt;br /&gt;DAL at PIT:  PIT&lt;br /&gt;WAS at BAL:  BAL&lt;br /&gt; TB at CAR:  CAR&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-6027465660133803217?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/6027465660133803217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=6027465660133803217' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6027465660133803217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6027465660133803217'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/12/gotta-get-in-picks.html' title='Gotta get in the picks'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-8591049851128743825</id><published>2008-11-27T07:09:00.001-08:00</published><updated>2008-11-27T07:10:15.150-08:00</updated><title type='text'>Still More Football</title><content type='html'>Happy Thanksgiving!&lt;br /&gt;&lt;br /&gt;Just for the record... my program's Week 13 Picks:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;TEN at DET:  TEN&lt;br /&gt;SEA at DAL:  DAL&lt;br /&gt;ARI at PHI:  ARI&lt;br /&gt; NO at  TB:  NO&lt;br /&gt;IND at CLE:  IND&lt;br /&gt; SF at BUF:  BUF&lt;br /&gt;BAL at CIN:  BAL&lt;br /&gt;MIA at STL:  MIA&lt;br /&gt;NYG at WAS:  NYG&lt;br /&gt;CAR at  GB:  CAR&lt;br /&gt;ATL at  SD:  ATL&lt;br /&gt;PIT at  NE:  PIT&lt;br /&gt; KC at OAK:  KC&lt;br /&gt;DEN at NYJ:  DEN&lt;br /&gt;CHI at MIN:  CHI&lt;br /&gt;JAC at HOU:  JAC&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-8591049851128743825?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/8591049851128743825/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=8591049851128743825' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/8591049851128743825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/8591049851128743825'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/11/still-more-football.html' title='Still More Football'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-7697738837295621840</id><published>2008-11-20T15:18:00.000-08:00</published><updated>2008-11-20T15:27:02.571-08:00</updated><title type='text'>More football</title><content type='html'>Because the Thursday night game is only hours away, I present my program's Week 12 picks:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;CIN at PIT:  PIT&lt;br /&gt;HOU at CLE:  CLE&lt;br /&gt; SF at DAL:  DAL&lt;br /&gt;BUF at  KC:  BUF&lt;br /&gt;MIN at JAC:  MIN&lt;br /&gt; TB at DET:  TB&lt;br /&gt;CHI at STL:  CHI&lt;br /&gt;NYJ at TEN:  TEN&lt;br /&gt;PHI at BAL:  BAL&lt;br /&gt; NE at MIA:  MIA&lt;br /&gt;OAK at DEN:  DEN&lt;br /&gt;NYG at ARI:  NYG&lt;br /&gt;WAS at SEA:  WAS&lt;br /&gt;CAR at ATL:  CAR&lt;br /&gt;IND at  SD:  IND&lt;br /&gt; GB at  NO:  NO&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In my opinion, there's no real surprises this week (maybe Miami taking down New England).  And, unlike last week, this week actually has a few visiting teams winning (like the Giants...).&lt;br /&gt;&lt;br /&gt;Last week was crazy.  I don't have time to tally right this second but I think it got six wrong.  And no, it would not have predicted a tie (but it &lt;em&gt;did &lt;/em&gt;pick Cincinnati).  I do want to play with this algorithm.  Instead of relying solely on team record, I'd like to try points-for and points-against.  Or maybe even touchdowns scored/field goals scored.  I don't know.  The boring part is collecting the data; to my knowledge, there are no &lt;em&gt;free &lt;/em&gt;XML feeds out there (and RSS would involve parsing).  But once the data is there I am free to play!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-7697738837295621840?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/7697738837295621840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=7697738837295621840' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7697738837295621840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7697738837295621840'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/11/more-football.html' title='More football'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-5120631011245002412</id><published>2008-11-11T18:10:00.001-08:00</published><updated>2008-11-11T18:32:27.866-08:00</updated><title type='text'>Week 11 Picks</title><content type='html'>In my &lt;a href="http://jamesqmurphy.blogspot.com/2008/11/football-and-so-called-experts.html"&gt;last post&lt;/a&gt; I described a quick little program that made NFL predictions based only on team record, and that gave the home team a slight edge.  I didn't want to tweak the algorithm &lt;strong&gt;that &lt;/strong&gt;much, but I decreased the maximum winning probability from 0.90 to 0.85.  So, without further ado, here are the program's predictions for week 11:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;NYJ at  NE:  NE&lt;br /&gt;DEN at ATL:  ATL&lt;br /&gt;DET at CAR:  CAR&lt;br /&gt;MIN at  TB:  TB&lt;br /&gt;BAL at NYG:  NYG&lt;br /&gt;OAK at MIA:  MIA&lt;br /&gt; NO at  KC:  KC&lt;br /&gt;PHI at CIN:  CIN&lt;br /&gt;CHI at  GB:  GB&lt;br /&gt;HOU at IND:  IND&lt;br /&gt;STL at  SF:  SF&lt;br /&gt;ARI at SEA:  SEA&lt;br /&gt;TEN at JAC:  JAC&lt;br /&gt; SD at PIT:  PIT&lt;br /&gt;DAL at WAS:  WAS&lt;br /&gt;CLE at BUF:  BUF&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;There's some surprises there (Cincinnati over the Eagles?!?!) but that's what I love about it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-5120631011245002412?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/5120631011245002412/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=5120631011245002412' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/5120631011245002412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/5120631011245002412'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/11/week-11-picks.html' title='Week 11 Picks'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-6793818335676226740</id><published>2008-11-09T08:01:00.000-08:00</published><updated>2008-11-09T08:42:51.108-08:00</updated><title type='text'>Football and so-called experts</title><content type='html'>I'm a fan of football.  Although, I'm almost ashamed to admit it, it's mostly due to peer pressure back in high school.  Back then, all the guys would talk about the sports teams, and I really could not follow what they were talking about.  I wouldn't even &lt;em&gt;know&lt;/em&gt; it was Superbowl Sunday.&lt;br /&gt;&lt;br /&gt;But that changed one year.  It was 1985, and I made up my mind that I would actually sit and watch football games.  It seemed like a modest investment of time; a few hours on a Sunday afternoon.  So I followed the New York Giants, and I listened to John Madden and Pat Summerall, who, at the time, did a good job of explaining the game.  Sure enough, after a few weeks, I got the hang of it.  And the Giants did okay that year (10-6), so it was fun to watch.  I was hooked.  (That was also the year that the Chicago Bears beat the New England Patriots -- remember the Superbowl Shuffle?)  I played a little fantasy football during my years at Procter &amp;amp; Gamble, but that just ruined the game for me.  Sure, you get to be a real expert on the league, but you can't enjoy a game the way it was meant to be enjoyed.  I prefer to remain a purist.&lt;br /&gt;&lt;br /&gt;I like football and I like talking about it.  But here's what I don't get: sports analysts.  I'm not talking about reporters; they have a job and they do it.  But analysts?  Why?  What possible value do sports analysts add?  They get paid to write their opinions in the newspaper, about sports.  But why?  Who really cares what they think?  It's not like coaches are going to start coaching differently based on what the analysts say.  It's not like business analysts; at least they write about stuff that actually affects people, like investments.  (Although business analysts are wrong just as often as their sports-spewing brethern.)  And don't get me started on talk radio/TV shows.  That's just uselessness magnified.&lt;br /&gt;&lt;br /&gt;What makes me laugh are the so-called experts and their "picks."  For instance, check out &lt;a href="http://sports.espn.go.com/nfl/features/talent"&gt;http://sports.espn.go.com/nfl/features/talent&lt;/a&gt;.  (Yeah, the URL really contains the word "talent" -- oh the irony.)  Ok, so these guys pick their winners.  Nobody does really great; as of today, Mortensen seems to be doing the best at 87-44, which means he is correct about two-thirds of the time.  What caught my eye was something called AccuScore, which supposedly simulates the game play-by-play to arrive at a prediction.  AccuScore has the exact same record as Mortensen (87-44), which means it beats all the other experts.  (And forget about the crowd-sourced Pigskin Pick-'em, where everyone else picks the winners.  It's doing the worst, which explains how sports bookies stay in business.)&lt;br /&gt;&lt;br /&gt;But then I thought it would be fun to write my own program to "predict" the outcomes of games.   Why not?  So, I created a few XML files that contained the matchups and the previous team records (I couldn't find this info in XML format anywhere for free, so I keyed it in myself).  My algorithm was simple:  I computed the "odds" that the home team would win, generated a (pseudo)random number, and compared it against the probability.  The probability of a home team victory is simply the weighted average of the home team's winning percentage and the visiting team's losing percentage, plus 0.1 for a home-field advantage, but never greater than 0.9.  Now, I couldn't figure the Thursday night game, but here's what the program generated for this week's games:&lt;br /&gt;&lt;code&gt;&lt;br /&gt; NO at ATL:  NO&lt;br /&gt;TEN at CHI:  TEN&lt;br /&gt;JAC at DET:  JAC&lt;br /&gt;BAL at HOU:  BAL&lt;br /&gt;SEA at MIA:  MIA&lt;br /&gt; GB at MIN:  GB&lt;br /&gt;BUF at  NE:  BUF&lt;br /&gt;STL at NYJ:  NYJ&lt;br /&gt;CAR at OAK:  CAR&lt;br /&gt;IND at PIT:  PIT&lt;br /&gt; KC at  SD:  SD&lt;br /&gt;NYG at PHI:  NYG&lt;br /&gt; SF at ARI:  ARI&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;I'm curious to see how it stacks up against the "experts."  None of picks exactly match what the "experts" say, so I'm actually optimistic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-6793818335676226740?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/6793818335676226740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=6793818335676226740' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6793818335676226740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6793818335676226740'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/11/football-and-so-called-experts.html' title='Football and so-called experts'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-6227033036004014547</id><published>2008-09-29T20:00:00.001-07:00</published><updated>2008-09-29T20:06:54.991-07:00</updated><title type='text'>About Dr. Knox</title><content type='html'>&lt;div style="float: right; margin-left: 10px; margin-bottom: 10px;"&gt;&lt;a href="http://www.flickr.com/photos/54399929@N00/2900957828/" title="photo sharing"&gt;&lt;img src="http://farm4.static.flickr.com/3024/2900957828_9227162f88_m.jpg" alt="" style="border: solid 2px #000000;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size: 0.9em; margin-top: 0px;"&gt;&lt;a href="http://www.flickr.com/photos/54399929@N00/2900957828/"&gt;njit_brochure_1990&lt;/a&gt;&lt;br /&gt;Originally uploaded by &lt;a href="http://www.flickr.com/people/54399929@N00/"&gt;JamesQMurphy&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;I just learned yesterday that &lt;a href="http://www.njit.edu/news/2008/2008-344.php"&gt;Dr. Dana E. Knox passed away&lt;/a&gt;.  Dr. Knox was one of my favorite professors at NJIT.  He was one of the youngest professors I had, which meant he could relate to us students.  He was only 53.&lt;br /&gt;&lt;br /&gt;Dr. Knox taught Thermodynamics.  That's right, thermo -- where the Q is for heat.  (Yep, it was after &lt;i&gt;his&lt;/i&gt; class where I got the "Q" in JamesQMurphy.)  This cover is the NJIT Brochure around 1990, and on it, you can see our thermo class.  It was the first nice day of spring in 1989.  We asked Dr. Knox if we could have class outside, and he said, "Sure, why not!"  The next thing you know, we were outside, reviewing an exam I think.  A passing photographer snapped a picture, and it was used on the brochure the following year.&lt;br /&gt;&lt;br /&gt;You can see Dr. Knox on the cover.  I'm the one in the pink shirt (hey, it was 1989).  The friend who gave me the Q?  Right behind me, in the blue shirt.&lt;br clear="all" /&gt;&lt;br/&gt;He was cool.  He'll be missed, but never forgotten.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-6227033036004014547?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/6227033036004014547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=6227033036004014547' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6227033036004014547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6227033036004014547'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/09/about-dr-knox.html' title='About Dr. Knox'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm4.static.flickr.com/3024/2900957828_9227162f88_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-6032753835602079140</id><published>2008-09-23T19:30:00.001-07:00</published><updated>2008-09-23T19:57:46.333-07:00</updated><title type='text'>I am Ted</title><content type='html'>&lt;p&gt;Yes I'm back, and I've got rants. Lots of rants. Hey, I'm still working at Merrill Lynch, and ever since the takeover by Bank of America, the workplace has become a fertile ground of rant-worthy material.  But before I jump into those, I thought I'd start with a happy little personal observation.&lt;/p&gt;&lt;p&gt;You see, I am Ted. Ted who? Why, Ted Forth, of course. Ted Forth from the fabled comic &lt;a href="http://www.kingfeatures.com/features/comics/sforth/about.htm"&gt;Sally Forth&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I've been a fan of the strip for years, but over the past few years, I've noticed a lot of similarities between Ted, the father figure in the strip, and myself. Ted is a kid at heart. He often shares the same attitudes as their 10-year-old daughter Hillary. In fact, the two of them are often seen playing together, and ganging up on Sally. Ted is quick to pull out a quote from the 80's (such as "Kneel before Zod", while playing Monopoly). When Ted was laid off from his job last year, he was seen driving home, windows rolled down, singing along to "I am Superman" by R.E.M.&lt;/p&gt;&lt;p&gt;I didn't think it could get more eerie. Last week, I was talking with my son (now 9!) about science fiction movies, and for some reason, I thought about &lt;a href="http://www.imdb.com/title/tt0087597/"&gt;The Last Starfighter&lt;/a&gt;. I described it to him, and promised that if it ever came on, we would watch it together.&lt;/p&gt;&lt;p&gt;&lt;em&gt;The very next morning&lt;/em&gt;, I saw this Sally Forth strip in the paper:&lt;/p&gt;&lt;p align="left"&gt;&lt;a href="http://3.bp.blogspot.com/_zPXCucVdm2g/SNmouUg6NoI/AAAAAAAAACM/q07gUROMAVQ/s1600-h/sf_09_18.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5249412354411214466" style="CURSOR: hand" alt="" src="http://3.bp.blogspot.com/_zPXCucVdm2g/SNmouUg6NoI/AAAAAAAAACM/q07gUROMAVQ/s400/sf_09_18.gif" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I immediately recognized the quote, but the following day's strip explained it for those who didn't:&lt;/p&gt;&lt;a href="http://3.bp.blogspot.com/_zPXCucVdm2g/SNmpg9t4B-I/AAAAAAAAACU/k6OdLtrYrlc/s1600-h/sf_09_19.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5249413224464910306" style="CURSOR: hand" alt="" src="http://3.bp.blogspot.com/_zPXCucVdm2g/SNmpg9t4B-I/AAAAAAAAACU/k6OdLtrYrlc/s400/sf_09_19.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Eerie indeed, but proof-positive that I am Ted. (I also sneak a Pop-Tart from the vending machine on occasion.)&lt;/p&gt;&lt;p&gt;By the way, the strip has now taken a very interesting turn.  Ted has been at his new job for five months, and has yet to make a single friend.  Sally has encouraged him to try and make friends, but his clumsy attempts (by attempting to talk sports) have backfired.  Suddenly, in walks Aria, the woman quoting The Last Starfighter.  Finally, Ted has found a kindred spirit -- and it's a woman!&lt;/p&gt;&lt;p&gt;At this point, he has not yet told Sally of his new friend.  I'm &lt;em&gt;dying&lt;/em&gt; to see Sally's reaction.  Ted would never cheat -- he is too innocent to do so -- but it will be great to see where the strip goes.  Stay tuned!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-6032753835602079140?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/6032753835602079140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=6032753835602079140' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6032753835602079140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6032753835602079140'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/09/i-am-ted.html' title='I am Ted'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_zPXCucVdm2g/SNmouUg6NoI/AAAAAAAAACM/q07gUROMAVQ/s72-c/sf_09_18.gif' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-6975834060595869819</id><published>2008-04-18T14:13:00.000-07:00</published><updated>2008-04-21T17:57:47.738-07:00</updated><title type='text'>Sanibel Trip -- and some useful stuff</title><content type='html'>Ok, so three months without a post might be considered an abandoned blog. But in my defense, I find that if I'm not blogging, it means I'm &lt;em&gt;doing&lt;/em&gt;. And I have been doing stuff, but before I bore you to tears with that stuff, let me bore you with our trip to Sanibel, Florida. Here's some useful tips just in case you've stumbled upon this blog and just happen to be planning a trip to Sanibel (or Captiva).&lt;br&gt;&lt;br /&gt;For those of you who don't know (or don't use Wikipedia), Sanibel Island is an island just off the west coast of Florida, near Fort Meyers. And I mean &lt;em&gt;just&lt;/em&gt; off -- you drive over a causeway to get to it. Captiva Island used to be a separate island, but thanks to a major storm filling in the gap, the two are now connected. Sanibel has got everything a normal town would have, except traffic lights. And let me tell you, a couple of traffic lights would serve this town some good. If you're like me, and you're used to driving in New Jersey, then driving in Sanibel is maddening, because they drive &lt;em&gt;slowly&lt;/em&gt;. Don't speed -- you'll get a ticket. I suppose that's a good thing -- there's plently of wildlife on the island, and the last thing you want to do is harm some poor unsuspecting creature. But it takes getting used to. And nobody there understands the concept of a four-way stop -- which is why some traffic lights would be helpful.&lt;br&gt;&lt;br /&gt;Speaking of wildlife, there's the &lt;a href="http://www.fws.gov/dingdarling/"&gt;J.N. "Ding" Darling Wildlife Refuge&lt;/a&gt;. If you like birds, or even if you like a nice bike ride, then plan to spend half a day here. Yes, you can drive through if you're in a rush like us (or if you're just lazy), but you'll miss a lot. It's about 4 miles of path, followed by a four-mile trek back along Sanibel-Captiva road back to the education center. You'll see birds, but you have to look and listen for them. And it's a lot easier to do that from a bike.&lt;br&gt;&lt;br /&gt;The beaches in Sanibel are not nice and sandy.  They are littered with shells.  Which, if you like to look for shells, is a great thing.  Hey, some people take it so seriously that they call it "shelling."  Really, as in, "Let's go shelling."  It's not like it's a sport.  Oh well.  One thing that surprised me was just how &lt;em&gt;calm&lt;/em&gt; the Gulf of Mexico is.  There are no waves, and there is no "roar of the ocean."  Good things if you want to take little ones to the beach.&lt;br&gt;&lt;br /&gt;Ok, so what about food and nightlife. First, let me say, that if you're looking for a bar-hopping scene with hundreds of twenty-somethings, then turn around, head back over the causeway, make a right at Route 835, and head to Ft. Meyer's Beach. Our friends took us there on Saturday night, and it looked like a lot of fun. But if you want to stay on the island, Sanibel and Captiva are chock-full of great restaurants. Most of the restaurants are on the main drag in Sanibel -- Periwinkle Drive. If you go to Sanibel, get your hands on the &lt;a href="http://www.cuisine-scene.com/"&gt;dining guide&lt;/a&gt; -- they have the menu from almost every restaurant printed in this guide.  Our hotel had it, and I'm sure most other hotels have it as well.  Just look for something that suits your style, and you're golden. Note that prices are a little high here, but that's to be expected, since it is a tourism-based economy.&lt;br&gt;&lt;br /&gt;Here's the places we visited, in the order we visited them. We didn't take our son, but I'll mention which places looked kid-friendly.&lt;ul&gt;&lt;li&gt;&lt;b&gt;Mucky Duck Tavern.&lt;/b&gt; This place is way out on Captiva Island. On Wednesday night, we got there at 5:30, hoping to beat the crowd (they open at 5:00). We got the last parking space available and had to wait 45 minutes -- and one of the bartenders said it was a slow day! But it's worth it. The best part about waiting is that you wait right by the beach (not quite on the beach -- but near it), and you can have a drink (or 3) while you wait, listening to some guy with an electronic keyboard sing "Sweet Caroline" and such. The kids will amuse themselves, and there's plenty of other kids to run around with (yes, running is okay, you're right by the beach after all). Casual atmosphere -- we were wearing jeans because it was still a little chilly, but most people wear shorts and sandals. Once inside, both Lisa and I had fried grouper sandwiches with fries -- awesome. You can opt for more dinner-like food if you want. Plenty of kid-friendly food as well. It'll run you about $25 a plate plus drinks.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Gramma Dot's Saloon.&lt;/b&gt; On Thursday, we decided to go here for a drink before dinner. Ok, finding this place is fun -- you go down Periwinkle drive and turn left at North Yachtsman way. You think you're entering a private driveway, but you are really entering the marina. Gramma Dot's is a restaurant with a bar, but it's still kid-friendly.  I'm told they also have great breakfasts.  Lisa and I wanted to sit outside and watch the boats, so we couldn't get a drink at the bar itself, but rather, at the attached convenience/yachting store. So yeah, we walked right past the yacht supplies and grabbed a few cans of Heinekin, then sat out and watched the pelicans. We even saw a few dolphins swim by.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Lazy Flamingo.&lt;/b&gt; There are two Lazy Flamingo restaurants -- we went to the newer on, in Sanibel. Much more kid-friendly and very casual. Not quite as good as other restaurants, but it's still a good time. Maybe $20 a plate plus drinks. Kinda reminds me of a Joe's Crab Shack.&lt;/li&gt;&lt;li&gt;&lt;b&gt;The Jacaranda.&lt;/b&gt; After we scarfed down our food, it was just after six o'clock, so we headed over to The Jacaranda to catch the last bit of happy hour. Now this place was not so casual -- everyone there still had shorts, but the men were wearing shirts with collars. Don't bring your kids here unless they can sit still. Still, it looked like a nice place. The bar area -- oh excuse me, it's a &lt;em&gt;lounge&lt;/em&gt;, not a bar -- is called "The Jac", and wasn't so bad. There was a band there playing classic rock, and they were okay. Mostly couples in their fifties. Hey, if that's your scene...&lt;/li&gt;&lt;li&gt;&lt;b&gt;Pinochio's Ice Cream.&lt;/b&gt; We wanted some ice cream, so we skipped the Dairy Queen and drove over to Pinochio's. Smart move! It's a little place in a shopping plaza, but it's good. Real good. It closes at 9:00, so avoid the last-minute stampede.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Island Cow.&lt;/b&gt; On Friday, after our cruise (see below), we headed to Island Cow for lunch. We got there at 12:50 and had a 30-minute wait. That should tell you how good the food was -- and it was good indeed. Kid-friendly, real casual, and lunch cost around $12-$15 a plate. This place has breakfast and dinner as well, and it looks like a great place to go. Lisa and I both had fajita salads that were really good.&lt;/li&gt;&lt;li&gt;&lt;b&gt;The Green Flash.&lt;/b&gt; Nice, pricey, and formal. Don't bring your kids here, unless they can sit still. You can still wear shorts and sandals, but wear a nice shirt. The food was good. About $30 a plate, unless you're ordering the $50 lobster tail. Oh, and if you do go, make sure you use the restroom -- that's all I'm saying. (One nit about The Green Flash: It's named after the atmospheric phenomenon of the same name -- you can read about it &lt;a href="http://en.wikipedia.org/wiki/Green_flash"&gt;here&lt;/a&gt; -- but oddly enough, the restaurant is &lt;em&gt;not&lt;/em&gt; situated on the Gulf. That's right -- you can't actually observe the real "green flash" here, despite the little handouts they give you.)&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Bicycles: If you can, bicycling is definitely the way to go. As I mentioned, the traffic drives slowly, so you can actually make decent time on a bike. Our inn had some loaner bikes that fit the bill, but if you want something decent, or more exotic like a bicycle-built-for-two, then there are some rental places on the island (everyone seemed to rent from Billy's Bikes). We rode from our hotel over to the lighthouse area, just because we were in the mood. There's nothing special there -- the lighthouse itself is ugly -- but it was a nice ride.&lt;br&gt;&lt;br /&gt;We went on board the Stars &amp;amp; Stripes and cruised around the northern part of the island. It was the best fifteen bucks (each) that we spent. You get a 90-minute cruise, and the dolphins will jump and play in the boat's wake!  The cruise takes off right outside Gramma Dot's (see above). If you have a boating license, you can rent your own 20-foot boat as well.&lt;br&gt;&lt;br /&gt;That's Sanibel.  Not exactly a romantic getaway, but still a nice place to visit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-6975834060595869819?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/6975834060595869819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=6975834060595869819' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6975834060595869819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6975834060595869819'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/04/sanibel-trip-and-some-useful-stuff.html' title='Sanibel Trip -- and some useful stuff'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-4098928394012700250</id><published>2008-01-20T09:29:00.000-08:00</published><updated>2008-01-20T10:36:30.198-08:00</updated><title type='text'>StarCraft: The Board Game</title><content type='html'>&lt;a href="http://jamesqmurphy.blogspot.com/2006/05/game-engine-and-why.html"&gt;A long time ago&lt;/a&gt;, I extolled the virtues of perhaps the most perfect video game ever created, StarCraft.  Well when &lt;a href="http://www.fantasyflightgames.com/starcraft.html"&gt;Fantasy Flight Games&lt;/a&gt; put out StarCraft: The Board Game, I just had to have it.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;What's In The Box?&lt;/h2&gt;&lt;a href="http://bp2.blogger.com/_zPXCucVdm2g/R5OJewguEAI/AAAAAAAAABM/oe8i-eQ3kV0/s1600-h/IMG_1615.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_zPXCucVdm2g/R5OJewguEAI/AAAAAAAAABM/oe8i-eQ3kV0/s400/IMG_1615.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5157617159780569090" /&gt;&lt;/a&gt;&lt;a href="http://bp3.blogger.com/_zPXCucVdm2g/R5OJ7AguEBI/AAAAAAAAABU/LNWNNQzaLrM/s1600-h/IMG_1616.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_zPXCucVdm2g/R5OJ7AguEBI/AAAAAAAAABU/LNWNNQzaLrM/s400/IMG_1616.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5157617645111873554" /&gt;&lt;/a&gt;&lt;br /&gt;Overall, the game is beautifully manufactured.  Most of the game elements are on cardboard punchouts.  The cardboard is &lt;em&gt;heavy&lt;/em&gt; and durable.  The elements are double-sided, as well -- and line up perfectly.  There are six total factions to play:  Two Terran factions (Acturus Mengsk, Jim Raynor), two Protoss factions (Tassadar, Aldaris), and two Zerg factions (The Overmind, Queen of Blades -- not sure why they didn't go with the name "Kerrigan").  Each player gets their own deck of combat cards, a technology deck to enhance their combat deck, a sheet to track upgrades and resources, and a quick-reference cheat sheet.  Each player also gets figures -- I'll get to those in a second.  Here is a shot of the game contents, minus the figures:&lt;br /&gt;&lt;a href="http://bp3.blogger.com/_zPXCucVdm2g/R5OMXAguEFI/AAAAAAAAAB0/CZooFf763h0/s1600-h/IMG_1613.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_zPXCucVdm2g/R5OMXAguEFI/AAAAAAAAAB0/CZooFf763h0/s400/IMG_1613.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5157620325171466322" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;The Figures&lt;/h2&gt;Each player has several types of units.  For each race, there are three of each type.  (Note that Terrans have nine types; the other races only have eight.)&lt;br /&gt;&lt;a href="http://bp0.blogger.com/_zPXCucVdm2g/R5OKaQguECI/AAAAAAAAABc/gUPeC7OR9pM/s1600-h/IMG_1609.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_zPXCucVdm2g/R5OKaQguECI/AAAAAAAAABc/gUPeC7OR9pM/s400/IMG_1609.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5157618181982785570" /&gt;&lt;/a&gt;&lt;br /&gt;Terran Units.  Back row (from left to right):  Goliath, Science Vessel, Wraith, Battlecruiser.  Front row:  Marine, Firebat, Ghost, Vulture, Siege Tank.  Note that the Terrans get nine types of units, whereas the other races get eight types.&lt;br&gt;&lt;br /&gt;&lt;a href="http://bp1.blogger.com/_zPXCucVdm2g/R5OKagguEDI/AAAAAAAAABk/Jnky90CD8Go/s1600-h/IMG_1606.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_zPXCucVdm2g/R5OKagguEDI/AAAAAAAAABk/Jnky90CD8Go/s400/IMG_1606.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5157618186277752882" /&gt;&lt;/a&gt;&lt;br /&gt;Zerg Units.  Back row: Scourge, Queen, Ultralisk, Guardian, Mutalisk.  Front row: Hydralisk, Zergling, Defiler.&lt;br&gt;&lt;br /&gt;&lt;a href="http://bp3.blogger.com/_zPXCucVdm2g/R5OKbAguEEI/AAAAAAAAABs/XYvRB38K4qU/s1600-h/IMG_1610.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_zPXCucVdm2g/R5OKbAguEEI/AAAAAAAAABs/XYvRB38K4qU/s400/IMG_1610.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5157618194867687490" /&gt;&lt;/a&gt;&lt;br /&gt;Protoss Units.  Back row:  Scout, Arbiter, Carrier.  Front row:  Zealot, Dragoon, High Templar, Archon, Reaver.&lt;br&gt;&lt;br /&gt;&lt;h2&gt;Missing and Broken Pieces&lt;/h2&gt;Unfortunately, the game arrived with some broken pieces and one missing piece.  Here's a shot of my broken pieces:&lt;br /&gt;&lt;a href="http://bp1.blogger.com/_zPXCucVdm2g/R5OOpgguEGI/AAAAAAAAAB8/UPJCe5UIPlI/s1600-h/IMG_1611.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_zPXCucVdm2g/R5OOpgguEGI/AAAAAAAAAB8/UPJCe5UIPlI/s400/IMG_1611.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5157622842022301794" /&gt;&lt;/a&gt;&lt;br /&gt;Can you believe that all three of Tassadar's Arbiters were broken?  I suspect Aldaris set out to sabotage him.  Anyway, in addition to the broken pieces, one of Kerrigan's Queens was missing as well: &lt;br /&gt;&lt;a href="http://bp3.blogger.com/_zPXCucVdm2g/R5OOqAguEHI/AAAAAAAAACE/la5cq6d3Xho/s1600-h/IMG_1612.JPG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_zPXCucVdm2g/R5OOqAguEHI/AAAAAAAAACE/la5cq6d3Xho/s400/IMG_1612.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5157622850612236402" /&gt;&lt;/a&gt;&lt;br /&gt;I guess she got hungry and consumed one.  Anyway, from reading on Fantasy Flight's forum, it looks like this is a &lt;a href="http://www.fantasyflightgames.com/cgi-bin/yabb/YaBB.cgi?num=1200333017"&gt;common occurence&lt;/a&gt;, but that their customer service is outstanding and will replace any broken or missing pieces.  I've sent them an e-mail; we'll see how it goes.&lt;br /&gt;&lt;h2&gt;Game Play&lt;/h2&gt;Well, I haven't played the game yet.  But I've talked with my game-playing friends, and there's some interest in giving the game a try.  FFG has posted the rules in PDF-format &lt;a href="http://www.fantasyflightgames.com/PDF/StarCraft_rules.pdf"&gt;here&lt;/a&gt;.  First impressions?  It kinda seems like a combination of &lt;a href="http://en.wikipedia.org/wiki/Risk_game"&gt;Risk&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Pok%C3%A9mon_Trading_Card_Game"&gt;Pokémon&lt;/a&gt;.  The Risk element comes from the fact that players have territory, and the more territory you have, the more troops you are able to get.  The actual game play board, which consists of planets that are interconnected, is generated at the start of the game by player placement.  The Pokémon aspect shows itself through battles; each player has a combat deck of cards that are used to play.  Also, it helps if you've played the StarCraft video game, so you'll be familiar with the units and attack styles.&lt;br /&gt;&lt;br /&gt;I'll let you know how it goes!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-4098928394012700250?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/4098928394012700250/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=4098928394012700250' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/4098928394012700250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/4098928394012700250'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/01/starcraft-board-game.html' title='StarCraft: The Board Game'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_zPXCucVdm2g/R5OJewguEAI/AAAAAAAAABM/oe8i-eQ3kV0/s72-c/IMG_1615.JPG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-6094871734802931928</id><published>2008-01-18T18:16:00.000-08:00</published><updated>2008-01-18T18:47:27.085-08:00</updated><title type='text'>Which Rendering Engine</title><content type='html'>I haven't been working on the Game Engine for the past two months.  Instead, I read Charles Petzold's book &lt;a href="http://www.amazon.com/Applications-Code-Markup-Presentation-Foundation/dp/0735619573"&gt;Applications = Code + Markup&lt;/a&gt; to see if WPF would be a more-suitable rendering solution for the Game Engine.&lt;br /&gt;&lt;br /&gt;Actually, that's only partially true.  I am actually considering doing the game rendering using Microsoft's Silverlight Plug-in.  I was under the (somewhat mistaken) impression that Silverlight was simply "WPF in a box".  It's not.  (Or at least, version 1.0 is not.)  Silverlight 1.0 is a XAML renderer, &lt;em&gt;not&lt;/em&gt; a WPF engine.  Yes, you can draw buttons and even hook code up to the buttons, but any such client-side code must be written in Javascript.  Communications to the server are done via AJAX.&lt;br /&gt;&lt;br /&gt;Now it &lt;em&gt;is&lt;/em&gt; possible to implement my &lt;a href="http://jamesqmurphy.blogspot.com/2007/09/state-of-game-state.html"&gt;game design&lt;/a&gt; this way.  However, recall that in my design, I wanted to have it so that the developer would only have to write the GameState object once.  (The GameState object is like the business layer -- it wraps the raw GameData and translates it into something useful, and enforces some rules.)  But with Javascript on the client, it would force the developer to write the GameState object twice -- once for the server side in a CLR language, and once for the client side in Javascript.  Now, I could do something like have the server side load a Javascript runtime and run Javascript on both ends, but the truth is, I'd rather have the developer write C# or VB.NET on both sides.&lt;br /&gt;&lt;br /&gt;Enter Silverlight 1.1, which promises that you can write your client code in C# or VB.NET.  This does hold some promise, but I will need to take a closer look.  I'm going to be playing with Silverlight 1.1 over the next few weeks and evaluating its potential for the Game Engine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-6094871734802931928?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/6094871734802931928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=6094871734802931928' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6094871734802931928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6094871734802931928'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2008/01/which-rendering-engine.html' title='Which Rendering Engine'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-6614823184392704776</id><published>2007-12-23T13:38:00.000-08:00</published><updated>2007-12-23T14:38:17.257-08:00</updated><title type='text'>Popsicle Stick Bridge Contest</title><content type='html'>How about a quick break from programming?&lt;br /&gt;&lt;br /&gt;This past fall, my third-grade son was in a school-sponsored Family Science night, where a local science teacher has the families perform a few science-oriented activities (such as studying the properties of a cornstarch mixture à la Mythbusters Walking on Water).  He really doesn't teach the concepts, however; he just lets the kids do the activies and have fun with them.&lt;br /&gt;&lt;br /&gt;The long-term project was to build a bridge out of popsicle sticks and Elmer's glue.  We were given a bag of 49 popsicle sticks (we were &lt;i&gt;supposed&lt;/i&gt; to receive 50), a small length of twine (which we lost), and the bottle of glue.  The bridge was to span a length of 12 inches, and we could use any resource that we wanted, including the Internet.&lt;br /&gt;&lt;br /&gt;I figured that the lessons were:&lt;ul&gt;&lt;li&gt;Triangles are strong&lt;/li&gt;&lt;li&gt;Computers can be used to design bridges&lt;/li&gt;&lt;/ul&gt;So after poking around the Internet a bit, I ran across the West Point Bridge Design contest, and their software:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bridgecontest.usma.edu/"&gt;http://bridgecontest.usma.edu/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This program lets you design and submit a bridge for the West Point contest.  Of course, I was not interested in entering the West Point contest, but the software does do a good job of analyzing your design.  One of the cute features of the program is that after you lay out the design, it will drive a truck across the span, and if the span does not hold, the truck will plunge into the river.  (This kept my son occupied for hours!)&lt;br /&gt;&lt;br /&gt;After some playing, we came up with a basic design and built our bridge:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp0.blogger.com/_zPXCucVdm2g/R27d9gguD9I/AAAAAAAAAA0/QhTVfCwWwBQ/s1600-h/Bridge1.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_zPXCucVdm2g/R27d9gguD9I/AAAAAAAAAA0/QhTVfCwWwBQ/s400/Bridge1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5147295472899985362" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As you can see it was a simple truss design.  I especially like the triangular beams that are holding up the cardboard deck (we did that for fun -- the deck was not permanently attached and we did not take it with us to the contest).  Also, it's hard to tell from the picture, but the topmost beams in the center are doubled.  This was because the software indicated that these members would be the most under compression.  You can see this better in our shot of the Presidential Limousine crossing the bridge:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp0.blogger.com/_zPXCucVdm2g/R27fSgguD-I/AAAAAAAAAA8/avlNhFlOJ0Y/s1600-h/Bridge2.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_zPXCucVdm2g/R27fSgguD-I/AAAAAAAAAA8/avlNhFlOJ0Y/s400/Bridge2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5147296933188866018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, I didn't bring my camera to the competition.  About half of the bridges were trusses; the other half were simple spans.  Of course, the simple spans snapped after about ten pounds of load.  The trusses fared much better, each holding over 40 pounds.  One bridge made it up to 55 pounds... it was tough to beat, but we did it!  Our bridge made it to 60 pounds before it started to creak and then finally fail:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp2.blogger.com/_zPXCucVdm2g/R27geAguD_I/AAAAAAAAABE/ePCnIHlfyfI/s1600-h/BridgeBroken.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_zPXCucVdm2g/R27geAguD_I/AAAAAAAAABE/ePCnIHlfyfI/s400/BridgeBroken.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5147298230268989426" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It was very interesting to see where it failed.  The center stayed put; it was the ends that collapsed.&lt;br /&gt;&lt;br /&gt;The bridge is still in pieces, but maybe over Christmas break I'll glue it back together.  We still have the cardboard deck.  And hey, it's fun to play with!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-6614823184392704776?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/6614823184392704776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=6614823184392704776' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6614823184392704776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6614823184392704776'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/12/popsicle-stick-bridge-contest.html' title='Popsicle Stick Bridge Contest'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_zPXCucVdm2g/R27d9gguD9I/AAAAAAAAAA0/QhTVfCwWwBQ/s72-c/Bridge1.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-5762305053920831971</id><published>2007-10-28T08:15:00.001-07:00</published><updated>2007-10-28T08:54:53.671-07:00</updated><title type='text'></title><content type='html'>Given that the plumbing of the Gaming engine was able to support TicTacToe, I decided that I wanted to work a bit on front-end presentation.  Up until now, the front-end was using Windows Forms, which has been around since .NET 1.0.  It's straightforward to use, and if you grew up with programming the Windows API (like I did), it's easy enough to learn.&lt;br /&gt;&lt;br /&gt;One of the things I want the Gaming Engine to do was grey out the playing area while waiting for other players to join.  The game owner would also have a special control window that allows him/her to move players to different seats, to invite players, and to eject them.  I want it to be in a window that sits on top of the playing window, but I also want the window to be somewhat transparent so that the immediate effects of the game can also be witnessed.&lt;br /&gt;&lt;br /&gt;The problem is, for out-of-the-box Windows Forms, only the Form class supports an Opacity property.  It's a neat property, but it makes the whole form translucent, not just the child window.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp2.blogger.com/_zPXCucVdm2g/RySqzdIPPfI/AAAAAAAAAAk/Ig628kQsmSU/s1600-h/forms20opacity.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_zPXCucVdm2g/RySqzdIPPfI/AAAAAAAAAAk/Ig628kQsmSU/s400/forms20opacity.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5126410076823698930" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I started reading up on alpha blending and looking at some Win32 API extended styles.  Although I knew I could figure it out, I decided not to pursue it, for a few reasons:&lt;ul&gt;&lt;li&gt;I knew that WinForms was not "the future", so to speak.&lt;/li&gt;&lt;li&gt;Using P/Invoke to access the Win32 API is straightforward enough, but the Gaming Engine loads the game assemblies into AppDomains that have limited privileges, for security reasons.  Although the engine will have the necessary rights for P/Invoke, setting up the necessary Asserts() is tricky, and I'd rather not do it unless I had to.&lt;/li&gt;&lt;li&gt;If other technologies solved the transparent child window problem, then it's less work for me.&lt;/li&gt;&lt;li&gt;Since I'm already using WCF for the Gaming Engine communication layer, I'm already committed to .NET 3.0&lt;/li&gt;&lt;/ul&gt;So I decided to put the Gaming Engine on hold for a bit, and focus on learning Windows Presentation Foundation (WPF).&lt;br /&gt;&lt;br /&gt;I'm about halfway through Charles Petzold's book &lt;a href="http://www.amazon.com/Applications-Code-Markup-Presentation-Foundation/dp/0735619573"&gt;Applications = Code + Markup&lt;/a&gt;.  And I have to say this:  WPF is a good thing.&lt;br /&gt;&lt;br /&gt;If you've been putting off learning WPF, and clinging to Windows Forms as I had been doing, stop doing it now.  WPF does things a &lt;em&gt;whole&lt;/em&gt; lot better.  Here's what it does:&lt;ul&gt;&lt;li&gt;If you want, you can lay out a window like a web page, with tables that automatically size themselves.&lt;/li&gt;&lt;li&gt;They finally got the command-routing code right.  I've toyed with a few solutions of my own, but their command binding solution is very clean.&lt;/li&gt;&lt;li&gt;They've got a document-view construct similar to that of MFC.&lt;/li&gt;&lt;li&gt;And of course, you can apply Opacity to a child window.&lt;/li&gt;&lt;/ul&gt;I love how Petzold doesn't even introduce XAML until the second half of the book.  He has several code examples, and once you've written all the code, you'll appreciate the declarative nature of XAML, and why it was developed.  The only thing I don't like about his book is that he doesn't illustrate all his samples -- you've got to actually run the programs to see the output.  (I'm reading his book from &lt;a href="http://www.books24x7.com"&gt;books24x7.com&lt;/a&gt;, so it's just copy/paste for me.)&lt;br /&gt;&lt;br /&gt;Here's a program that illustrates a child window with Opacity.  I've derived two classes from label:  Clock and SeeThruMessage.  Clock is just a label with a timer, and just displays the time.  SeeThruMessage is a label with Opacity set to 0.5.  The great thing is, even when SeeThruMessage is in front of the Clock, the Clock still continues to redraw.  This is exactly what I want.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp2.blogger.com/_zPXCucVdm2g/RySv_dIPPgI/AAAAAAAAAAs/Q3nXcIUv0rQ/s1600-h/wpfopacity.PNG"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_zPXCucVdm2g/RySv_dIPPgI/AAAAAAAAAAs/Q3nXcIUv0rQ/s400/wpfopacity.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5126415780540268034" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Windows;&lt;br /&gt;using System.Windows.Controls;&lt;br /&gt;using System.Windows.Input;&lt;br /&gt;using System.Windows.Media;&lt;br /&gt;using System.Windows.Threading;&lt;br /&gt;&lt;br /&gt;namespace JamesQMurphy.Test&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public class TestOpacity : Window&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[STAThread]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void Main()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Application app = new Application();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app.Run(new TestOpacity());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Clock _clock = new Clock();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SeeThruMessage _mymsg = new SeeThruMessage();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public TestOpacity()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Canvas canvas = new Canvas();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.Content = canvas;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;canvas.Children.Add(_clock);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Canvas.SetLeft(_clock, 0.0);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Canvas.SetTop(_clock, 0.0);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;canvas.Children.Add(_mymsg);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Canvas.SetLeft(_mymsg, 0.0);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Canvas.SetTop(_mymsg, 0.0);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_mymsg.Width = 400;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_mymsg.Content = "Howdy!";&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_mymsg.Opacity = 0.5;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_mymsg.Visibility = Visibility.Hidden;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected override void OnMouseDown(MouseButtonEventArgs e)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base.OnMouseDown(e);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_mymsg.Visibility = Visibility.Visible;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;e.Handled = true;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public class Clock : Label&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private DispatcherTimer _timer = new DispatcherTimer();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Clock()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_timer.Interval = TimeSpan.FromMilliseconds(500);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_timer.Tick += new EventHandler(_timer_Tick);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_timer.Start();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.Background = Brushes.Blue;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.Foreground = Brushes.White;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.FontSize = 20;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.FontFamily = new FontFamily("Comic Sans MS");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.Width = 250;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.Height = 75;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected override void OnMouseDown(MouseButtonEventArgs e)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base.OnMouseDown(e);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MessageBox.Show("Click clock!");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;e.Handled = true;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void _timer_Tick(object sender, EventArgs e)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.Content = System.DateTime.Now.ToString();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public class SeeThruMessage : Label&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public SeeThruMessage()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.Background = Brushes.Orange;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.Foreground = Brushes.White;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.FontSize = 40;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.FontFamily = new FontFamily("Comic Sans MS");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected override void OnMouseDown(MouseButtonEventArgs e)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.Visibility = Visibility.Hidden;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;e.Handled = true;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-5762305053920831971?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/5762305053920831971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=5762305053920831971' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/5762305053920831971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/5762305053920831971'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/10/given-that-plumbing-of-gaming-engine.html' title=''/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_zPXCucVdm2g/RySqzdIPPfI/AAAAAAAAAAk/Ig628kQsmSU/s72-c/forms20opacity.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-7996135123977658543</id><published>2007-10-09T18:12:00.000-07:00</published><updated>2007-10-09T18:15:40.241-07:00</updated><title type='text'>Game Ratings</title><content type='html'>A quickie... &lt;a href="http://www.codinghorror.com/blog/"&gt;Coding Horror&lt;/a&gt; is one of my favorite blogs.  &lt;a href="http://www.codinghorror.com/blog/archives/000961.html"&gt;This post&lt;/a&gt; talks about game ratings.  Definitely good material for the Gaming Engine!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-7996135123977658543?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/7996135123977658543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=7996135123977658543' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7996135123977658543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7996135123977658543'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/10/game-ratings.html' title='Game Ratings'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-4028718754617452343</id><published>2007-09-30T09:06:00.000-07:00</published><updated>2007-09-30T09:47:40.876-07:00</updated><title type='text'>State of the Game State</title><content type='html'>Way back when, I outlined &lt;a href="http://jamesqmurphy.blogspot.com/2006/09/history-shouldnt-repeat-and-also.html"&gt;the basic workings of the Game Engine&lt;/a&gt;.  To summarize, there exists a single Game object on the server that controls the game.  The Game object manipulates the GameState, and has complete knowledge of the game.  Each player receives a limited, filtered view of the GameState.  As the Game object manipulates the GameState, each player receives (filtered) updates to their local GameState object.&lt;br /&gt;&lt;br /&gt;But as I actually worked with this model, it became apparent that it was difficult to write the code that did the work of managing the state and filtering when appropriate.  So I introduced a new object into the mix, the &lt;em&gt;GameData object&lt;/em&gt;.  Basically, the GameData object is a set of two dictionaries -- one public, and one private.  Any values stored in the public dictionary are broadcast unfiltered to everyone.  Values stored in the private dictionary are broadcast only to the player who "owns" the value.  Other players (and spectators) know that there is a value stored; they just don't know what it is.&lt;br /&gt;&lt;br /&gt;Forgive the cheesy diagram, but here is how it looks:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp1.blogger.com/_zPXCucVdm2g/Rv_LF-FVTgI/AAAAAAAAAAc/kR6NhEtqoaA/s1600-h/GameGameStateGameData.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_zPXCucVdm2g/Rv_LF-FVTgI/AAAAAAAAAAc/kR6NhEtqoaA/s400/GameGameStateGameData.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5116031005141323266" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This simplified things immensely.  The GameState object essentially becomes a wrapper around the GameData object, allowing the programmer to put game-specific logic around the data.  (Think of it as a business layer.)  For example, while writing the TicTacToe game (which only uses the public dictionary), the logic looks something like this (and forgive the cheesy code -- this is illustrative only):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class TicTacToeGameState : GameState&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// other code omitted&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public string GetSquare(int nSquare)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string key = "SQUARE" + nSquare;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return this.GameData.Public[key];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;   &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void SetSquare(int nSquare, string XorO)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string key = "SQUARE" + nSquare;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.GameData.Public[key] = XorO;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;To make things easier, the base GameState class has events that fire whenever a value (public or private) is updated.  Thus, the client can render the necessary UI whenever the changes happen.  Simple, yes, but consider what happens in TicTacToe:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Client submits the command ("X" in center square)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The command reaches the Game object&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Game object calls SetSquare method on GameState object&lt;/li&gt;&lt;br /&gt;&lt;li&gt;GameState updates GameData object&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The changes gets propagated to each client's GameData object&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The client notices the change and updates the UI&lt;/li&gt;&lt;/ol&gt;Note that there is a delay between the time that the player makes the move ("X" in center square) and the time that the UI actually gets the notification (center square now has an "X").  I actually went back and forth on this, but in the end I went with the simple solution:  Game Clients can freely update the local GameData object, via the local GameState object.  In this case, in addition to submitting the Command, the client application can locally call GameState.SetSquare.  The resulting change event fires immediately, and when the change finally arrives from the server, nothing happens, since the value does not change.&lt;br /&gt;&lt;br /&gt;I actually do have code that does this, but at first, I added in a whole bunch of extra code that checks for "unexpected updates" (suppose the client marks the square with an "O" instead of an "X").  But lately I decided that this was overkill.  Once I remove all the extra code, I'll try and see if I can post TicTacToe as it exists now.  You'll even see some of the additional problems that have surfaced.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-4028718754617452343?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/4028718754617452343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=4028718754617452343' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/4028718754617452343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/4028718754617452343'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/09/state-of-game-state.html' title='State of the Game State'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_zPXCucVdm2g/Rv_LF-FVTgI/AAAAAAAAAAc/kR6NhEtqoaA/s72-c/GameGameStateGameData.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-6125156588855235452</id><published>2007-09-18T18:16:00.001-07:00</published><updated>2007-09-18T18:43:06.949-07:00</updated><title type='text'>How do you layout your classes?</title><content type='html'>I'm still in the .NET 3.0 world... I haven't really gotten my feet wet with .NET 3.5 or LINQ or any of the latest stuff.  But, I finally looked up the syntax of a cool feature of .NET 3.0... &lt;em&gt;automatic properties&lt;/em&gt;.  Basically, if you write a lot of this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;private int _prop;&lt;br /&gt;public int Prop&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;get { return _prop; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;set { _prop = value; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;In C# 3.0, you can write it in one line:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;public int Prop { get; set; }&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The compiler will automatically generate the _prop backing field (although it calls it something like &lt;strong&gt;k__AutomaticallyGeneratedPropertyField0 &lt;/strong&gt;-- see &lt;a href="http://blogs.msdn.com/wriju/archive/2007/03/27/c-3-0-features-automatic-property-part-2.aspx"&gt;this article at Wriju's blog&lt;/a&gt; for more info).  This is a very cool thing -- it let's you declaratively express the fact that you have a trivial property.  You can write it like a field, but it actually gets implemented as a property.  Plus, you can give the get{} and set{} methods different access modifiers:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;public int Prop { get; private set; }&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I love it, but I'm going to have to rethink the way I layout my classes.  This is the structure that I use:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;[Attributes]&lt;br /&gt;public class MyClass&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Any constants.  I use ALL CAPS:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;const int MY_VALUE = 4;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// All static stuff goes here, usually in a #region block&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// The pattern of the static members follows the pattern&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// of the class&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Any private nested classes&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// All data fields, which are always private by convention&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Fields marked "readonly" generally come first&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// BTW, I usually use an underscore:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;int _noticeTheUnderscore = 0;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Constructors&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Public properties&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Public methods&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Public events (which usually include a protected &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// override method and a private "FireXXX" method)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Any explicit interface implementations&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// (in a #region block)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Protected members (properties, methods, events)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Internal members (properties, methods, events)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Private members (properties, methods, events)&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Where should automatic properties go?  With the properties, or with the fields?  The nice thing about keeping the data members in one place is that you can easily get a feel for the memory footprint of the class.  And by keeping all the public members in one section, you can see the public interface of a class as well.  But automatic properties make this difficult -- do I put them with the private members, where I can see their footprint, or the public interface?&lt;br /&gt;&lt;br /&gt;If I had to choose right now, I'd say I'd put them with the other properties.  I suppose I could put a comment with the private fields, to help judge the memory footprint, but there is a risk that the comment would not be updated if the property is altered or removed.&lt;br /&gt;&lt;br /&gt;Of course, I could simply stick to the old way.  But I really hate boilerplate code!&lt;br /&gt;&lt;br /&gt;Any thoughts?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-6125156588855235452?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/6125156588855235452/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=6125156588855235452' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6125156588855235452'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6125156588855235452'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/09/how-do-you-layout-your-classes.html' title='How do you layout your classes?'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-278987955602509120</id><published>2007-09-14T18:32:00.000-07:00</published><updated>2007-09-14T19:09:59.392-07:00</updated><title type='text'></title><content type='html'>If you work at a big company, then you're probably familiar with the &lt;a href="http://en.wikipedia.org/wiki/United_Way_of_America"&gt;United Way&lt;/a&gt;.  At my company, we have it too, but I'll give 'em credit:  They've come up with some creative ideas to raise the money and have employees donate:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;An eBay-like auction site, where employees donate items and services, and employees bid.&lt;/li&gt;&lt;li&gt;A 5K race (in which I'm competing)&lt;/li&gt;&lt;li&gt;An Oktoberfest carnival, where employees can set up fund-raising booths&lt;/li&gt;&lt;li&gt;Various golf outings&lt;/li&gt;&lt;li&gt;A singing contest &lt;em&gt;a la&lt;/em&gt; American Idol.  This always pulls in thousands of dollars.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Well, our manager has her turn in coming up with an event.  And she did what any good manager does... she delegated the task to her minions.  And then it hit me.&lt;br /&gt;&lt;br /&gt;But first, have you ever seen the movie &lt;a href="http://en.wikipedia.org/wiki/Midnight_Madness"&gt;Midnight Madness&lt;/a&gt;?  You haven't?  Well go watch it... I'll wait.&lt;br /&gt;&lt;br /&gt;Ok, our campus sits in the middle of Hopewell -- and I mean campus.  It's twelve building sprawled out on grassy fields, complete with a lake (with a little foot bridge!), softball courts, etc.  What a perfect spot to play Midnight Madness!  So I pitched the idea to my manager, and promised her a more coherent idea by Monday.&lt;br /&gt;&lt;br /&gt;Now, we can't have what went on in the movie.  That would tear up our campus, and the maintenance folks would be none-too-happy.  But, if you couple it up with modern technology, you can get something just as good, and it keeps the campus clean:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Teams start off with a clue.  (Example:  Geena, Rosie, and Madonna might be here)&lt;/li&gt;&lt;li&gt;The clue identifies a location on campus.  (Example: The clue identifies the movie "A League Of Their Own", which implies that the location is the softball field)&lt;/li&gt;&lt;li&gt;Once solved, the team proceeds to the location, where they search for a hidden word.&lt;/li&gt;&lt;li&gt;Back at base, they punch the hidden word into a web site, which reveals the next clue.&lt;/li&gt;&lt;li&gt;The game proceeds on and on, until one team reaches the finish line.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;The great thing about involving a web site is that it provides instant tracking, and that it prevents teams from entering clues out-of-order.  (In the movie, there were two instances of teams skipping locations when they bumped into teams that had moved ahead of them.)&lt;br /&gt;&lt;br /&gt;It's just an idea, but I think I can make it fly...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-278987955602509120?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/278987955602509120/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=278987955602509120' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/278987955602509120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/278987955602509120'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/09/if-you-work-at-big-company-then-youre.html' title=''/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-7980574987079284479</id><published>2007-09-08T18:36:00.000-07:00</published><updated>2007-09-08T19:08:36.759-07:00</updated><title type='text'>If I can find M57, so can you!</title><content type='html'>There's more to life than game engines and programming... there's astronomy!  And tonight I found my first deep space object:  &lt;a href="http://server6.wikisky.org/starview?object_type=3&amp;object_id=9"&gt;M57&lt;/a&gt;, the Ring Nebula.&lt;br /&gt;&lt;br /&gt;Usually, I'm what they call an "armchair astronomer," which means I'm content to read &lt;em&gt;Astronomy&lt;/em&gt; magazine and look at the pictures.  But the weather's been nice -- nice enough to go into the pool even -- and the sky was a nice, deep cloudless blue.  I took out the telescope (my father's old orange &lt;a href="http://en.wikipedia.org/wiki/Celestron"&gt;Celestron 8&lt;/a&gt;) and pointed it at Jupiter, which is in the southern sky these days.  It just so happens that tonight, Europa is passing in front of Jupiter, but I didn't feel like staying up for it.&lt;br /&gt;&lt;br /&gt;So I thought, what the hey, let me try for a deep-sky object.  Now, you should know that I have &lt;em&gt;never&lt;/em&gt; been able to find a deep-sky object.  Planets, the Moon, the &lt;a href="http://en.wikipedia.org/wiki/Orion_nebula"&gt;Orion Nebula&lt;/a&gt; -- that's the limit of my experience.  So for me, actually finding a deep-sky object is a big deal.&lt;br /&gt;&lt;br /&gt;And it's easy!  Trust me, if I can do it, anybody can.  It's actually located between two stars in Lyra (the names are Sulaphat and Shelyak).  If you can find &lt;a href="http://en.wikipedia.org/wiki/Cygnus"&gt;Cygnus, the Northern Cross&lt;/a&gt;, then here's where to look for M57:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp2.blogger.com/_zPXCucVdm2g/RuNU9Th8SkI/AAAAAAAAAAM/Op6JcdVQeGc/s1600-h/M57+Finder.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_zPXCucVdm2g/RuNU9Th8SkI/AAAAAAAAAAM/Op6JcdVQeGc/s320/M57+Finder.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5108019814559664706" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Yes, it's a cheesy sketch.  But I'm serious... just point your scope there and look.  You really can't miss it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-7980574987079284479?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/7980574987079284479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=7980574987079284479' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7980574987079284479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7980574987079284479'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/09/if-i-can-find-m57-so-can-you.html' title='If I can find M57, so can you!'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_zPXCucVdm2g/RuNU9Th8SkI/AAAAAAAAAAM/Op6JcdVQeGc/s72-c/M57+Finder.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-5676053479401157687</id><published>2007-09-02T18:30:00.001-07:00</published><updated>2007-09-03T08:53:25.463-07:00</updated><title type='text'>A Waitable Queue</title><content type='html'>And now for something completely different... a bit of code!&lt;br /&gt;&lt;br /&gt;In addition to the Gaming engine, I also have a common library that I use to collect reusable classes and bits of code that I write.  One such example is a &lt;em&gt;waitable queue&lt;/em&gt;, which is sometimes called a &lt;em&gt;blocking queue&lt;/em&gt;.  It's a queue where readers can safely wait for an item to be enqueued.  Once enqueued, a waiting reader will immediately pick up the queued item.  Readers can specify a timeout period; if nothing is queued within the timeout period, the reader will be notified of this.&lt;br /&gt;&lt;br /&gt;Most of the time, you won't need a structure like this.  The built-in .NET thread pool has a queue; adding an item to the queue is as simple as calling ThreadPool.QueueUserWorkItem.  The thread pool automatically wakes up a background thread to come and process the item.  This works great for operations where each unit of work is concrete, separate, and does not depend on other items currently queued.  As a result, you have no control over which thread actually gets assigned to your work item, and normally, you don't care.&lt;br /&gt;&lt;br /&gt;But for the Gaming Engine, my needs are a little different.  I want to ensure that Game objects process one and only one work item (Command) at a time, and that these occur in a definite sequence.  Thus, instead of the thread pool, the Gaming Engine creates a fixed number of threads.  Every game is "owned" by a thread; all calls into the game are guaranteed to be called from the very same thread.  To do this, I needed my own queue.  Basically, the Game Engine does this kind of work on one of these worker threads:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;Queue&amp;lt;Command&amp;gt; _queue = new Queue&amp;lt;Command&amp;gt;();&lt;br /&gt;Command cmd;&lt;br /&gt;&lt;br /&gt;while ( false )&lt;br /&gt;{&lt;br /&gt;   Command cmd = queue.Dequeue();&lt;br /&gt;   if ( cmd != null )&lt;br /&gt;   {&lt;br /&gt;      Game game = GetCorrectGame();&lt;br /&gt;      game.SubmitCommand( cmd );&lt;br /&gt;   }&lt;br /&gt;   else&lt;br /&gt;   {&lt;br /&gt;      Thread.Sleep(100);&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This code is okay, but not great.  If the queue is full, then items are processed quickly, but if the queue is empty, the thread sleeps.  When an item is finally enqueued, the thread does not automatically wake; rather, it waits until it is done sleeping.&lt;br /&gt;&lt;br /&gt;I wanted a class that would allow me to wait, but immediately wake once an item has been enqueued.  Enter the WaitableQueue&amp;lt;T&amp;gt; class (code shown below).  It functions just like a normal queue, with Enqueue() and Dequeue() methods.  It also introduces the WaitAndDequeue method:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;bool WaitableQueue&amp;lt;T&amp;gt;.WaitAndDequeue(int timeout, out T item);&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;If there is an item in the queue, this method functions just like Dequeue.  If the queue is empty, the method will block until another thread calls Enqueue(), or until the timeout period is reached.  As you can probably guess, the method returns true if an item is returned, or false if no item is returned.&lt;br /&gt;&lt;br /&gt;This is a class I designed myself, although I did look at an example of a blocking queue to clean up my design (see the section on "Blocking Queue" in the &lt;a href="http://msdn.microsoft.com/msdnmag/issues/07/05/CLRInsideOut/default.aspx"&gt;May 2007 MSDN Magazine CLR Inside Out&lt;/a&gt; column.  Basically, you can use the queue like so, assuming you have a class named WorkItem:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;WaitableQueue&amp;lt;WorkItem&amp;gt; queue = new WaitableQueue&amp;lt;WorkItem&amp;gt;();&lt;br /&gt;int timeout = 5000;  // arbitrary&lt;br /&gt;&lt;br /&gt;// Let's assume another thread can call queue.Enqueue()&lt;br /&gt;&lt;br /&gt;while ( !bTimeToQuit )&lt;br /&gt;{&lt;br /&gt;   WorkItem item;&lt;br /&gt;   if ( queue.WaitAndDequeue(timeout, out item) )&lt;br /&gt;   {&lt;br /&gt;      // Do work with item&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The implementation is straightforward enough.  The class contains a Queue and an AutoResetEvent.  The event is used to signal to a waiting thread that there is an item ready to be picked up.  After the item is enqueued, the event is Set, and any thread which is waiting on the event will be woken up.&lt;br /&gt;&lt;br /&gt;The call to WaitAndDequeue is a bit more interesting.  If there is an item already present, it immediately dequeues the item and clears the event, avoiding any wait.  If not, it calls Event.WaitOne(), passing the timeout value.  The lock(_queue) is used to ensure that only one thread is actively waiting on the event.  The lock(_evt) is used to ensure that the state of the event (signaled or not) is kept in sync with the count of queue items.&lt;br /&gt;&lt;br /&gt;Feel free to use this class, royalty-free if you like.  Disclaimer:  Use the code at your own risk -- I am not responsible for any use or misuse of this code in your project, or any losses you encur!  Hey, it's my first code post, gotta be careful. :) &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Threading;&lt;br /&gt;&lt;br /&gt;namespace JamesQMurphy.Common.Collections&lt;br /&gt;{&lt;br /&gt;   [Serializable]&lt;br /&gt;   public sealed class WaitableQueue&amp;lt;T&amp;gt;&lt;br /&gt;   {&lt;br /&gt;      // The actual queue&lt;br /&gt;      private Queue&amp;lt;T&amp;gt; _internalQueue = new Queue&amp;lt;T&amp;gt;();&lt;br /&gt;&lt;br /&gt;      // Event used to trigger to readers that an item has been queued&lt;br /&gt;      [NonSerialized]&lt;br /&gt;      private AutoResetEvent _evt = new AutoResetEvent(false);&lt;br /&gt;&lt;br /&gt;      // We lock on the objects above in the following ways:&lt;br /&gt;      // lock( _internalQueue )&lt;br /&gt;      //      Used by readers (dequeue-ers) only.  This ensures that only&lt;br /&gt;      //      one reader is ever waiting on the event.&lt;br /&gt;      //&lt;br /&gt;      // lock ( _evt )&lt;br /&gt;      //      Used by readers (dequeue-ers) and writers (enqueue-ers).&lt;br /&gt;      //      This ensures that the state of the event is always&lt;br /&gt;      //      consistent with the queue:&lt;br /&gt;      //          Signaled ==&amp;gt; queue has an item&lt;br /&gt;      //          Cleared  ==&amp;gt; queue is empty&lt;br /&gt;&lt;br /&gt;      public bool Contains(T item)&lt;br /&gt;      {&lt;br /&gt;         // Locking is pointless here&lt;br /&gt;         return _internalQueue.Contains(item);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public int Count&lt;br /&gt;      {&lt;br /&gt;         // Locking is pointless here&lt;br /&gt;         get { return _internalQueue.Count; }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public void Enqueue(T item)&lt;br /&gt;      {&lt;br /&gt;         lock ( _evt )&lt;br /&gt;         {&lt;br /&gt;            _internalQueue.Enqueue(item);&lt;br /&gt;            _evt.Set();&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public T Dequeue()&lt;br /&gt;      {&lt;br /&gt;         T item;&lt;br /&gt;         if ( TryDequeue(out item) )&lt;br /&gt;         {&lt;br /&gt;            return item;&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;            throw new InvalidOperationException("Queue is empty");&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public bool TryDequeue(out T item)&lt;br /&gt;      {&lt;br /&gt;         return WaitAndDequeue(0, out item);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      // Note:  all dequeue functions go thru here&lt;br /&gt;      public bool WaitAndDequeue(int timeout, out T item)&lt;br /&gt;      {&lt;br /&gt;         item = default(T);&lt;br /&gt;&lt;br /&gt;         // Let only one reader in to wait and watch the event&lt;br /&gt;         lock ( _internalQueue )&lt;br /&gt;         {&lt;br /&gt;            // If the queue is populated, no need to wait&lt;br /&gt;            lock ( _evt )&lt;br /&gt;            {&lt;br /&gt;               if ( _internalQueue.Count &amp;gt; 0 )&lt;br /&gt;               {&lt;br /&gt;                  _evt.Reset();&lt;br /&gt;                  item = _internalQueue.Dequeue();&lt;br /&gt;                  return true;&lt;br /&gt;               }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            // Queue is empty.  Wait on the event; if it signals,&lt;br /&gt;            // then something has been queued&lt;br /&gt;            if ( _evt.WaitOne(timeout, false) )&lt;br /&gt;            {&lt;br /&gt;               item = _internalQueue.Dequeue();&lt;br /&gt;               return true;&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;               // Nothing queued while we waited; we timed out&lt;br /&gt;               return false;&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public void Clear()&lt;br /&gt;      {&lt;br /&gt;         // Make sure these are locked in the same order as WaitAndDequeue,&lt;br /&gt;         // otherwise it will introduce a deadlock&lt;br /&gt;         lock ( _internalQueue )&lt;br /&gt;         {&lt;br /&gt;            lock ( _evt )&lt;br /&gt;            {&lt;br /&gt;               _internalQueue.Clear();&lt;br /&gt;               _evt.Reset();&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-5676053479401157687?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/5676053479401157687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=5676053479401157687' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/5676053479401157687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/5676053479401157687'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/09/waitable-queue.html' title='A Waitable Queue'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-6913130037568120622</id><published>2007-08-30T12:13:00.000-07:00</published><updated>2007-08-30T12:17:45.114-07:00</updated><title type='text'>The blog's not dead... really!</title><content type='html'>What in the world happened?  I'm not sure myself.  One minute, you're getting geared up for summer; the next, it's almost over.  A summer of lawn-mowing, baseball, and programming.  Gone in an instant.&lt;br /&gt;&lt;br /&gt;Actually, I do know what happened.  Rather than blog about the Game Engine, I've actually been working on it.  Or, more precisely, reworking it.  I know, I know, it shows lack of discipline.  The problem is, I've been so involved in reworking the engine that I really have had little time for anything else.&lt;br /&gt;&lt;br /&gt;The first thing I did was redesign the communication layer to use WCF, which was actually quite easy, given the fact that I had already defined the contract, at least conceptually.  I started from the ground up, creating new solution files, new NUnit test cases, and new dependencies.  This gave me a chance to rename some of my objects (e.g., "GameObject" is now finally "Game").  I'll cover more about the WCF end of it in another post.&lt;br /&gt;&lt;br /&gt;What I did want to talk about was the separation of display from game logic.  This is one of the tenets of &lt;em&gt;n&lt;/em&gt;-tier design:  Design a business-layer that's independent of display logic, and then design your front end(s) against that business layer.  This allows you to put several different types of front-ends (desktop application, Web application, cell-phone app, etc.) against the same back-end -- this reduces code duplication, which I believe is one of the fundamental evils of programming.  It also allows easy reuse of code, especially if your business layer is easily accessible.&lt;br /&gt;&lt;br /&gt;I wanted more than a conceptual separation of display and logic; I wanted a physical separation.  On the (game) server side, there is no need for display logic, so I didn't want any display-related assemblies (such as System.Windows.Forms.dll) loaded.  However, the gaming system will need display-related base classes and infrastructure.  These would go in a separate base assembly.  It would also require every game to be deployed into two assemblies (if not, then the display logic gets loaded into the server process), although a collection of games could be deployed in two assemblies.&lt;br /&gt;&lt;br /&gt;Up until recently, I figured I had two choices for display logic:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;WinForms.&lt;/strong&gt;  I'm familiar with this, but it would require the end user to download code.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Javascript/AJAX.&lt;/strong&gt;  Limited, but without the download problem.  I'm not that familiar with it (although I have friends that are)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Two new technologies have emerged that caught my eye:  &lt;strong&gt;Silverlight&lt;/strong&gt; and &lt;strong&gt;XNA Game Studio&lt;/strong&gt;, both from Microsoft.  I'll be evaulating both of them to see which is best.  But in the meantime, since I want something out there and completed, I'll stick with WinForms.&lt;br /&gt;&lt;br /&gt;Next time... I'll introduce the new Game object properly!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-6913130037568120622?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/6913130037568120622/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=6913130037568120622' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6913130037568120622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6913130037568120622'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/08/blogs-not-dead-really.html' title='The blog&apos;s not dead... really!'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-477387697690207382</id><published>2007-05-14T18:12:00.000-07:00</published><updated>2007-05-15T03:29:36.173-07:00</updated><title type='text'>One thing and not the other</title><content type='html'>So, by now you would have thought, "Gee, he must be done with his system." Well, no. I did spec out a box, somewhat, but these are the things that have been holding me back:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;First, I set out looking for a HD Tuner card with CableCard support. One problem... there aren't any. At least none for do-it-yourselfers like me.&lt;/li&gt;&lt;li&gt;Verizon just dropped fiber-optic cable to my curb (actually, my pole), allowing me to get FiOS if I wanted it. I'm not sure if I do or not... I hate Verizon, which is why I switched to Vonage. But I'm also not thrilled with Cablevision either.&lt;/li&gt;&lt;li&gt;I have had no luck finding hybrid hard drives on the market. These are the hard drives with on-board flash memory... it makes for a &lt;em&gt;very &lt;/em&gt;speedy drive.&lt;/li&gt;&lt;/ol&gt;So, I'll wait.&lt;br /&gt;&lt;br /&gt;In the meantime, I have actually been making some good progress on the game engine. A good review of the game engine is &lt;a href="http://www.blogger.com/2006/09/history-shouldnt-repeat-and-also.html"&gt;here&lt;/a&gt;, but there was one fatal flaw with my design. Recall that I had descdribed a "master" Game object that sits on the server, and each player had a "satellite" Game object on the local client that would be kept in synch. Players could submit commands to the master Game object, and a short while later, the satellites would receive synchronization events.&lt;br /&gt;&lt;br /&gt;Well, it turns out that actually programming this way was difficult. Take TicTacToe. After submitting a command ("X in the center square"), the Game object would update the state (Center Square, X), then broadcast an event. Satellite game objects would receive the event and make the same update. In other words, there were two mechanisms to update state. This complicated things like validation ("Is it X's turn, and is the center square open?").&lt;br /&gt;&lt;br /&gt;Then it hit me. I had the model wrong. Here is the refined version:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;There is only one Game object. It sits on the server, and it responds to Commands.&lt;/li&gt;&lt;li&gt;The Game object updates a GameState object, which also sits on the server. The GameState object is just that -- state. In the TicTacToe example, it holds the state of the board, i.e., where the X's and O's are.&lt;/li&gt;&lt;li&gt;The stock GameState object will suffice for most games, although you can derive from it. The base class contains four collections:&lt;br /&gt;a.  A public collection.  Everybody sees this.&lt;br /&gt;b.  A public per-slot collection.  Everybody sees these as well.&lt;br /&gt;c.  A private collection.  Nobody seese this.&lt;br /&gt;d.  A private per-slot collection.  Each player sees his/her own collection, but not &lt;/li&gt;&lt;li&gt;Each player has his/her own GameState object, which gets used for rendering.  The player's GameState has the same four collections, except that:&lt;br /&gt;a.  They don't have anything in their private collection&lt;br /&gt;b.  They can see the contents of their private per-slot collection, depending on what slot they are in, but cannot see what is in the other slots.&lt;/li&gt;&lt;/ol&gt;The GameEngine is capable of synchronizing the collections using Actions.&lt;br /&gt;&lt;br /&gt;There was one catch:  The Game object itself can freely update state, but in order to ensure that any state updates were transmitted, I protected the GameState object so that state can only be updated in the context of an Action.  Thus, this code:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;this.GameState.Public["some_element"] = "some value";&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;would only work if triggered from an Action.  This worked out well, and in no time I had a clean TicTacToe implementation.  I still need to work on end-of-game conditions, but once I do, I'll post it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-477387697690207382?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/477387697690207382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=477387697690207382' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/477387697690207382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/477387697690207382'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/05/one-thing-and-not-other.html' title='One thing and not the other'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-213389313436181690</id><published>2007-03-19T17:48:00.000-07:00</published><updated>2007-03-19T18:28:01.215-07:00</updated><title type='text'>Building a PC</title><content type='html'>I mentioned that I want to build a new PC for my family room.  And here's my requirements:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It has to do DVR&lt;/li&gt;&lt;li&gt;It has to access my MP3 and my pictures, which are on my Networked Attached Storage (NAS)&lt;/li&gt;&lt;li&gt;It has to serve as a gaming console -- games should look good on a 32" LCD TV.&lt;/li&gt;&lt;li&gt;It has to act as a music synthesizer for my &lt;a href="http://www.m-audio.com/products/en_us/Keystation49e-main.html"&gt;M-Audio Keystation 49e&lt;/a&gt;&lt;/li&gt;&lt;li&gt;It has to control my X10 devices&lt;/li&gt;&lt;li&gt;It has to look great&lt;/li&gt;&lt;/ul&gt;In short, I'm envisioning this as my master-control computer.  I want my family room to be the "bridge" of my house.&lt;br /&gt;&lt;br /&gt;I've built my own machines in the past, and I love doing it.  It's really not that hard.  I sat down and started to pick the components:&lt;br /&gt;&lt;br /&gt;1.  I actually started with the last requirement -- that it look great.  I wanted a pretty case with front-facing USB ports (for importing pictures, hooking up the Keystation 49e, etc.)  and with an LCD panel.  I went over to performance-pcs.com and started to browse.  Silverstone makes a lot of nice cases, but one that caught my eye was &lt;a href="http://www.performance-pcs.com/catalog/index.php?main_page=product_info&amp;products_id=4658"&gt;Kingwin's Supernova SN-213HTBK&lt;/a&gt; case.   Gotta read up on it.&lt;br /&gt;&lt;br /&gt;2.  Most of the nice cases do not accept full ATX-sized motherboards.  The Supernova accepts MicroATX.  Okay, fine.  Let's assume we're going with a Micro ATX-sized motherboard.&lt;br /&gt;&lt;br /&gt;3.  When it comes to motherboards, I only buy Intel.  I've had bad luck with Asus boards.  The Intel board I bought a few years back has &lt;em&gt;never&lt;/em&gt; given me any trouble.  Ok, Intel motherboard.&lt;br /&gt;&lt;br /&gt;4.  This actually presented some other questions.  What kind of processor?  I definitely want at least a Core 2 Duo processor.  Yes, Intel introduced their Quad-core processor, but only their top-of-the-line motherboard accepts it, and besides the inflated price, it's full-ATX sized.  The Core 2 Duo is fast enough, I reasoned, especially if you have a beefy graphics card, plenty o' memory, and fast hard drives.  So I settled for the &lt;a href="http://www.intel.com/products/motherboard/DG965OT/"&gt;DG965OT&lt;/a&gt; -- it's got the 965 chipset and it's MicroATX.  There's a limited number of slots -- in fact, there's only one PCI Express x16 slot -- but I knew that I would only be adding a few cards (graphics card + TV Tuner card).&lt;br /&gt;&lt;br /&gt;5.  Speaking of graphics card, I had a tough choice.  I love my ATI Radeon 9800 series card in my current system, but since I knew I would be running Vista, I wanted a DirectX 10 card.  Enter the NVidia GeForce 8800 GTX.  And yes, I know that the 965 chipset doesn't support SLI (read about SLI &lt;a href="http://techreport.com/etc/2004q2/nvidia-sli/index.x?pg=1"&gt;here&lt;/a&gt;), but then again, there's only going to be room for one of these cards anyway.  (Not to mention that this card runs hot -- hotter than &lt;a href="http://www.google.com/search?hl=en&amp;q=asli+bilgin"&gt;Asli Bilgin&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;6.  I've heard that the DVR capabilities of Vista are actually quite good, so I decided that I would run Vista.  More on that later.&lt;br /&gt;&lt;br /&gt;I also will touch upon hard drives and tuner cards in a later post.  That's where it gets interesting!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-213389313436181690?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/213389313436181690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=213389313436181690' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/213389313436181690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/213389313436181690'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/03/building-pc.html' title='Building a PC'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-9120912253968677023</id><published>2007-03-16T03:12:00.000-07:00</published><updated>2007-03-16T03:20:05.244-07:00</updated><title type='text'>So what have I been up to?</title><content type='html'>Yikes, two months go by without a post!  Here's what's up.&lt;br /&gt;&lt;br /&gt;Weight goal:  Forget it.  What I've been doing instead is following the &lt;a href="http://www.mensfitness.com/yearlong"&gt;yearlong program&lt;/a&gt; at Men's Fitness magazine.  Although I haven't been dropping weight, I have been adding muscle.&lt;br /&gt;&lt;br /&gt;Gaming engine:  Only a few minor tweaks here and there.  Nothing substantial.&lt;br /&gt;&lt;br /&gt;What I will be talking about over the next few posts is my building a new PC.  I will be building a combination gaming machine and DVR (digitial video recorder -- like TiVo).  This is actually not that common; most people usually do not build gaming machines that do DVR.  But this is for a machine that I want to sit in my family room, and hook up to our 32" LCD television.&lt;br /&gt;&lt;br /&gt;More to come!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-9120912253968677023?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/9120912253968677023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=9120912253968677023' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/9120912253968677023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/9120912253968677023'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/03/so-what-have-i-been-up-to.html' title='So what have I been up to?'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-3456536951120478447</id><published>2007-01-26T05:47:00.000-08:00</published><updated>2007-01-26T06:04:41.714-08:00</updated><title type='text'></title><content type='html'>A &lt;a href="http://jamesqmurphy.blogspot.com/2007/01/giving-it-try.html"&gt;few weeks ago&lt;/a&gt;, I mentioned my weight goal:  A pound a week, starting at 185 pounds.  Well, my progress hasn't been so stellar:&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;th&gt;Week&lt;/th&gt;&lt;th&gt;Goal&lt;/th&gt;&lt;th &gt;Weight&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;185&lt;/td&gt;&lt;td&gt;185&lt;/td&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;184&lt;/td&gt;&lt;td&gt;183&lt;/td&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;183&lt;/td&gt;&lt;td&gt;184&lt;/td&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;182&lt;/td&gt;&lt;td&gt;???&lt;/td&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;I've been doing the first installment of the year-long workout in Men's Fitness magazine.  They finally posted it &lt;a href="http://www.mensfitness.com/year_workout_program/fitness/workout_routines/153"&gt;here&lt;/a&gt;.  This week, I did workout A on Monday, B on Tuesday, and C on Wednesday.  Overall, I like them -- they've been a good "shock" to my body and I've been hitting my muscles differently than with my old workout.  I've even hit a few that I never hit before!  Today, I took the day off and I'm trying another shock.  I will do my &lt;em&gt;entire&lt;/em&gt; traditional routine in one day, then use my 20% coupon for a deep-tissue massage.  Let's hope that gets me down to 182.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-3456536951120478447?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/3456536951120478447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=3456536951120478447' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/3456536951120478447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/3456536951120478447'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/01/few-weeks-ago-i-mentioned-my-weight.html' title=''/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-7402268751761947257</id><published>2007-01-22T18:08:00.001-08:00</published><updated>2007-01-22T18:08:51.395-08:00</updated><title type='text'>Pretty as an IP Address</title><content type='html'>&lt;div style="float: right; margin-left: 10px; margin-bottom: 10px;"&gt; &lt;a href="http://www.flickr.com/photos/54399929@N00/366506623/" title="photo sharing"&gt;&lt;img src="http://farm1.static.flickr.com/130/366506623_06f6074d8d_m.jpg" alt="" style="border: solid 2px #000000;" /&gt;&lt;/a&gt; &lt;br /&gt; &lt;span style="font-size: 0.9em; margin-top: 0px;"&gt;  &lt;a href="http://www.flickr.com/photos/54399929@N00/366506623/"&gt;9block&lt;/a&gt;  &lt;br /&gt;  Originally uploaded by &lt;a href="http://www.flickr.com/people/54399929@N00/"&gt;JamesQMurphy&lt;/a&gt;. &lt;/span&gt;&lt;/div&gt;This is my home IP address, shown using Don Park's Identicon algorithm.  You can read about it &lt;a href="http://www.docuverse.com/blog/donpark/2007/01/18/visual-security-9-block-ip-identification"&gt;here&lt;/a&gt;.  You can see what yours looks like &lt;a href="http://www.docuverse.com/blog/9block"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Basically, the algorithm plugs your IP address through the SHA-1 hash to generate the pattern.  Don uses it as an identifier and displays it next to poster's names.  Pretty cool, eh?&lt;br clear="all" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-7402268751761947257?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/7402268751761947257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=7402268751761947257' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7402268751761947257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7402268751761947257'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/01/pretty-as-ip-address.html' title='Pretty as an IP Address'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm1.static.flickr.com/130/366506623_06f6074d8d_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-8415680155396035231</id><published>2007-01-20T11:01:00.000-08:00</published><updated>2007-01-20T12:05:32.868-08:00</updated><title type='text'>Dogs and Ponies from Microsoft</title><content type='html'>Occasionally, we have presenters from Microsoft come by and showcase the new technologies. This past Thursday, we had a couple of presenters come by and talk about Windows Presentation Framework, Windows Communication Framework, and Visual Studio Team System. Now, we are a Microsoft shop, although we do use other tools and technologies (Oracle, Rational ClearQuest, etc.). Still, the presentations do tend to come off a bit sales-ish. The best way to guard against this is to accept this; I went with the mindset that this was a Microsoft-only trade show. Once you get past it, you can enjoy the show.&lt;br /&gt;&lt;br /&gt;Here's what transpired:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Intro to .NET 3.0&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;I can sum it up with a simple equation:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;.NET 3.0 = .NET 2.0 + WPF + WCF + WF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;WPF = Windows Presentation Framework&lt;br /&gt;WCF = Windows Communication Framework&lt;br /&gt;WF = Windows Workflow Framework (can't use WWF, that's for the wildlife federation)&lt;br /&gt;&lt;br /&gt;Yep, .NET 3.0 does not contain a new version of the CLR. It installs right alongside .NET 2.0, and only adds the components above.&lt;br /&gt;&lt;br /&gt;The presentation was given by Asli Bilgin, who is a brilliant presenter and always fun to listen to.  Don't know who she is?  &lt;a href="http://www.google.com/search?hl=en&amp;q=asli+bilgin"&gt;Google her&lt;/a&gt;.  Better yet, &lt;a href="http://images.google.com/images?q=asli%20bilgin&amp;amp;hl=en"&gt;Google her image&lt;/a&gt; -- she is gorgeous!  Well, at least I think she is.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Windows Presentation Framework&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;I'll be honest -- this presentation was a letdown. I expected a demo of the power of WPF and XAML, the XML-based presentation language. Instead, it was a sales pitch for Microsoft's new Expression line of web designer software (think Frontpage trying to be DreamWeaver). It started out good; Asli demonstrated the NY Times reader -- a smart client app that downloads the paper and displays it using WPF technologies. A very cool app! But then she started to demo Expression Blend by building a web app. Which web app? A simple click-on-the-thumbnail and see-the-full-size-image type of app. YAWN SNOOZE it was no easier than five years ago with Visual Studio 2002. Boo!&lt;br /&gt;&lt;br /&gt;(Yes, I did ask her a question related to my gaming engine, but more on that at a later date.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Windows Communication Framework&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;This one was about what I expected. I have been reading bits and bobs about WCF, and how it's supposed to be the be-all and end-all of any communications going forward. It was a good introduction, the instructor (I can't remember his name; he was good, but hey they can't all be as cute as Asli Bilgin) demonstrated how today's web services can be written as WCF service endpoints. Basically, that's the gist of the technology; you define interfaces (yes, .NET interfaces), attribute-decorate them as service endpoints, and then write classes to implement the interfaces. .NET takes care of the communications underneath, in a declarative-style configuration manner. I only wish that the sample was explained a little better. Case in point: The presenter had a class that called another class. Great, we saw the output. But then he switched the protocol mechanism to use gzip transmission, instead of plain text. The same output. He opened &lt;a href="http://www.fiddlertool.com/fiddler/"&gt;Fiddler&lt;/a&gt; (which is a great tool, btw) and showed that the request size shrunk. But why didn't he show the raw transmission? That would have made it much more effective. He glossed over a lot of details but it was a good talk overall.&lt;br /&gt;&lt;br /&gt;(WCF is making me think a great deal about the gaming engine; specifically, how clients retrieve the Actions generated by the games on the gaming server).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Visual Studio Team System&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;This turned out to be a pleasant surprise; too bad we won't be adopting it anytime soon where we work. VSTS is a client/server based solution for software construction. It incorporates project tracking, source control, unit testing, and a build system, all-in-one. It incorporates FXCop and their test software (their version of NUnit) right into the package -- you can even have it prevent check-ins unless it passes the tests. It even has client applications for managers and non-developers, allowing other project stakeholders the ability to gauge project status. Very cool. But it also has some features that don't seem that valuable to me. For example, it also has the ability to "virtually deploy" the app to a "virtual enterprise", supposedly giving you the ability to detect deployment problems. (Yeah right!) I would have also liked to see some collaboration tools built in, like forums or wikis. And integration with other bug-tracking software is promised (we use ClearQuest, for example). But overall, I wish we were using the package today.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-8415680155396035231?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/8415680155396035231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=8415680155396035231' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/8415680155396035231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/8415680155396035231'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/01/occasionally-we-have-presenters-from.html' title='Dogs and Ponies from Microsoft'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-6307439941370387519</id><published>2007-01-10T03:15:00.000-08:00</published><updated>2007-01-10T03:36:56.706-08:00</updated><title type='text'>Mocking about</title><content type='html'>I came across an excellent article on the difference between mock objects and stub objects on Martin Fowler's blog. The article is &lt;a href="http://martinfowler.com/articles/mocksArentStubs.html"&gt;here&lt;/a&gt;.  (And then there's Jeff Atwood's take on it &lt;a href="http://www.codinghorror.com/blog/archives/000765.html"&gt;here&lt;/a&gt;, with his &lt;span style="font-style: italic;"&gt;brilliant &lt;/span&gt;illustrations of the different types of objects.  If you are a coder, you should go read his blog, &lt;a href="http://www.codinghorror.com/blog/"&gt;Coding Horror&lt;/a&gt;.  I'm serious, go read it.  Now.)&lt;br /&gt;&lt;br /&gt;In my test cases for the gaming engine, I had a class named &lt;span style="font-family: courier new;"&gt;mock_Game&lt;/span&gt; that would be a test game.  It was not a playable game -- it would only do a few things and only respond to a few actions.  Its state would be exposed so that the unit test could inspect the results.  Well, that's what you get for being new to test driven development -- this is a &lt;span style="font-weight: bold;"&gt;stub &lt;/span&gt;object, not a mock object.  Mock objects are proxy objects that are used to test &lt;span style="font-style: italic;"&gt;behaviors&lt;/span&gt;.  With them, you test to see if certain methods were called, and in what order.  Stubs are used to test &lt;span style="font-style: italic;"&gt;state&lt;/span&gt;.  You use them to see if the data matches what you expect.&lt;br /&gt;&lt;br /&gt;Apparently, there are mock object libraries out there that take existing real objects and are able to construct mock objects.  I think I'm going to look into this and see what's brewing.  The notion of being able to test behavior is very useful.&lt;br /&gt;&lt;br /&gt;On a separate note: At the gym, I ran 5K in 28:35 -- a new personal best!  Today, I will be doing workout "B" in the Men's Fitness workout.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-6307439941370387519?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/6307439941370387519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=6307439941370387519' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6307439941370387519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/6307439941370387519'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/01/mocking-about.html' title='Mocking about'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-8273241353557626385</id><published>2007-01-08T18:31:00.000-08:00</published><updated>2007-01-08T18:54:39.268-08:00</updated><title type='text'>Giving it a try</title><content type='html'>I mentioned my new Men's Fitness subscription, and how there's a year-long excercise program.  I figured, what the hey, give it a whirl.  And thus it begins.&lt;br /&gt;&lt;br /&gt;I've been training for two years now, and this past year was my first serious training attempt.  My problem is not exercise, however -- it's diet.  Eating clean is tough, especially when things like ice cream exist.  So I thought I would use my blog to chronicle my progress.  Yeah, boring, but some people might say that programming a game engine isn't so riveting either.&lt;br /&gt;&lt;br /&gt;My goal?  Ten pounds in ten weeks.  A pound a week, using my bathroom scale, Monday mornings, right out of bed.  This morning, I was 185 lbs.  If I make my goal, that puts me at 175 on March 19.  (St. Patrick's day might make that tough, but here's hoping!)&lt;br /&gt;&lt;br /&gt;10 pounds to go!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-8273241353557626385?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/8273241353557626385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=8273241353557626385' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/8273241353557626385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/8273241353557626385'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/01/giving-it-try.html' title='Giving it a try'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-4784834292430179983</id><published>2007-01-04T18:27:00.000-08:00</published><updated>2007-01-04T18:41:06.129-08:00</updated><title type='text'>Not just programming</title><content type='html'>Funny, I expected to see a lot of new people at the gym this past week.  I did see two new people take a tour, but the gym wasn't crowded with newbies.  Generally, there are two times of the year when the gym gets crowded:  January and May.  January usually brings the New Years' resolutioners, May brings the bathing suit shoppers.&lt;br /&gt;&lt;br /&gt;For Christmas, I did get a subscription to Men's Health magazine.  I'm going to try their year-long workout and see what kind of results I get.  More to come on that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-4784834292430179983?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/4784834292430179983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=4784834292430179983' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/4784834292430179983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/4784834292430179983'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/01/not-just-programming.html' title='Not just programming'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-8762057403131579735</id><published>2007-01-01T07:04:00.000-08:00</published><updated>2007-01-01T07:58:04.642-08:00</updated><title type='text'>Doing the Fisher-Yates Shuffle</title><content type='html'>Turn the way-back machine to 1982. I was in 7th grade, and the most advanced computer in our house was the Atari 2600. But that was about to change. My father worked for IBM, and had ordered an IBM PC through the company's employee-purchase program. We waited all summer for the PC to come in (it finally came on September 1). But I wasn't sitting idly... I had read a fantastic book on BASIC programming. It was called &lt;a href="http://www.amazon.com/Instant-freeze-dried-computer-programming-BASIC/dp/0918398576/sr=1-49/qid=1167664009/ref=sr_1_49/104-9579466-9023910?ie=UTF8&amp;s=books"&gt;Instant BASIC&lt;/a&gt; and it written at the perfect level for a 7th grader. I had finished the book by early summer and had already written some programs in a spiral-bound notebook by the time the PC arrived (most notably, &lt;a href="http://en.wikipedia.org/wiki/Yahtzee"&gt;Yahtzee&lt;/a&gt; -- I guess I've always had a penchant for games).&lt;br /&gt;&lt;br /&gt;I was captivated by the last program in the book. It was a program to deal five cards from a deck of cards, and offer the user a chance to deal again from that deck or a new deck. The only problem is that it was used to teach two-dimensional arrays. The deck was a 4x13 array of flags. The program dealt a card by randomly determining the suit and rank ([1,4] and [1,13], respectively) and would use the array to see if the card had been dealt. The book pointed out that as you neared the end of the deck, it would take longer to find the remaining cards, and in fact would hang once you tried to deal the 53rd card.&lt;br /&gt;&lt;br /&gt;That never sat well with me, and I vowed to find a better solution. Essentially, the solution that I came up with was to represent a deck as a &lt;em&gt;flat&lt;/em&gt; array of 52 elements, and to randomly shuffle the contents. This is what I came up with (written in pseudo-C#):&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Random r = new Random();&lt;br /&gt;for ( i = 0; i &lt; 10000; i++)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;r1 = r.Next(0,52);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;r2 = r.Next(0,52);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SwapElements(deck, r1, r2);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;I patted myself on the back and considered the problem solved.  Until this morning, that is, when I read about the problems when doing this.  It turns out that this problem has been solved already, by the experts.  It is called the &lt;a href="http://www.nist.gov/dads/HTML/fisherYatesShuffle.html"&gt;Fisher-Yates shuffle&lt;/a&gt; (or sometimes, the Knuth shuffle), and here is the correct solution:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Random r = new Random();&lt;br /&gt;for ( i = 0; i &lt; 52; i++)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;r0 = r.Next(i,52);&amp;nbsp;&amp;nbsp;&amp;nbsp;// Note the use of "i", not zero!&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SwapElements(deck, i, r0);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Several sources have identified "bad" implementations, and most list the example where r1 is between 0 and 52. This actually introduces a bias into the shuffle. My original solution is not equivalent to the "bad" solution, but it might be just as bad. It is certainly much less efficient -- I set the loop to an arbitrarily high number, which is not necessary in the Fisher-Yates algorithm.&lt;br /&gt;&lt;br /&gt;It suffices to say, I'm glad that I found this out before I actually implemented any card-playing games in my gaming engine. This is one area of the engine that needs to be well-documented, and it would have been embarrassing had I implemented the wrong algorithm.&lt;br /&gt;&lt;br /&gt;One other note: I don't actually use the Random class in the gaming engine. The Random class implements the Knuth pseudo-random generator, which is not sufficient for most real gaming purposes. I use the RNGCryptoServiceProvider class to generate my random numbers, which generates cryptographically-secure random sequences.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-8762057403131579735?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/8762057403131579735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=8762057403131579735' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/8762057403131579735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/8762057403131579735'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2007/01/doing-fisher-yates-shuffle.html' title='Doing the Fisher-Yates Shuffle'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-7277531419602974798</id><published>2006-12-29T08:55:00.000-08:00</published><updated>2006-12-29T09:03:34.989-08:00</updated><title type='text'>No, no, I'm still here!</title><content type='html'>I hate when project work takes over life for a short while.  Although I haven't been blogging, I have been able to sneak in the occasional minute and work on the gaming engine.&lt;br /&gt;&lt;br /&gt;The only real progress I've made is on the seating rules.  Recall how I had five states for a slot?  (Occupied, Vacant, Open for Human, Open for Bot, Closed)  I decided that I didn't need the "Vacant" slot.  Instead, I introduced a "seating policy" that can be Autoseat, Player Choose, or Owner Choose.  When the policy is "Autoseat", the game engine will automatically attempt to fill a slot that is marked Open for Human.  When it's "Player Choose", then players can automatically take the seats themselves.  "Owner Choose" means just that... only the owner can seat the players. Bots are always considered "Autoseat" and the engine will always fill slots marked as "Open for Bot."&lt;br /&gt;&lt;br /&gt;Speaking of bots... I am tackling bots next.  I figure once that is done, I can begin working on the Game Harness -- a program that actually lets a game designer play-test the game.&lt;br /&gt;&lt;br /&gt;Later!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-7277531419602974798?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/7277531419602974798/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=7277531419602974798' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7277531419602974798'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/7277531419602974798'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/12/no-no-im-still-here.html' title='No, no, I&apos;m still here!'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-115993326433087190</id><published>2006-10-03T20:36:00.000-07:00</published><updated>2006-10-13T05:09:29.356-07:00</updated><title type='text'>Did you notice...</title><content type='html'>Is it just me, or does Ivan Rodriguez of the Detroit Tigers look like "Little Arturo" from the Powerpuff girls?&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.geocities.com/a_great_ivan_page/ivan3.jpg"&gt;&lt;img style="cursor: pointer; width: 400px;" src="http://www.geocities.com/a_great_ivan_page/ivan3.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.geocities.com/TelevisionCity/Broadcast/9481/images/gangreen3.JPG"&gt;&lt;img style="cursor: pointer; width: 400px;" src="http://www.geocities.com/TelevisionCity/Broadcast/9481/images/gangreen3.JPG" alt="" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-115993326433087190?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/115993326433087190/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=115993326433087190' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115993326433087190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115993326433087190'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/10/did-you-notice.html' title='Did you notice...'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-115937745014476319</id><published>2006-09-27T10:17:00.000-07:00</published><updated>2006-09-27T19:16:24.566-07:00</updated><title type='text'>History Shouldn't Repeat (and also, a review of the Game Engine)</title><content type='html'>&lt;p class="mobile-post"&gt;Ok, so why don't I want to replay the entire history of Actions to new players when they join a game? In theory, this sounds like it would work, but there are problems with the approach. Before I explain, let's review the basic engine.&lt;/p&gt;&lt;p class="mobile-post"&gt;A game consists of a Game object, sitting on a server. The players do not have direct access to this Game object; rather, each has his or her own, separate Game object, which is used to track the state of the game. You can think of this local game object as a player's "view" into the game. Although the players cannot access the server Game object, they can interact with it by submitting Commands to the game, and by listening for the resulting Actions. Any Actions received are fed into their local Game objects, and the local Games are kept in synch. (This is similar to some forms of database replication.)&lt;/p&gt;&lt;p class="mobile-post"&gt;In so-called &lt;a href="http://en.wikipedia.org/wiki/Perfect_information"&gt;perfect information&lt;/a&gt; games, i.e., games that have no secrets, players generally receive the same Actions as everybody else. Consider chess. When a player makes a move, both players (and any bystanders for that matter) see the action plainly. In this case, the Actions do not need to be filtered. The same can be said for games like Backgammon, where even though the outcome is left to chance (a roll of the dice), all players have identical information. However, in most card games (like poker), players receive a limited view of the game in that they can only see their cards, and any public cards on the table. Tournaments aside, bystanders cannot see &lt;em&gt;any&lt;/em&gt; of the face-down cards. &lt;a href="http://en.wikipedia.org/wiki/Blind_man"&gt;Blind Man's Bluff&lt;/a&gt; is unique in that players see all the cards &lt;em&gt;except&lt;/em&gt; their own. For this reason, Actions can be filtered and modified before being sent to the listeners. It is theoretically possible for every player to receive a different, customized Action. In most cases however, there will only be two flavors of an Action: filtered and unfiltered, and players will get one version or the other.&lt;/p&gt;&lt;p class="mobile-post"&gt;Now, consider what happens when a player joins the game. A local Game object is created on her computer, but this object, like a newly replicated database, must be synchronized with the server version. In theory, simply replaying the entire history Actions should do the trick. What are the problems?&lt;/p&gt;&lt;p class="mobile-post"&gt;For starters, filtering the Actions for the player becomes difficult. During normal play, the basis for filtering Actions is made by looking at the game state (Can this player see this card?). This is straightforward when the Action is current, but when replaying history to a new player, the decision must be made based on the game state &lt;em&gt;at the time of the Action&lt;/em&gt;. Requiring this would place a huge burden on game developers.&lt;/p&gt;&lt;p class="mobile-post"&gt;Second, what if the game has been played for hours, with new players constantly switching in and out? Replaying this history is inefficient, but the situation is even worse with poker. Skilled poker players observe the betting habits of other players, and adjust their play accordingly. If history is replayed to a new player, this new player has a distinct advantage over the established players. The established players would know nothing of the new player's habits, whereas the new player knows exactly what types of players he is up against.&lt;/p&gt;&lt;p class="mobile-post"&gt;Ok, so then, how do new players get their game synchronized? I decided to punt. Whenever a PlayerChangeAction is broadcast, the game &lt;em&gt;must&lt;/em&gt; also broadcast a GameStateAction. In other words, the game must broadcast its complete state, which includes a list of the players, the slots (described in my last entry), the players on standby, and of course, the details of the game. This means that, even if a player enters a game as a standby in the middle of game, the complete state will be broadcast to everyone, even though none of the players have changed. This does require that game developers implement functions to generate the game state on the fly(not including the player details, which would be handled by the engine), and to be able to synchronize to a given state when a GameStateAction event is received. I felt this was acceptable, and in fact also opens up other possibilities (for example, the ability to have a game be hot-swapped to another server, simply by transmitting the state).&lt;/p&gt;&lt;p class="mobile-post"&gt;Also note that GameStateActions can (and should) be filtered, just like all other actions. A player entering a card game would only see the face-up cards on the table, and not what is in the players' hands.&lt;/p&gt;&lt;p class="mobile-post"&gt;It should be worth noting that this research is leading me into the world of &lt;a href="http://en.wikipedia.org/wiki/Game_theory"&gt;game theory&lt;/a&gt;. For example, the types of games I have been modeling are called &lt;em&gt;extensive form&lt;/em&gt; games (as opposed to &lt;em&gt;normal form&lt;/em&gt; games). Neat, huh?&lt;/p&gt;&lt;p class="mobile-post"&gt;Next time, I'll talk about the necessity of updating game state only during Actions (and not during commands). I encountered this earlier, and it's been bugging me ever since.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-115937745014476319?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/115937745014476319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=115937745014476319' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115937745014476319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115937745014476319'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/09/history-shouldnt-repeat-and-also.html' title='History Shouldn&apos;t Repeat (and also, a review of the Game Engine)'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-115923535879422920</id><published>2006-09-25T18:28:00.000-07:00</published><updated>2006-09-25T19:26:47.063-07:00</updated><title type='text'>Slot Machine?</title><content type='html'>I usually try to work on the gaming engine during lunch, but for the past two weeks, work deadlines have made that impossible.  Nonetheless, I've been thinking about the engine, and as promised, I'll discuss the problems associated with adding and removing players.&lt;br /&gt;&lt;br /&gt;During the course of most games, the progression is such:  The players gather.  Somtimes, as they arrive, they take their seats at the game table.  The game is laid out, and sometimes, certain decisions are made.  (I remember showing up to play a game of &lt;a href="http://en.wikipedia.org/wiki/Dungeon_%28game%29"&gt;Dungeon&lt;/a&gt;, and both my friends had already chosen the coveted "Wizard" class, of which there are only two.)  Once all the players have arrived, the game commences and progresses, until there is a winner.  Sometimes players are eliminated, sometimes they stay until the end.  Pretty simple, yes?&lt;br /&gt;&lt;br /&gt;Now suppose a player has to leave.  Traditionally, there have been three courses of action:&lt;br /&gt;1.  &lt;strong&gt;Abandon the game.&lt;/strong&gt;  Yuck.&lt;br /&gt;2.  &lt;strong&gt;Put the game aside and play it later.&lt;/strong&gt;  Essentially, save the game.  Difficult to do in the physical world, where Mom and Dad would insist that the game be put away and there is little time to write down all the details.  Easy to do in the virtual world, of course!&lt;br /&gt;3.  &lt;strong&gt;Have another player take her place.&lt;/strong&gt;  Perfectly acceptable, if everyone is willing.  The advantage is that the game can continue.&lt;br /&gt;&lt;br /&gt;Notice how (for most games) that the game cannot continue unless there are the same number of players.  This model is straightforward to implement.  There are, of course, exceptions:  Poker and Yahtzee are two that come to mind.  But this opens up a whole new set of problems:  games in which the players can join and leave anytime.  How can that be implemented?  Even more importantly, what kind of model takes both types of games into account.&lt;br /&gt;&lt;br /&gt;But wait, there's more.  Consider an Internet-driven scenario, where a player starts up a type of game (say, the Cheapass game  &lt;a href="http://www.cheapass.com/free/games/fight.html"&gt;Fight!&lt;/a&gt;).  This is the kind of game where the number of players is constant, but he may not know how many players will be joining.  He may wait around, and once a certain number of people show up, then he will start the game.&lt;br /&gt;&lt;br /&gt;I settled upon a moderated chat-room model.  A player creates a game, and other players can come and go.  The initial player is the "owner" of the game, and as such has total control of the room.  She can invite players, boot players out, rearrange the seating, set up bots (Bots?  more on that later), etc.  The difficulty was that, once a game was started, how do you "freeze" the players so that no new players could barge in on the game, and yet not keep the players hostage, which is impossible to do anyway.  Plus, suppose a game was waiting for a final, fourth player, and two players entered the room at the same time.  One player would win the seat, obviously, but what would happen with the other player, who was expecting to join a game.  Putting up a "Sorry, you missed!" message seemed, well, mean.&lt;br /&gt;&lt;br /&gt;I got around these issues by developing this set of rules:&lt;br /&gt;1.  Games can hold an unlimited amount of people.  (Not players, people).  People can see who else is in the room and who is playing the game (and who is not).&lt;br /&gt;2.  Players can be invited to games, but they cannot enter a specific game on their own.&lt;br /&gt;3.  Players can "wait in line" for a certain type of game to open up.  When such a game needs a player, it can invite the player in.&lt;br /&gt;4.  Games have a limited number of &lt;em&gt;slots&lt;/em&gt;.  These slots are for those players who are actually playing the game.  The number of slots equals the maximum number of players that can play a certaing type of game.  This is important; a type of game &lt;em&gt;always&lt;/em&gt; has the same number of slots.  Chess has two, bridge has four, Parker Brothers' &lt;a href="http://en.wikipedia.org/wiki/Pay_Day_%28board_game%29"&gt;Payday&lt;/a&gt; has four, even if only two are playing.&lt;br /&gt;5.  Slots can have one of five states:  Occupied, vacant, open for human, open for bot, and closed.  The game owner can freely change the state of any slot; this is how he can control the number and types of players.  Here is what they mean:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Occupied&lt;/strong&gt; -- a player is in that slot&lt;br /&gt;&lt;strong&gt;Vacant&lt;/strong&gt; -- the slot is empty, but available.  Only the owner can place a player or bot in this slot.&lt;br /&gt;&lt;strong&gt;Open for Human&lt;/strong&gt; -- the slot is empty, but any player can enter the slot.&lt;br /&gt;&lt;strong&gt;Open for Bot&lt;/strong&gt; -- the slot is empty but is immediately filled with a bot by the game engine.&lt;br /&gt;&lt;strong&gt;Closed&lt;/strong&gt; -- the slot will not be occupied.  This is how owners control the number of players in a game.&lt;br /&gt;&lt;br /&gt;6.  If a player is in a room, she can be either in a slot, or she can be on standby.  While on standby, she can see who is occupying the slots, and can wait for a slot to open.  (Typically, this would happen in a friendly game, where the player would know the owner).&lt;br /&gt;7.  Removing a player from the game does not necessarily remove him from the room, although the owner can do that as well if she so chooses.  The player would simply be on standby until he was placed in a new slot.&lt;br /&gt;8.  A player can leave the room at any time.  At this point, the slot would revert to the "Empty" state, where the owner can assign another player, a bot, or open it up to other players.  Note that if the owner closes the slot, this could potentially end the game, as the number of players would have changed.  This decision would be left up to the specific game.&lt;br /&gt;&lt;br /&gt;It is important to note that when a player joins or leaves a game, or one of the slots changes state, an Action is generated and broadcast to all people in the room (not just the players in the slots).  Remember, the basic model is that Actions are broadcast to &lt;em&gt;all&lt;/em&gt; occupants, so therefore, the entire state of the room must be broadcast, so that the newcomer can receive a complete list of the occupants.&lt;br /&gt;&lt;br /&gt;That's all for now, it's getting late.  I still haven't answered the question I raised in my last post -- why not broadcast a complete history to newcomers.  But you might be able to guess at some of the reasons.  I promise -- more later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-115923535879422920?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/115923535879422920/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=115923535879422920' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115923535879422920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115923535879422920'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/09/slot-machine.html' title='Slot Machine?'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-115797797724691158</id><published>2006-09-11T05:05:00.000-07:00</published><updated>2006-09-11T05:42:28.296-07:00</updated><title type='text'>Game:  A series of (fortunate) events</title><content type='html'>In thinking about how to design a game engine, I realized that every game (at least the  ones that I can think of) are a series of events.  Pawn to K4, Pawn to KB4, Knight to KB3.  X in the center square, O in the upper-left corner.  Purchase a hotel on Boardwalk.  I chose to design the game around this concept -- it is an ordered sequence of things that happen.  Rather than use the word "event", which is already used in most programming languages (including C#), I settled on the word "Action".  By viewing a game as a stream of Actions, it solves some problems nicely:&lt;br /&gt;&lt;br /&gt;1.  &lt;span style="font-weight:bold;"&gt;Threading&lt;/span&gt;.  I wanted game design to be simple, and by guaranteeing that games are single-threaded, this simplifies things.  A game can sit happily on its thread, processing Actions one-by-one.&lt;br /&gt;&lt;br /&gt;2.  &lt;span style="font-weight:bold;"&gt;Scalability&lt;/span&gt;.  Ordered lists translate very nicely to queues, which scale very well.  &lt;br /&gt;&lt;br /&gt;3.  &lt;span style="font-weight:bold;"&gt;Auditing&lt;/span&gt;.  By storing the stream of events, a complete record of the game is kept.&lt;br /&gt;&lt;br /&gt;4.  &lt;span style="font-weight:bold;"&gt;Persistence&lt;/span&gt;.  Not only can a game be saved this way, but it can also be loaded by simply "playing" the stream from the beginning.&lt;br /&gt;&lt;br /&gt;5.  &lt;span style="font-weight:bold;"&gt;Transmission&lt;/span&gt;.  For multi-player scenarios, Actions can be broadcast to the appropriate players, and each would have an updated version of the game state.&lt;br /&gt;&lt;br /&gt;This works very well for deterministic games like chess, checkers, and TicTacToe, where Actions are 100% player-determined.  Initially, this was my first attempt -- each player would submit an Action, and the engine would submit it to the necessary parties.  Take TicTacToe, for example.  Suppose the board consists of nine squares, numbered 1 thru 9 (1 in the upper left, 5 in the center, 9 in the lower right).  When player 1 places an X in the upper-left corner, she would submit an action of "1", which would get broadcast to both players and any auditing routines.  If player 1 tries to submit again, before player 2, this would be considered an illegal move and would be trapped.  Once player 2 submits a move (let's say he chooses the center square, so he submits a "5"), the Action gets broadcast again.&lt;br /&gt;&lt;br /&gt;But what about games such as Backgammon, where the roll of the dice can change the outcome?  Certainly, a player cannot submit an action that translates into "I rolled a double-six."  This caused me to alter the model slightly:  Players would not submit Actions, they would submit their intent, which I call a "Command".  In the backgammon example, a player would submit a command to roll the dice, and the server would generate the appropriate Action (a "6-2" was rolled, for example).  Then the player would submit additional commands that indicated what her move was, which would in-turn generate more Actions.  Note that the other player would still see a stream of Actions (a roll of "6-2", then a move).  In the case of TicTacToe, the players submit Commands, which simply translate directly to Actions.&lt;br /&gt;&lt;br /&gt;Implementing the Command/Actions scenario turned out to be a little tricky.  Remember that one of my goals was to keep the amount of work simple -- I didn't want to have to design separate objects for the server version of the game and the client version.  So, Commands generate Actions, and the Actions get echoed to every Game object in the mix, incluing the server version itself.  This presented a little realization:  I could only update game state during the Action processing phase, not the Command processing phase.  This made sense:  during playback, for example, there would not be any Commands, so all game state updating needed to occur during the Action phase anyway.&lt;br /&gt;&lt;br /&gt;So far, so good.  There were two challenges that I saw:&lt;br /&gt;&lt;br /&gt;1.  &lt;span style="font-weight:bold;"&gt;Filtering of events&lt;/span&gt;.  During, say, poker, when a player is dealt a card, only that player can know what the card is.  In my mind, this was an easy problem:  simply filter the events before sending them to the players.  The actual player would get a truly descriptive action ("a 2 of clubs was dealt"), whereas the other players would get a filtered version ("a card was dealt").  Auditing and history listeners would get the full, unfiltered version.&lt;br /&gt;&lt;br /&gt;2.  &lt;span style="font-weight:bold;"&gt;Adding/Removing players&lt;/span&gt;.  This was a tough challenge, at least for me.  When a new player joins, he does not have a list of all the Actions that led up to the current game state.  (In fact, he doesn't even have a list of the players!)  While I could have chosen to simply replay all the events to the new player, I didn't want to go that route, for several reasons.  I'll describe my reasons and the solution in the next entry.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-115797797724691158?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/115797797724691158/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=115797797724691158' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115797797724691158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115797797724691158'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/09/game-series-of-fortunate-events.html' title='Game:  A series of (fortunate) events'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-115712035919815400</id><published>2006-09-01T07:19:00.000-07:00</published><updated>2006-09-02T08:53:43.546-07:00</updated><title type='text'>I'm not alone</title><content type='html'>A friend of mine just passed on a link to this blog.  I'll check it out!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.codinghorror.com/blog/archives/000669.html"&gt;http://www.codinghorror.com/blog/archives/000669.html&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-115712035919815400?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/115712035919815400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=115712035919815400' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115712035919815400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115712035919815400'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/09/im-not-alone.html' title='I&apos;m not alone'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-115711335313590626</id><published>2006-09-01T05:03:00.000-07:00</published><updated>2006-09-01T05:22:33.223-07:00</updated><title type='text'>TDD -- Tofu Driven Development?</title><content type='html'>I've been using TDD (Test Driven Development) on my gaming engine.  How's it going?  Well, it's going alright, I suppose.  It definitely takes some getting used to.  You know what it feels like?   It feels like "eating clean" -- you know it's good for you, and you see some benefits, but you'd much prefer to slip into your old habits.&lt;br /&gt;&lt;br /&gt;Eating "clean" is a term that bodybuilders use.  It means eating only healthful foods, good, clean food that is good for your body.  Naturally, this means no sweets, but it also means no processed foods, no bad fats, and no bad carbs (breads, pasta, etc.).  It also means no dairy -- lactose is a sugar.  In fact, Dr. John Emmett gives a compelling argument against dairy in his book, "Turning Back The Hands of Time".  (His website is &lt;a href="http://www.nufitness.net/"&gt;here&lt;/a&gt;.)  His argument is simple:  humans are the only mammal that continue to drink milk after being weaned.  He claims that's why you see no pudgy lions.  I've also seen this argument lots of places on the web.  And come to think of it, housecats will also drink milk if it is given to them, and housecats also tend to be fat.  I do work out, and I try to eat clean, but it's not easy -- especially when there's ice cream.  Oh, and cheese.  Me love cheese.&lt;br /&gt;&lt;br /&gt;Anyway, what about Test Driven Development?  Well it's like eating clean.  It's good for you, it produces clean code, and it requires discipline.  I've been programming my game engine and I can tell you that what I have so far is bug-free.  But it requires patience.  Whenever I create a new class (like my SeatManager which I'll describe another day), I create a set of test cases for it, to make sure the class behaves well.  I fully exercise the class before introducing it into the code.  This produces high-quality code.&lt;br /&gt;&lt;br /&gt;But it's slow, at least at first.  Because your forced to spend some time developing quality up front, it feels like your going at a snail's pace.  The only comfort is knowing that there are very few loose ends -- and for those that are there, I have a failing test case.&lt;br /&gt;&lt;br /&gt;Eat clean.  Code clean.  (Should that be my new motto?)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-115711335313590626?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/115711335313590626/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=115711335313590626' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115711335313590626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115711335313590626'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/09/tdd-tofu-driven-development.html' title='TDD -- Tofu Driven Development?'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-115604642475331905</id><published>2006-08-19T19:49:00.000-07:00</published><updated>2006-08-19T21:02:48.946-07:00</updated><title type='text'>Game Engine -- Let's talk</title><content type='html'>Okay, it's about time that I started talking about the gaming engine.  I'll start by talking about the design goals; &lt;span style="font-style:italic;"&gt;i.e.&lt;/span&gt;, what I wanted to accomplish.  I've mentioned that I wanted to create a framework that would allow me to create games without worrying about things like player connectivity, backup, etc.  Essentially, solve these problems once, encapsulate it into the framework, and never worry about it again.  I also mentioned that I was using Tic Tac Toe as a test game.&lt;br /&gt;&lt;br /&gt;Well, when I finally got .NET 2.0 and NUnit installed, I decided to take what I learned and rewrite from scratch, using a TDD (Test-driven development) approach.&lt;br /&gt;&lt;br /&gt;Here's the problems that I wanted to solve, listed out, along with some analysis:&lt;br /&gt;&lt;br /&gt;1.  &lt;span style="font-weight:bold;"&gt;Adding/Removing players.&lt;/span&gt;  First, there's the number of players.  Most games have a variable number of players, usually two to six or two to eight.  Some games (such as chess and checkers) have two and only two players.  Some games are elimination-style (think Monopoly).  Other games, like poker, can actually &lt;span style="font-style:italic;"&gt;change&lt;/span&gt; the number of players when somebody joins the game.&lt;br /&gt;&lt;br /&gt;This raises another interesting problem:  Who controls the players that join the game?  Some games can be "open" and anyone can join, but most users would want some measure of control over who can join (and who they can give the boot).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2.  &lt;span style="font-weight:bold;"&gt;Thwart cheating.&lt;/span&gt;  This is fundamental, and a crucial problem for large-scale commercial gaming sites.  But think about it for a moment.  For games such as chess and checkers, can you really cheat?  The only way to cheat at these types of games is to distract your opponent, and while she is not looking, rearrange the pieces on the board.  (And any half-decent player will immediately notice!)  Ok, the first type of cheating -- modifying game state -- is easy enough to solve.&lt;br /&gt;&lt;br /&gt;But the second type of cheating -- accessing to privileged information -- is more commonplace and comes in many flavors.  During a card game, if a player can read the cards of his opponents, he can better his game.  If a player can predict the outcome of seemingly random events (i.e., she knows the next die roll during a Monopoly game), she can alter her decisions to take advantage.&lt;br /&gt;&lt;br /&gt;This problem can have some subtle challenges.  If a player is hosting a game on his computer, he technically has access to the entire game state.  Moreover, if a gaming system is written so that private information is passed to the clients, it must be written so that other players' information does not get passed to the client.  (Even if it is not displayed, it can still be "read" using debugging tools.)  Again, not a problem for chess, checkers, or TicTacToe, but a problem for most games.&lt;br /&gt;&lt;br /&gt;As you'll see later, I put this problem front-and-center.  The solution specifically addresses this problem.  (Hopefully it won't be months from now!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-115604642475331905?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/115604642475331905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=115604642475331905' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115604642475331905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115604642475331905'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/08/game-engine-lets-talk.html' title='Game Engine -- Let&apos;s talk'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-115094176522229437</id><published>2006-06-21T18:47:00.000-07:00</published><updated>2006-06-21T19:02:45.236-07:00</updated><title type='text'>Registry access bug in Visual Studio 2005</title><content type='html'>At Merrill Lynch, I have administrator rights to my machine (they're not easy to obtain any more, by the way).  Mostly, this is so that I can install tools, install the Merrill Lynch application frameworks, set up a local website, etc.  Also, it allows me to run certain legacy applications (such as PVCS).  Imagine the shock that Merrill Lynch will get when they learn that Visual Studio 2005 will also require admin access.&lt;br /&gt;&lt;br /&gt;On my home machines, I run Windows XP Professional.  I'm smart enough to create limited access user accounts for me, my wife, and my son.  It's kept us virus-free for years.  (My mother-in-law, who recently got a new computer and who runs as Administrator mode, managed to get SpyAxe on her computer.  When my wife asked if we could get it, I could confidently tell her that there was no way SpyAxe would be able to drop its naughty DLLs in our Windows\Systems directory.)&lt;br /&gt;&lt;br /&gt;Well, I was running Visual Studio 2005 (legally, mind you) on my home machine, from my limited user account.  I plugged in my thumb drive and started to write some test cases for my framework.  I went to add a file to the test project (Add New Item or Add Class) when I got a message box:  "Requested registry access not allowed."&lt;br /&gt;&lt;br /&gt;It turned out that there are a boatload of classes in HKEY_CLASSES_ROOT that do not have READ access for the Users group!  I found the answer on the MSDN forum, and even posted my two cents (see it &lt;a href="http://forums.microsoft.com/msdn/showpost.aspx?postid=156954&amp;siteid=1"&gt;here&lt;/a&gt;.)  Simply granting read access to the Users group did the trick.  I modified these three keys; there are many more that I didn't bother with:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;HKEY_CLASSES_ROOT\VisualStudio.cs.8.0&lt;br /&gt;HKEY_CLASSES_ROOT\VisualStudio.csdproj.8.0&lt;br /&gt;HKEY_CLASSES_ROOT\VisualStudio.csproj.8.0&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Hope this helps somebody out there!&lt;br /&gt;&lt;br /&gt;PS-- As far as my mother-in-law's SpyAxe infestation, a recent Microsoft update corrected the problem.  She may run as Administrator but she does have automatic updates turned on thankfully.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-115094176522229437?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/115094176522229437/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=115094176522229437' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115094176522229437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115094176522229437'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/06/registry-access-bug-in-visual-studio.html' title='Registry access bug in Visual Studio 2005'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-115089520032498851</id><published>2006-06-21T05:51:00.000-07:00</published><updated>2006-06-21T06:26:50.663-07:00</updated><title type='text'>Summer of TDD</title><content type='html'>The official start of summer -- how's my summertime programming going?&lt;br /&gt;&lt;br /&gt;Well, it's actually not as bad as it's been. I've got Visual Studio 2005 installed both at home and at work. I haven't tackled the game engine yet -- I've got a very small framework that I've been working on and converting to .NET 2.0.&lt;br /&gt;&lt;br /&gt;I've also downloaded NUnit (&lt;a href="http://www.nunit.org"&gt;http://www.nunit.org&lt;/a&gt;) and am seriously trying TDD -- test-driven development. TDD is something I've always believed in, and I've done it informally -- usually hacking together a test app or test page for web apps. NUnit lets you write test-case code, and it provides the harness that locates and runs all your tests.&lt;br /&gt;&lt;br /&gt;Now, normally, I hate third-party components and avoid them like the plague, especially when it's something I can write myself.  But I &lt;span style="font-weight: bold;"&gt;love&lt;/span&gt; NUnit. It's open-source, and you know what's nice? They tell you exactly what files are going where when you install it. Bravo! Another thing that I like is that NUnit itself is developed using TDD -- they eat their own dogfood (see &lt;a href="http://en.wikipedia.org/wiki/Eat_one%27s_own_dog_food"&gt;Wikipedia&lt;/a&gt; to see what that means).&lt;br /&gt;&lt;br /&gt;Here' how TDD works --you write the test first, then you write enough code just to get the test to compile, although it will fail when you run it.  Then you write code that makes the test succeed.  You refactor as needed, and you can refactor with confidence, since you have a boatload of test code that immediately tells you if you've broken anything.&lt;br /&gt;&lt;br /&gt;The one cardinal rule about TDD is that you don't write a line of code until you have a supporting test in place.  Another way of saying that is, if you have to write more code than you have tests, then you need more tests.  The one thing I don't understand is, how does that work with GUI programming?  Specifically, how can you test whether or not your program drew the graphic correctly?  Comparing screen bitmaps seems to coarse a method.  At least NUnit lets you download the source (and the test cases); maybe I'll see how they did it.&lt;br /&gt;&lt;br /&gt;Like I said, I started doing my framework in .NET 2.0, using TDD.  One of my classes that I'm particularly fond of is my CommandLine class, which encapsulates a command line and its arguments.  Now, it's true that .NET passes the command-line arguments in a string array, but this is crude.  My class is quote-aware, which means this command line:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;xyz.exe "Hello world"&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;will actually report one argument.  In addition, I look for named parameters and provide a handy accessor method, so that when passed the command line:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;xyz.exe /a:One /b:Two&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I can access it like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;CommandLine cl = new CommandLine("xyz.exe /a:One /b:Two");&lt;br /&gt;string paramA = cl.Named["a"];&lt;br /&gt;string paramB = cl.Named["b"];&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;TDD is perfect for this kind of developent.  Within a day I had about twenty tests, and I know that if I make changes to the class's implementation, I can run these tests in a split-second and see if I broke anything.&lt;br /&gt;&lt;br /&gt;I just have to get to the gaming engine now!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-115089520032498851?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/115089520032498851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=115089520032498851' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115089520032498851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/115089520032498851'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/06/summer-of-tdd.html' title='Summer of TDD'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-114907158539710541</id><published>2006-05-31T03:06:00.000-07:00</published><updated>2006-05-31T03:33:05.443-07:00</updated><title type='text'>Summertime programming... gotta love it!</title><content type='html'>There's something special about programming in the summer, at least for me.  Lounging by the pool with a good book, spending nights by the keyboard with the windows open and the warm summer breeze blowing.... you know how it is.&lt;br /&gt;&lt;br /&gt;Some of my favorite summers were those spent programming and learning.  In 1995, during my first programming job, I first learned how to program Windows.  During the summer of 2000, I spent countless hours creating the user interface for Toadnode, a Gnutella client.  In 2002 I first learned the .NET framework.&lt;br /&gt;&lt;br /&gt;The summer of 2006 is off to an awesome start.  The northeast had one of the nicest Memorial Day weekends in years.  I'm set to make this one of the best programming summers yet.&lt;br /&gt;&lt;br /&gt;Here's a list of what's needed:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;A technology to learn.&lt;/span&gt;  In my case, it will be .NET 2.0.  I'm stoked about rewriting the game engine to make use of generics.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;A project.&lt;/span&gt;  Easy -- the afore-mentioned gaming engine.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;A good book.&lt;/span&gt;  Check -- "CLR via C#" by Jeffrey Richter.  When you can't be programming, you can be reading in the sun.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Some good tunes.&lt;/span&gt;  This I have to decide upon, but I'm leaning towards Alanis Morissette's acoustic release of "Jagged Little Pill."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-114907158539710541?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/114907158539710541/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=114907158539710541' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/114907158539710541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/114907158539710541'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/05/summertime-programming-gotta-love-it.html' title='Summertime programming... gotta love it!'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-114726566297586554</id><published>2006-05-10T05:25:00.000-07:00</published><updated>2006-05-10T05:54:22.986-07:00</updated><title type='text'>The Game Engine and Why</title><content type='html'>This is what working at Merrill Lynch has done to me.... five months without a blog entry.  Shame.  Well, at least we have a new director in place, and thankfully, he is not your business-as-usual guy.  Very personable, as well.&lt;br /&gt;&lt;br /&gt;Ok, ok, the game engine.  Why?  So I can be a better poker player, naturally!  I believe that I can be a better poker player by writing a poker game, at least as far as getting a handle on odds and game mechanics and such.  Yes, I know that true poker is a people game, but there is still much to learn about it by writing you own version.&lt;br /&gt;&lt;br /&gt;I have never visited one of those online poker sites.  If I did, I would surely stop programming in my spare time altogether!  This is what happened before -- I had an idea for a really great game, but then I discovered Starcraft, which came pretty close to my vision of the "perfect" game.  I stopped programming for about two years!  (I still play Starcraft, on occasion...)&lt;br /&gt;&lt;br /&gt;Here's how my thinking went.  Many times, when reading a book that teaches a programming language, some of the examples will model real-life examples.  For example, a book might teach two-dimensional arrays using a chess program.  This works great with newer languages such as Java and C#:  Their rich support of classes makes it possible to model just about anything.  This is kind of the point -- well-written business class libraries model business rules, and leave storage and presentation details to other layers.  One should program against Account objects, not against pointers to numeric arrays.&lt;br /&gt;&lt;br /&gt;When learning C#, one of the first things I wrote was a poker-scoring algorithm, and it was fun to write.  I then thought, hey, I have the makings of a good business layer, why not expand it?  So I pondered the problems of an online poker game (presentation, keeping players cards secret, connecting players, keeping a permanent record of all games, etc).  I would also want it to play variants of poker (7-stud, Omaha, etc.) and I would also want it to be played locally on the PC as well.&lt;br /&gt;&lt;br /&gt;The thinking expanded.  Occasionally, a friend of mine (the same friend who gave me the "Q" in my name) hosts a board game day in his basement.  This is where I first played &lt;em&gt;Puerto Rico&lt;/em&gt; and &lt;em&gt;Age Of Steam&lt;/em&gt;.  I thought about how I would love to write computer versions of these games, and also thought about how these could possibly be played online or locally.&lt;br /&gt;&lt;br /&gt;I realized that all online games share fundamental problems:  How to connect players, how to log all game activity for auditing purposes, authentication and security, etc.  Some games also have the additional problem of player secrets;  games like chess and checkers have no secrets, but virtually all card games do (the cards in each players hand).  Then of course, each game has specific "business" rules, and each game also has different presentation rules (although games played with playing cards can share much of those presentation rules).&lt;br /&gt;&lt;br /&gt;Thus was born the game engine, and I'll get into the design in future entries.  As I mentioned, I started with one of the simplest of games -- Tic Tac Toe.  So far, it has proved a good "straw man" of a game and has given me a good test bed.&lt;br /&gt;&lt;br /&gt;More later...  right now, back to my PL/SQL training course!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-114726566297586554?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/114726566297586554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=114726566297586554' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/114726566297586554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/114726566297586554'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/05/game-engine-and-why.html' title='The Game Engine and Why'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-113824242836445172</id><published>2006-01-25T18:13:00.000-08:00</published><updated>2006-01-25T18:27:08.376-08:00</updated><title type='text'>My Pet Project</title><content type='html'>I'll go into details at another time, but my big pet project at the moment is a gaming engine.  Right now I'm testing it with Tic-Tac-Toe (how lame!), but a future milestone is to write a more complicated game, such as chess.  Problem is, I don't have the interest, inclination, time, etc., to write a chess engine.&lt;br /&gt;&lt;br /&gt;That's when I thought, "Gee, I wonder if anyone has exposed such an engine over a web serice?"  A quick Google search turned up &lt;a href="http://www.valil.com/chess2/index.html"&gt;www.valil.com&lt;/a&gt;.  The actual endpoint of the service is &lt;a href="http://www.valil.com/ChessWebService/Service.asmx"&gt;here&lt;/a&gt;.  The author, a guy by the name of Valentin Iliescu, wrote a .NET Compact Framework app that plays chess, using a web service as the back end.  Clever!  He even won a prize and wrote an article on it on &lt;a href="http://www.codeproject.com/csharp/chess.asp"&gt;CodeProject&lt;/a&gt;.  Sounds like fun!  This guy is pretty sharp and does a lot of Avalon work.  Can't wait to explore his &lt;a href="http://spaces.msn.com/members/viliescu/"&gt;blog&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-113824242836445172?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/113824242836445172/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=113824242836445172' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/113824242836445172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/113824242836445172'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/01/my-pet-project.html' title='My Pet Project'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-113693304772710573</id><published>2006-01-10T14:44:00.000-08:00</published><updated>2006-01-10T18:09:44.600-08:00</updated><title type='text'>I wonder if police detectives feel this way</title><content type='html'>&lt;p class="mobile-post"&gt;Every developer has been there:  Faced with a problem that occurs once in a while, with no apparent cause, armed only with a few sparse log files, the poor developer is asked to solve the problem.  It's like trying to solve a crime with precious few clues.&lt;/p&gt;&lt;p class="mobile-post"&gt;That's where I was today, and it is quite literally the hellish part of my job.  The sad part is that once solved, the developer usually gets no recognition, since, after all, it is his job.  The only consolation prize is a heck of a war story (and maybe some good material for the year-end performance review).&lt;/p&gt;&lt;p class="mobile-post"&gt;Perhaps a good night sleep can help me find the problem.  Go subconscience!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-113693304772710573?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/113693304772710573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=113693304772710573' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/113693304772710573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/113693304772710573'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/01/i-wonder-if-police-detectives-feel.html' title='I wonder if police detectives feel this way'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-113686036294369459</id><published>2006-01-09T18:10:00.000-08:00</published><updated>2006-01-09T18:37:43.526-08:00</updated><title type='text'>Container Pattern, or, So that's what I'm up to</title><content type='html'>Ok, almost a month goes by and nothing to show.&lt;br /&gt;&lt;br /&gt;Truth is, we are coming out of a monster of a release. I work for Merrill Lynch and am part of the Retirement Group, which means I work on their 401(k) website, &lt;a href="http://www.benefits.ml.com"&gt;Benefits OnLine&amp;reg;&lt;/a&gt;. If you happen to have your 401(k) plan record-kept by Merrill Lynch, and checked your 401(k) recently, then you know what I mean.&lt;br /&gt;&lt;br /&gt;But, ironically, that's not what I wanted to talk about. It's about a rather silly article I read in the "Design Patterns" column of the September 2005 issue of MSDN magazine (yes, I'm behind). The article can be found &lt;a href="http://msdn.microsoft.com/msdnmag/issues/05/09/DesignPatterns/default.aspx"&gt;here&lt;/a&gt;. Don't get me wrong; I'm a fan of patterns and glad to see Microsoft actually referencing them and using them. But this article spells out a rather mundane example of "Dependency Injection," which (at least to me) is just a fancy name for dynamically loading code. Snooze -- this sort of problem was solved with COM over ten years ago.&lt;br /&gt;&lt;br /&gt;But, there was one thing that interested me. The column was also a shameless plug for a product called Spring.NET, which is a framework that offers some services. Funny thing -- that's also what I am working on: a framework. No, I am not trying to rewrite .NET (and neither is Spring, for that matter), but I do find that, in my own work, I tend to solve certain problems the same way, and I basically wanted a package that allowed me to easily reuse my solutions. I also wanted a way to easily inject workarounds for those pesky .NET problems like memory leaks and what not.&lt;br /&gt;&lt;br /&gt;What was interesting? The article mentions that frameworks are an example of the &lt;strong&gt;Container&lt;/strong&gt; pattern. Containers can provide common services to the objects they house (the Microsoft-y example being the Transaction context provided by COM+). Which is exactly what I am after.&lt;br /&gt;&lt;br /&gt;So that's what I've really been up to... implementing the Container pattern.  Like I said, I like using patterns.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-113686036294369459?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/113686036294369459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=113686036294369459' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/113686036294369459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/113686036294369459'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2006/01/container-pattern-or-so-thats-what-im.html' title='Container Pattern, or, So that&apos;s what I&apos;m up to'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20019204.post-113504643023461571</id><published>2005-12-19T18:31:00.000-08:00</published><updated>2005-12-19T18:40:30.243-08:00</updated><title type='text'>Me?  A blog?</title><content type='html'>Well why on &lt;em&gt;earth&lt;/em&gt; would I have a blog?&lt;br /&gt;&lt;br /&gt;It's a recent decision, really.  See, I'm a developer, and I was passed a link from a fellow developer.  This link took me to another developer's blog, where he talked about some discoveries about static constructors in C#.  I won't repost the link, because the entry itself was useless, but then, it finally occured to me.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Blogs are today's research journals!&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Well &lt;strong&gt;duh!&lt;/strong&gt;  But it took me awhile to make that connection.  And as I thought back over my ten-plus years as a developer, and all the systems I have worked on, I realized that I have collected a tiny bit of knowledge -- the kind of knowledge that can't be learned in a book, nor even a forum, but rather, the kind of knowledge that only experience can bring.  The kind that comes from watching other skilled developers ply their trade.  The kind that comes from all-night releases of web applications.  The kind that comes from talking with the systems folks, listening to them ping and pinch and test connections.&lt;br /&gt;&lt;br /&gt;So stay awhile!  I hope you get to know me a bit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20019204-113504643023461571?l=jamesqmurphy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jamesqmurphy.blogspot.com/feeds/113504643023461571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20019204&amp;postID=113504643023461571' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/113504643023461571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20019204/posts/default/113504643023461571'/><link rel='alternate' type='text/html' href='http://jamesqmurphy.blogspot.com/2005/12/me-blog.html' title='Me?  A blog?'/><author><name>JamesQMurphy</name><uri>http://www.blogger.com/profile/17137126790512604899</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
