I bet you guessed that there was a software aspect to my last post on the Great Apple Experiment. You were right.
First, there's the fairly easy job of randomly assigning numbered jars to Scouts and marking them for their purpose: Love, Hate, etc. This was a fairly straightforward job of maintaining a collection of jars and a collection of spots (22 Scouts x 6 jars per Scout = 132 spots). Then I just use a pseudo-random number generator to pick a random jar and assign it to a random spot until all the jars are gone.
The harder part is collecting the results from the experiment. My goal is to have all 22 Scouts rank all 132 apple slices and to crunch the numbers before the end of the meeting. Entering the 2904 numbers by hand will be a serious challenge within the one-hour limit I have. So, I decided to speed up the process. I can bring a scanner to the meeting and scan the score cards to produce black and white bitmap images. The only problem now is capturing the results from the bitmaps.
OCR technology would be rather hard to use - especially when the Scouts will be writing the results by hand with pencils. I decided to go with a "fill in the dots" approach. Now the problem is that the scanner isn't perfect and the page can be rotated by several degrees. I can't just look at an x/y point on the page and expect the circle to be there.
Here's a scanned score card:
And here's a magnified version of the top left part of the card with red marks added by my software:
The circles are arranged in 4 columns of 33 rows of circles. At the top of the page, I include a circle at the top left and top right of the page for registration marks.
I was able to locate the registration marks and find their centers. Based on this information, I knew the orientation of the page compared to a carefully-scanned sample. I was able compute the centers of the circles on the sample sheet and stored that information in the program. Then, with the scanned image, I take each point (the centers of the circles shown as red dots in the image above), transform them according to the registration marks, draw a 21x21 square around them (shown as red squares), and capture the bits (1 or 0) in each square. Any square that had more than 200 black bits (0's) was counted as ON.
This actually worked (wow) and I was able to get reliable results. The result is an array of 132 numbers from 1 to 9 or 0 if no circle was filled in. This is exactly the information I need to run the stats.
You'll notice that I print a series of bars at the top of the page. My thought was that I'd scan the Scout's number by scanning it and collecting which bars were long and which were short. I'd always start and end with a long bar then within the code, short bars are 0 and long are 1 making a binary number representing the Scout's number. I decided in the end not to use it because it doesn't take long for me to manually enter the Scout number and it allows me to print generic score cards instead of ones specific to each Scout. I expect that some of the Scouts will mess up the score cards and will need to re-do them. It's a whole lot easier if I can just give them a generic sheet.
Part 2 of the experiment is on Tuesday. I'll let you know how it goes.
Sunday, January 30, 2011
Saturday, January 22, 2011
The Great Apple Experiment
My son's Scout troop has taken me up on my offer to help them get their science badges. To do this, we're going to run the Great Apple Experiment with the whole troop. Basically, Nikki Owen made a claim that cutting an apple in half and talking nicely to one half and meanly to the other half makes the nice one rot more slowly than the bad one. Rebecca Watson ran an experiment on this claim and invited everyone to write their results on a Facebook page.
We have 22 Scouts in the troop and I'm going to get them all to run the apple experiment. We'll start by discussing bias, blinding and controls. We'll then cut up the apples, place them into marked containers, and have the scouts talk to them every day until the following week's meeting. We'll then have all the Scouts assess all of the apple slices and collect the results.
I don't have much time to develop and get feedback on the protocol for the experiment, so I thought I'd post it here and get feedback.
Protocol (thanks to PZ Myers for his suggestions):
If you have any comments or suggestions on this protocol, please e-mail me at david@simberon.com or post them as comments to this post.
Thanks
We have 22 Scouts in the troop and I'm going to get them all to run the apple experiment. We'll start by discussing bias, blinding and controls. We'll then cut up the apples, place them into marked containers, and have the scouts talk to them every day until the following week's meeting. We'll then have all the Scouts assess all of the apple slices and collect the results.
I don't have much time to develop and get feedback on the protocol for the experiment, so I thought I'd post it here and get feedback.
Protocol (thanks to PZ Myers for his suggestions):
- Discard any apples that are obviously bruised or nicked
- Wash the apples and slicer before beginning
- Slice apples into 8 pieces (Rebecca suggests 2 pieces but I don't have a budget for that many apples considering the other things I want to do)
- Apple slices are placed into clear containers which are marked by unique numbers
- Each Scout gets 6 apple slices (Love, Hate, Neutral, Untouched Control, Known Preservative, Open Air) chosen at random from the available containers
- For Known Preservative, we'll coat the apple slices with lemon juice
- For Open Air the slice will be kept in a container with no lid. We will use paper towel on top held on by an elastic band to prevent any insects from entering.
- Each container will have a window into which we'll slide a label saying "Love", "Hate" etc. This is to help prevent mistakes while the Scouts have the apples home during the week.
- The container numbers are recorded indicating which number goes to which Scout and what the label on that container reads (Love, Hate, etc).
- Each container will be sealed with a lid that won't be removed for the remainder of the experiment
- The Scouts take the containers home.
- Each day, they will take the Love container to another room, say nice things to it and return it.
- They then take the Hate container to another room, say bad things to it and return it
- They then take the Neutral container to another room, say neutral things to it and return it.
- All other containers remain untouched for the week
- At the end of the week, the Scouts will bring the containers to the meeting
- Each Scout will rate his own 6 slices (knowing which is which) on a scale from 0 (not rotted at all) to 10 (very rotten). We'll provide photos of each level for reference.
- Each Scout will then remove the labels Love, Hate etc. leaving only the numbers on the containers and place them in a line on a table
- A Scout leader will re-arrange all containers randomly
- Each Scout will rank each apple (skipping their own which they've already ranked)
- Scouts cannot show their rankings to other Scouts or discuss the experiment with other Scouts until the experiment is complete.
- Each slice will be grouped by category - Love, Hate, Neutral, etc excluding the Scout's assessment of his/her own slices.
- In each category, the ratings will be averaged and standard deviation calculated
- Each Scout's assessment of his or her own slices will be compared to the averages to determine if the Scouts exhibited bias in assessing their own slices without blinding
- All results will be published on the Internet with photos and videos
If you have any comments or suggestions on this protocol, please e-mail me at david@simberon.com or post them as comments to this post.
Thanks
Thursday, January 20, 2011
OCSTUG meeting Jan 27, 2011
Building Courses in Smalltalk
David Buck
Building a course that supports several programming languages can be tough. Using conventional tools like PowerPoint requires you to maintain multiple copies of each file even though most slides in the file are identical between the courses. In this presentation, David will show the toolset he built to allow him to develop multi-language courses while keeping the content centralized in one copy of the files.
Location: The Code Factory
246 Queen Street, Ottawa
Thursday, January 27th, 2011 at 6:00pm
There will be a $5 charge to pay for the room.
David Buck
Building a course that supports several programming languages can be tough. Using conventional tools like PowerPoint requires you to maintain multiple copies of each file even though most slides in the file are identical between the courses. In this presentation, David will show the toolset he built to allow him to develop multi-language courses while keeping the content centralized in one copy of the files.
Location: The Code Factory
246 Queen Street, Ottawa
Thursday, January 27th, 2011 at 6:00pm
There will be a $5 charge to pay for the room.
Tuesday, January 18, 2011
Multiple Return Values in Smalltalk
In the comments of my "Two-Sided Commit" post, I referred to a technique I heard about from my friend Anthony Lander. I thought I'd write that up explicitly.
Sometimes, you'd really like a method to return multiple values. Suppose, for example, we have a Color object that stores its value as integers for Red, Green and Blue. We may want to compute the Hue, Saturation and Value of the color. If we had individual methods for hue, saturation and value, we'd have to perform the calculation three times. Alternatively, we could write a method for the object called asHSV which returns the hue, saturation and value in an Array. Arrays, though, are messy to deal with because the values are indexed by an integer - you can't use the names hue, saturation, and value. We could also create an object for an HSV representation of the color but that introduces a lot of complexity. The HSV color should work interchangeably with an RGB color and that amount of work may not be justified.
Rather than have multiple return values (or returning an array of values), we can use a three-parameter block and name the parameters:
aColor asHSVDo: [:hue :saturation :value | ... ]
Now, the asHSVDo: method can perform the conversion once and run the block with the calculated values. We get to use nice names for the variables and we don't create extra objects we don't need.
Sometimes, this turns out to be a nice alternative when you think you need multiple return values.
Sometimes, you'd really like a method to return multiple values. Suppose, for example, we have a Color object that stores its value as integers for Red, Green and Blue. We may want to compute the Hue, Saturation and Value of the color. If we had individual methods for hue, saturation and value, we'd have to perform the calculation three times. Alternatively, we could write a method for the object called asHSV which returns the hue, saturation and value in an Array. Arrays, though, are messy to deal with because the values are indexed by an integer - you can't use the names hue, saturation, and value. We could also create an object for an HSV representation of the color but that introduces a lot of complexity. The HSV color should work interchangeably with an RGB color and that amount of work may not be justified.
Rather than have multiple return values (or returning an array of values), we can use a three-parameter block and name the parameters:
aColor asHSVDo: [:hue :saturation :value | ... ]
Now, the asHSVDo: method can perform the conversion once and run the block with the calculated values. We get to use nice names for the variables and we don't create extra objects we don't need.
Sometimes, this turns out to be a nice alternative when you think you need multiple return values.
Friday, January 14, 2011
Two-sided commit
I've encountered an interesting problem for which I've come up with an interesting solution.
My application needs to read records from several input queues and write thode records into a database. The input queues aren't in the database and have their own commit and abort abilities. The problem is that to avoid losing records, I have to coordinate the commits. I need to:
I'd like to isolate knowledge of multiple queues from the caller who writes to the database:
[message := queueManager getMessage.
message notNil] whileTrue: [
self beginTransaction.
self writeMessageIntoDatabase: message.
self commitTransaction
ifTrue: [???? commit]
ifFalse: [???? abort]]
The problem is that I don't know which queue I took the message from - the queue manager isolates me from that knowledge. But I need that knowledge so I can commit or abort the proper queue later.
What are my options? I could have getMessage return both a message and a queue. Then I'd know which queue to commit. It kind of breaks my encapsulation, though. I still need my method to know about the existence of multiple queues and how to commit or abort them.
I could have the queueManager keep track of which queue it pulled the message from so I could tell the queueManager to commit or abort and it would then tell the appropriate queue to commit or abort. This seems really messy, though.
My solution is to do this:
queueManager withAllMessagesDo: [:message |
self beginTransaction.
self writeMessageIntoDatabase: message.
self commitTransaction]
The queueManager delegates the message as-is to each of the queues. Each queue can then extract a message and run the block on it. If it returns true, the queue commits and if it returns false, the queue aborts.
The nice thing about this solution is that all the knowledge of multiple queues and even knowledge of how to commit or abort the queues is encapsulated into the queues and doesn't affect the high level code that needs to write to the database.
My application needs to read records from several input queues and write thode records into a database. The input queues aren't in the database and have their own commit and abort abilities. The problem is that to avoid losing records, I have to coordinate the commits. I need to:
- Read a record from one of the queues
- Write the object into the database
- Commit the database write
- Commit the read from the queue
I'd like to isolate knowledge of multiple queues from the caller who writes to the database:
[message := queueManager getMessage.
message notNil] whileTrue: [
self beginTransaction.
self writeMessageIntoDatabase: message.
self commitTransaction
ifTrue: [???? commit]
ifFalse: [???? abort]]
The problem is that I don't know which queue I took the message from - the queue manager isolates me from that knowledge. But I need that knowledge so I can commit or abort the proper queue later.
What are my options? I could have getMessage return both a message and a queue. Then I'd know which queue to commit. It kind of breaks my encapsulation, though. I still need my method to know about the existence of multiple queues and how to commit or abort them.
I could have the queueManager keep track of which queue it pulled the message from so I could tell the queueManager to commit or abort and it would then tell the appropriate queue to commit or abort. This seems really messy, though.
My solution is to do this:
queueManager withAllMessagesDo: [:message |
self beginTransaction.
self writeMessageIntoDatabase: message.
self commitTransaction]
The queueManager delegates the message as-is to each of the queues. Each queue can then extract a message and run the block on it. If it returns true, the queue commits and if it returns false, the queue aborts.
The nice thing about this solution is that all the knowledge of multiple queues and even knowledge of how to commit or abort the queues is encapsulated into the queues and doesn't affect the high level code that needs to write to the database.
Google Maps Fail
My wife and my son are taking a CPR course tomorrow. To find the location, I consulted Google Maps and got the following street view for the location of the course.
Ok, honey. I'll drop you off on the side of the freeway. Have a nice day.
Ok, honey. I'll drop you off on the side of the freeway. Have a nice day.
Thursday, January 13, 2011
Challenge: Scramble Squares
A few years ago, I was sitting in the waiting room of my dentist's office waiting for my kids to finish their appointments. On the table was a small wooden puzzle containing nine square pieces. Each piece had half a picture along each edge. The puzzle was to arrange the pieces into the 3x3 grid so that each edge matched on either side. The head on one side of the edge matched the tail on the other side and the colors were the same.
Here's a simplified picture of a scrambled puzzle with all the pieces.
When it's solved, the colors all line up and each arrow head is connected to an arrow tail. In the picture above only two edges match up - the blue arrow in the first row and the red arrow in the last column.
I tried solving it but found it amazingly difficult. The receptionist looked over and said "Nobody's ever solved that." I took that as a challenge. I went home and wrote a program in Smalltalk to solve the puzzle. I went back with my solution and amazed them by instantly putting all the pieces in the right places with the right orientations.
So, I challenge you. Can you solve this puzzle? Please don't put solutions into the comments - e-mail them to me at david@simberon and I'll announce the winner who solved the puzzle first. Feel free to write the program in any language. Next week, I'll post the Smalltalk source for my solution.
Have fun!
Here's a simplified picture of a scrambled puzzle with all the pieces.
When it's solved, the colors all line up and each arrow head is connected to an arrow tail. In the picture above only two edges match up - the blue arrow in the first row and the red arrow in the last column.
I tried solving it but found it amazingly difficult. The receptionist looked over and said "Nobody's ever solved that." I took that as a challenge. I went home and wrote a program in Smalltalk to solve the puzzle. I went back with my solution and amazed them by instantly putting all the pieces in the right places with the right orientations.
So, I challenge you. Can you solve this puzzle? Please don't put solutions into the comments - e-mail them to me at david@simberon and I'll announce the winner who solved the puzzle first. Feel free to write the program in any language. Next week, I'll post the Smalltalk source for my solution.
Have fun!
Tuesday, January 11, 2011
Refactoring (Smalltalk) Web Course
Simberon will be holding the course Refactoring Object Oriented Design as a webcast course during the week of March 7th, 2011. For details and to register, go to the Simberon web site.
The Fun of Software Development
I first started writing computer programs back in 1978 on my home-built computer. Back then, software development was fun and I wrote lots of creative little programs just because it pleased me.
In the professional software development world, it's easy to get caught up in requirements gathering or maintenance activities and forget that software development should be fun.
In this blog, I hope to re-kindle that creative and fun spark by proposing projects you can work on to improve your software development skills and to enjoy it at the same time.
If you have any suggestions for fun projects, let me know and I'll try to incorporate your ideas.
Have fun!
In the professional software development world, it's easy to get caught up in requirements gathering or maintenance activities and forget that software development should be fun.
In this blog, I hope to re-kindle that creative and fun spark by proposing projects you can work on to improve your software development skills and to enjoy it at the same time.
If you have any suggestions for fun projects, let me know and I'll try to incorporate your ideas.
Have fun!
Monday, January 10, 2011
Welcome to my Blog
My name is David Buck and I've been a software developer for 32 years now. My programming language of choice these days is Smalltalk but I'm interested in object oriented development, agile development, and software development practices. I host the Simberon Design Minute and I'm a co-host of the Independent Misinterpretations podcast.
You may know me as the DKB from DKBTrace - the ray tracing program that kicked off POVRay.
In this blog, I hope to provide food for thought for software developers and suggestions for helping developers improve the quality of their code. I also enjoy teaching about software development and encouraging people to have fun with software development. In addition to ray tracing graphics software, I've worked with simulated physics in ElastoLab, artificial intelligence with neural networks, 3D VRML worlds (see Pool World and Beach World) and computer music.
I welcome you to join me in an exploration of the world of software development.
I welcome your comments and your suggestions.
You may know me as the DKB from DKBTrace - the ray tracing program that kicked off POVRay.
In this blog, I hope to provide food for thought for software developers and suggestions for helping developers improve the quality of their code. I also enjoy teaching about software development and encouraging people to have fun with software development. In addition to ray tracing graphics software, I've worked with simulated physics in ElastoLab, artificial intelligence with neural networks, 3D VRML worlds (see Pool World and Beach World) and computer music.
I welcome you to join me in an exploration of the world of software development.
I welcome your comments and your suggestions.