New Website

by John 14. March 2017 12:04

If you happened to stuble across this blog, please be aware that I no longer update this site.  If you wish to learn more about me, please visit the main site, http://johnpirkey.net/

Tags:

General

A Simple Task? Generate Schedules

by John 17. March 2014 02:48

I was recently asked (or rather I volunteered) to build a website for a local sports league which included the ability to generate a schedule of matches, among the list of other to-be-expected functions (such as member management, player rankings, session results, etc).

I knew the scheduling aspect was going to be the most difficult; ensuring that all players play every other member just once and that no member was scheduled to play twice on a given night.  I fired up VS and started writing code.  I knew it was going to involve at least one nested loop that iterated the list of players, found an opponent and added them to the list of matches for that week - but it also had to check all other weeks to ensure these 2 players didn't play each other at some other time.  As the schedule grew in size the performance of the code disintegrated exponentially.  It worked wonderfully for my test data of 8 players, running in a second or 2, but when I put in the list of all the players (17) it grinded to a halt - running over a hundred-throusand iterations of all possible combinations.  I should note that my initial attempt included a random selection of 2 players.  Obviously, this was not going to work for a production website.

I did some research on scheduling and found some wiki articles on the set theory used to most often generate simple sports schedules.  With this new info in mind (and a few other tips picked up from the web) I came up with a solution that runs beautifully.  For 17 players, all playing a match per week, for 17 weeks, it generates a unique schedule in less than half a second.

It bugs me that I had to resort to searching for tips as the final solution appeared to be quite close to one of my iteration-attempts.  I simply ran out of time to get it working before the season was scheduled to begin.  I suppose one evening of coding/testing isn't always enough for "small" projects, heh.

The trick is to handle the first player/team individually for all of their matches, which effectively prevents that player from being in the pool for all the other generation.  Pair the 1st player with each iteration of the pool, then split the remaining list in half and walk through them.  Again, this is set operations (or modular systems or residue systems, depending on your particular brand of math/algebra schooling), so everything had to be mod-the-number-of-{something}.

What my own implementation was missing the special case handling of the first player and the rather ingenius splitting of the field as a starting point for the opponent's index search. Initially I was simply grabbing the next player in line, then grabbing the 3rd one after that (wrapping indexes, of course); checking logic and going forward.  It was something of a "brute force" method, to be sure, but it was quick to code and time is always a factor.  But because the number of players wasn't (or not guaranteed to be) prime, it meants that the value 2 could be found by more than one jump around the list; generating duplicates.  (A [odd] prime-based mod system means that every element in the set can generate every other element; whereas a non-prime system does not.)

My next attempt was to use LINQ to basically cross-join two arrays (as if you were building matrices) and while that did generate the pairings uniquely, assigning the rounds for each match was a bit more complex than I had anticipated; requiring a lot of logic checks and loops.  I didn't like that direction because surely there's a more elegant solution to this common task. So that's when I went to Google/Wikipedia. 

Anyway, I'm including the final code here so anyone else can find/use it:

public void GenerateSchedule()
{
     int numTeams = players.Count;
     int totalRounds = (numTeams - 1);
     int halfSize = numTeams / 2;
     List<Match> matches = new List<Match>();
     List<Player> teams = players.ToList();

     teams.RemoveAt(0);

     int teamsSize = teams.Count;

     for (int round = 0; round < totalRounds; round++)
     {
          int teamIdx = round % teamsSize;

          Match m = new Match();
          m.Round = round + 1;
          m.Player1ID = teams[teamIdx].PlayerID;
          m.Player2ID = players[0].PlayerID;
          matches.Add(m);

          for (int idx = 1; idx < halfSize; idx++)
          {
               int firstTeam = (round + idx) % teamsSize;
               int secondTeam = (round + teamsSize - idx) % teamsSize;
               //Console.WriteLine("{0} vs {1}", teams[firstTeam], teams[secondTeam]);
               m = new Match();
               m.Round = round + 1;
               m.Player1ID = teams[firstTeam].PlayerID;
               m.Player2ID = teams[secondTeam].PlayerID;
               matches.Add(m);
          }
      }

      GridView2.DataSource = matches.OrderBy(o => o.Round);
      GridView2.DataBind();
      lblCount.Text = matches.Count + " total matches.";
}

Tags: , ,

Programming | C#

T-SQL Utility

by John 5. December 2011 06:18

Here's a handly little routine that will generate INSERT statements from the data in a supplied table.  I wrote this a long time ago and don't often need to use it these days, but when security restricts me from doing any sort of actual table export/import between servers yet that's what I need to do, this is extremely useful.

 

DECLARE @ColName varchar (100) 
DECLARE @colType varchar (100) 
DECLARE @Output varchar (8000)
DECLARE @TableName varchar(50)

SELECT @TableName = '{table_name_here}'

SELECT @ColName = '', @ColType = '', @Output = ''

DECLARE rs CURSOR FOR
	SELECT c.Name,	t.Name
	FROM
		sysobjects o 
		JOIN syscolumns c ON o.ID = c.ID 
		JOIN systypes t	ON c.xType = t.xType
	WHERE
		o.Name = @TableName 
	
OPEN rs 

FETCH NEXT FROM	rs INTO @ColName,@ColType 

--build the field listing...
IF  @@Fetch_Status = 0
SET	@outPut = 'SELECT ''INSERT INTO ' + @TableName + ' (' 

WHILE @@Fetch_Status = 0
BEGIN
SELECT @output = @output + char ( 10 ) + '	' + @colname + ', ' 
	
FETCH NEXT FROM	rs INTO @ColName, @ColType
END
CLOSE rs 

--remove the trailing ', '
SELECT @output = Left(@output, Len(@output) - 1) 

--now build the values list
OPEN rs 
FETCH NEXT FROM rs INTO @ColName, @ColType 

--build the field listing...

IF @@Fetch_Status = 0
SET	@outPut = @output + char(10) + ') VALUES (' 

WHILE @@Fetch_Status = 0
BEGIN
SELECT @output = @output + char ( 10 ) + '	' + 
	CASE
		WHEN  @ColType IN ( 'varchar' , 'char' , 'smalldatetime' , 'timestamp' , 'datetime' , 'nvarchar' , 'nchar' ) 
			THEN ''''''' + replace(ISNULL(' + @ColName + ',''''),'''','''''''') + '''''
		ELSE ''' + convert(varchar,ISNULL(' + @ColName + ',0)) + '
	END

SELECT @output = @output + ''', '
FETCH NEXT FROM rs INTO @ColName, @ColType
END

CLOSE rs 
DEALLOCATE rs 

--remove the trailing  ', '
SELECT @output = Left( @output,Len( @output) - 2)

SELECT @output = @output + ''')''' 
--now we've completed the complicated SELECT clause, just close up the FROM

SELECT @output = @output + Char(10) + 'FROM ' + @TableName

--SELECT @output 
EXEC(@output)

 

Tags: , , , ,

SQL Server

What's The Point

by John 16. February 2011 04:45

Someone recently asked me what the point of this blog is.  That's a fair question.  There are hundreds of other tech blogs - most far more technical than this one.  The reason I started this is because every once in a while, I run across something that just strikes my fancy in such a way that I would love to share it.  It could be something I did which I consider to be excellent, it could be something "Dilbert-ish", or it could be something I read that I find share-worthy.

When I post little code snippets, they're one of two things: awesome or entertaining.  Like that little blurb of HTML in the last post.  I mean seriously, p - b - br - /b /p  no text, no labels, no placeholder, no names, no... anything.  That's just hilarious to me.  Maybe I'm too sarcastic to be a programmer? 

Every programmer who has ever been around the block has run into situations where they find themself in a situation which could drive you crazy.  If you don't find a way to deal with it, you will lose it and bad things happen. This blog is an outlet of sorts for me.  

Recently I've been talking about working with some older code.  I don't have a problem with that, but I'd be lying through my teeth if I didn't look at this stuff and remember all the times I spent writing this exact same type of stuff.  Because I've written thousands of lines of the same code, I feel justified is pointing it out in a mocking manner - because I'd be laughing at my own code if I ran across that too. Think about it: How many hours (over the years) have web developers wasted going back through their HTML source to capitalize their tags because that was the standard?  An awful lot.  Now, lowercase is the standard, so when VSIDE starts complaining about XHTML 4.0 compliancy, I just have to laugh.

I laugh because I find it entertaining just how little we programmers stick to our guns.  I'm quite sure that when CAPITALIZATION was the standard, those standard-mongers would go to war over a lowercase anchor tag.  When M$ said "oops, that looks terrible... um... the new standard is lowercase." those same people were the first to write RegEx scripts to parse through all that html and replace A with a.  If the next standard is UpAnDdOwN, I'm sure we'll have hundreds of RegEx's that do just that as well.

As much as I'd love to just do what I know, do what I did best, I can't. No full-time programmer can.  If we did, we'd be out of a job.  We have to evolve, adapt and overcome our own standards to adhere to what the marketplace wants.  I, personally, despise the idea of ending all lines with a semicolon. I hated it in Turbo Pascal, and I hate it in C# - but the difference is, now I get paid to put those semicolons in; and that makes all the difference.  I would prefer not to, but what I want and what the market wants don't always align.  I understand that - and I think any programmer that's been around longer than a few years understands that.  Especially as consultants, we are (or should be) the code-generating equivalent of Mystique.  We conform to whereever we are and however it's done there.  It doesn't mean we aren't still people with our own brand of humor, sarcasm, faith or lifestyle; it just means that the longer we're in this business, the more we become that old man in the bar who's been everywhere, behind the scenes, seen the show and saw the strings.  We should be happy to be that person because that means we've had a nice long run - and hopefully still running.

Tags: , ,

General

You Know You're Working With Old Code When...

by John 14. February 2011 11:10

Visual Studio IDE highlights e.v.e.r.y.t.h.i.n.g. in the source code when you open it up.

hahaha

Also, what's this do:

<p><B><br>
    </b></p>

*snicker*

 

Tags:

General

The Geek Is Strong With This One

by John 9. February 2011 10:07

This is more entertaining than anything else.  Over this past weekend, I slept in late, woke up, got coffee went to check my email and before my 2nd cup of coffee I was formatting the hard drive on my old desktop and installing Win2k3 server.  At the end of the day, I had a new Active Directory server also running IIS 6 with multiple websites.  I guess it's also a file server of sorts, since I have no use for the other 80gb drive in that box.  heh  It's important to note that my plan for the day was laundry and video games; neither of which require building a new domain controller.

Tags: , ,

General

How Not To Keep A .Net Developer Amused

by John 4. February 2011 10:01

I'm no spring chicken, but I'm no dinosaur either.  However, I have been around long enough to remember when using HTML templates and populating them in some server-side compiled DLL was all the rage in high-powered web development; a precursor even to VB6's WebClasses.  Do any of you remember the ridiculous hype those WebClasses received - particularly at VBITS 1998 (maybe it was 99, I'd have to check my tote bag to be sure)?  Well, anyway, it was super-duper showcased.  All the power of VB6 in a dll, but still running on a webserver, serving up html pages like pancakes at an IHOP.

 

Now, do you remember actually doing any real development with those webclasses? I bet most of you tried it, realized the one major flaw, and quickly abandoned the technology.  If you wanted to make so much as a single character edit to the HTML page, you had to recompile the DLL, stop/start the MTS package hosting the DLL and most likely stop/start the IIS website as well.  Not exactly the most developer friendly deployment scheme.

 

Now... imagine that same situation, but instead your code engine is Power Builder.  Add to that, an enormous amount of Javascript, some of it custom, the rest as part of old js-based menu system (Joust - remember?).  For that extra little topper, toss in multiple framesets.  Ooh, that's right. I said it. I said frames.  HOW COOL where frames when we got HTML 3.2?!? Oh man, they were the best thing ever.  How many corporate websites ran on frames? Just about all of them.

 

The point to all of this reminiscing is that some places have not realized the sins of the past and still, to this very day, run setups exactly as described above.  I know this because my newest client site is one of those places.  Yes. A major entity in the area is powered by classic asp, powerbuilder, javascript and frames (not even iFrames, real life frames. You remember:

 

<frameset cols="100%" rows="72,*">
	<frame name="title"   src="/webap_buildTitlePage.htm"  scrolling='no'   marginwidth='0' marginheight='0' APPLICATION='yes' noresize>
	<frame name="menu"    src="/webap_plan_menu.htm"  scrolling='auto' marginwidth='0' marginheight='0' APPLICATION='yes'>
</frameset>

 

Yep. It must be one of the dirtiest secrets in all of this city's IT departments.

 

Now, for the title of this post... I was recently handed, literally, hand-delivered 40 (FORTY) printed pages of Power Builder code and told to use this a guide to replace one function of a classic web app with a new .net page.

 

I understand the department doesn't have the resources or time for a full site redesign, development, etc... but this is not the first time we've tried this "lets replace this one function with .net and stay on the migration path" idea.  I'm reminded of the adage: "The road to hell is paved with good intentions." Yes, it's good to start thinking about moving away from PB/JS solutions, but trying to do it in this patchwork style only leads to bad things.

 

Oh, and lastly, when you deliver this stack of wasted paper and explain how you were the lead architect for the system 12 years ago and still brag on its flexibility and power, maybe you should realize that you've hired a "new age tech guy" to replace all of that stuff and this isn't your hayday anymore.  

 

It's a cold, harsh truth that, especially in IT, the *moment* you think you're finally ahead of the curve, you realize you've just been lapped.  I'm still fighting to stay in the race and as proud as I am about some of my past victories, I certainly would not expect any one of them to still be around today. 

Tags: , , , , , ,

Programming | .Net

About Me

I'm a .Net developer in St. Louis, MO working for Trizetto Provider Solutions. 

Professional Info

Tag cloud