<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Object Mentor Blog: PySweeper: Digging In</title>
    <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    <item>
      <title>PySweeper: Digging In</title>
      <description>&lt;p&gt;In the last installment I got the source and started up the
  development environment.Now I start to play with the tools.&lt;/p&gt;

  &lt;p&gt;I start to peruse the source. Python programs are written a
  mix of paradigms, and this is something I love about it. Every
  variable is a first-class object, but not all methods have to be
  members of a class. You can have global functions (well,
  module-scoped) which are themselves first-class objects capable
  of having multiple methods and member variables, all
  participating in reflection/introspection. As such, some will
  describe the use of non-class-bound methods as &amp;#8220;procedural&amp;#8221;, and
  I suppose it&amp;#8217;s technically a fair cop. Some of the program is
  written in class-free functions, mostly the bits that are used to
  initialize the application.&lt;/p&gt;

  &lt;p&gt;Python also has a number of functional programming features,
  but I suspect that the 2002 copyright predates list
  comprehensions and generators, so I don&amp;#8217;t see them represented
  here. I will be using some of those techniques to simplify code
  that had to be written in loops and nested loops before. It
  should shorten a number of methods.&lt;/p&gt;

  &lt;p&gt;The PyGame UI and business logic (guts) of the code are
  separate modules with a protocol for communicating between the
  two. I was afraid that I would find them all intermingled, and
  was delighted to see separate modules. The core of the game
  itself is only a few hundred lines of code if I include comments,
  docstrings, and whitespace.&lt;/p&gt;

  &lt;p&gt;I know that the first order of business is to get some testing
  started, but I want so badly to to take Eclipse PyDev for a spin
  that I&amp;#8217;m having an impulse control problem. I think the code is
  formatted reasonably, but I use the Eclipse feature to reformat
  the code to see if it works. I&amp;#8217;m rewarded with equally attractive
  code. No damage is done!&lt;/p&gt;

  &lt;p&gt;The outlining feature works fine, and so does completion. I
  scribble a little and delete it. It&amp;#8217;s looking good so far. I
  notice that the &lt;code&gt;Run As..&lt;/code&gt; menu has options to run
  Python, Jython, PyUnit, Python coverage and more. It&amp;#8217;s looking
  good.&lt;/p&gt;

  &lt;p&gt;What of refactoring? Sure enough I find that I can rename,
  extract and inline variables, and extract and inline functions.
  Those are the biggies. I scroll into the constructor of the
  &lt;code&gt;Field&lt;/code&gt; class. The &lt;code&gt;Field&lt;/code&gt; represents the
  playing field of the game, the grid of bombs and clues. In the
  constructor are various paragraphs of code that help set up the
  class. I pick the section that adds mines, move some of the
  constants out of the way by extracting local variables, and then
  extract that portion of the function as
  &lt;code&gt;_place_mines&lt;/code&gt;. In Python no functions are private, so
  the standard protocol is to use an underscore prefix as a &amp;#8216;wart&amp;#8217;
  to tell other authors that it&amp;#8217;s not really part of the formal
  interface, just a convenience function for the class. Love it or
  hate it, that is just how it&amp;#8217;s done.&lt;/p&gt;

  &lt;p&gt;I do the same with the paragraph that validates the parameters
  (ie there are more than zero rows, columns, and mines, and that
  there are not more mines than cells in the grid). This becomes
  &lt;code&gt;_validate_parameters&lt;/code&gt;, and is called from the
  constructor (in Pythonese the constructor is a function named
  &lt;code&gt;__init__&lt;/code&gt;).&lt;/p&gt;

  &lt;p&gt;I find eight instance variables in &lt;code&gt;__init__&lt;/code&gt;.
  That&amp;#8217;s quite a few. I pledge to look for violations of the Single
  Responsibility Principle later.&lt;/p&gt;

  &lt;p&gt;It dawns on me that Eclipse doesn&amp;#8217;t know my current version
  control selection, &amp;lt;a href=
  &amp;#8220;http://en.wikipedia.org/wiki/Bazaar_(vcs)&amp;#8221;&amp;gt;bazaar.&lt;/a&gt; This
  distresses me, because all the Team features of Eclipse are lost
  to me. I won&amp;#8217;t be able to do all my checkin/update/diff functions
  from within the &lt;span class="caps"&gt;IDE&lt;/span&gt;. I vow to look for a plugin soonest. That&amp;#8217;s
  two promises, two items of debt so far. I will keep going
  today.&lt;/p&gt;

  &lt;p&gt;For now, I see a function called &lt;code&gt;_get_adjacent&lt;/code&gt;.
  It has a pretty simple function, but it looks like this:&lt;/p&gt;
  &lt;pre&gt;

    def _get_adjacent(self, x, y):
        """Provide a list of all tiles adjacent to the given tile.

        This function takes the x and y coordinates of a tile, and returns a
        list of a 2-tuples containing the coordinates of all adjacent tiles.

        x and y are the x and y coordinates of the base tile, respectively.
        """ 
        adjlist = [(x - 1, y - 1), (x, y - 1), (x + 1, y - 1),
                   (x - 1, y), (x + 1, y),
                   (x - 1, y + 1), (x, y + 1), (x + 1, y + 1)]
        rmlist = []
        for adjpair in adjlist:
            for value, index in [(-1, 0), (-1, 1), (self.cols, 0),
                                 (self.rows, 1)]:
                if adjpair[index] == value:
                    rmlist.append(adjpair)
                    break
        for item in rmlist:
            adjlist.remove(item)
        return adjlist

&lt;/pre&gt;It looked pretty heavy to me, for the small amount of work
it&amp;#8217;s doing. Ah, it had to use nested loops instead of list
comprehensions, and it&amp;#8217;s adding unnecessary rows only to remove
them later. I think I could do better if I had a body of tests to
protect me.

  &lt;p&gt;I figure it&amp;#8217;s time to try PyUnit inside Eclipse. I create a
  new file called testPysweeper.py. I hate the name, and again go
  against my better instincts by leaving it that for a while. That
  would be yet another promise, and I&amp;#8217;m running out of patience
  for procrastination.  I rename it &lt;code&gt;testAdjacency.py&lt;/code&gt;. 
  I feel an instant sense of relief and go on to write a
  series of tests of the existing &lt;code&gt;_get_adjacent&lt;/code&gt;
  method. It is&lt;/p&gt;

  &lt;pre&gt;
        class PySweeperTest(unittest.TestCase):
            def parentSetup(self, columns, rows, mines, target):
                target_column, target_row = target
                self.game = pysweeper.Field(columns,rows,mines)
                self.target = (target_column,target_row)
                self.result = self.game._get_adjacent_cells(*self.target)
                self.result.sort()

        class CellsAdjacentToCol2Row2(PySweeperTest):
            """Expecting a circle of squares around the target cell""" 
            def setUp(self):
                self.parentSetup(5,5,0, (2,2))
            def testShouldFindEightCells(self):
                assert len(self.result) == 8
            def testShouldNotIncludeCol2Row2(self):
                assert self.target not in self.result
&lt;/pre&gt;These are not highly imaginative, and continue with several
different scenarios. I test a normal &amp;#8220;middle&amp;#8221; cell, one against an
edge, the top left and bottom right corners, etc. &lt;/p&gt;

  &lt;p&gt;You&amp;#8217;ll notice the base class &lt;code&gt;PySweeperTest&lt;/code&gt;. I didn&amp;#8217;t have that to start with
  but added it to reduce duplication, and I named it badly.  These
  are not general PySweeper tests, but they are specific cell adjacency tests.  Naming is easily fixed.
  &lt;/p&gt;
  &lt;p&gt;  A cool thing happens.  I rename it &lt;code&gt;AdjacencyTest&lt;/code&gt; and 
  Suddenly all the test names become redundant and silly.  I 
  start renaming them, and 
  &lt;pre&gt;
  class CellsAdjacentToCol0Row0(PysweeperTest):
  &lt;/pre&gt;
  becomes
  &lt;pre&gt;
  class Column0Row0(AdjacencyTest):
  &lt;/pre&gt;
  On further reflection, this becomes:
  &lt;pre&gt;
  class UpperLeftCorner(AdjacencyTest):
  &lt;/pre&gt;
  It&amp;#8217;s amazing how wrong my first instinct can be.  The test is so much more
  obvious now, and the conditions make so much more sense.  I smile in mild
  self-derision, but I&amp;#8217;m happy to have cleaned it up quickly.  The PyDev 
  refactoring tools feel pretty comfortable to me now.  One goal of the exercise
  is being met.
  &lt;/p&gt;

  &lt;p&gt;
  The tests run for the old routine, and I write a new routine.
  &lt;/p&gt;

  &lt;p&gt;I hit my next snag trying to run the python unit test. I have 
  always done python from the
  command line, and would run my tests as if they were any other
  python program. I never did them as:&lt;/p&gt;
  &lt;pre&gt;
        python -m unittest filename.testname

&lt;/pre&gt;I think that this must be what Eclipse wants to do. I can use
the option to &lt;code&gt;Run as.../Python run&lt;/code&gt; but I cannot use
the option to &lt;code&gt;Run as.../Python unit-test&lt;/code&gt;. When I try I
get the following error:
  &lt;pre&gt;
  Finding files... ['/home/tottinge/Projects/Pysweeper-1.0/testAdjacency.py']
  done.
  Importing test modules... done.

  ----------------------------------------------------------------------
  Ran 0 tests in 0.000s

&lt;/pre&gt;It found the right test file, but either it didn&amp;#8217;t import it,
or else it imported it and somehow didn&amp;#8217;t recognize any tests. I
added a print line to the file so I could see it, and got nothing.
Why would it find my file and not import it? This is something that
requires a little google..&lt;/p&gt;
&lt;p&gt;It doesn&amp;#8217;t work when I use the &lt;code&gt;python -m unittest blah&lt;/code&gt;
either.  Maybe the problem isn&amp;#8217;t that I&amp;#8217;m not used to PyDev, but that
I don&amp;#8217;t know enough about PyUnit?  I put this off, since I have a
reasonable workaround for now. This is &lt;em&gt;another&lt;/em&gt; bit of debt
to work off.  I&amp;#8217;m unhappy at how fast it piles up.&lt;/p&gt;

  &lt;p&gt; The old version of &lt;code&gt;_get_adjacent&lt;/code&gt; was about 21 lines 
  with loops and local variables. Here is a smaller 
  version using list comprehensions:&lt;/p&gt;
  &lt;pre&gt;
   def _get_adjacent(self, x, y):
        """Provide a list of all tiles adjacent to the given tile.""" 
        columns = (x-1,x,x+1);
        rows = (y-1,y,y+1);
        adjacent_pairs = [ (col,row)  for col in columns 
                                      for row in rows 
                                      if 0&amp;lt;=row&amp;lt;self.rows and 0&amp;lt;=col&amp;lt;self.cols]
        adjacent_pairs.remove( (x,y) )
        return adjacent_pairs

&lt;/pre&gt;

  &lt;p&gt;A list comp is very simple. The one above returns a list of &lt;code&gt;(row,column)&lt;/code&gt;
  pairs by iterating over &lt;code&gt;columns&lt;/code&gt; and &lt;code&gt;rows&lt;/code&gt;, and only returns a pair if the
  &lt;code&gt;row&lt;/code&gt; and &lt;code&gt;column&lt;/code&gt; are both on the grid. But it doesn&amp;#8217;t look that simple above.
  My spider sense buzzes.  I immediately worry that the list comp is too complex.
  The filtering is too deep in the list comprehension and is too far from the initialization of
  &lt;code&gt;rows&lt;/code&gt; and &lt;code&gt;columns&lt;/code&gt;. A quick modification and retest.&lt;/p&gt;
  &lt;pre&gt;
    def _get_adjacent_cells( self, x, y ):
        """Provide a list of all tiles adjacent to the given tile.""" 
        columns = [ col for col in ( x-1, x, x+1) if 0&amp;lt;=col&amp;lt;self.cols ]
        rows = [ row for row in (y-1, y, y+1) if 0&amp;lt;=row&amp;lt;self.rows ]

        adjacent_pairs = [ ( col, row )  for col in columns for row in rows ]
        adjacent_pairs.remove( ( x, y ) )

        return adjacent_pairs  
&lt;/pre&gt;

  &lt;p&gt;The tests all pass, and the code is more obvious to me. I have no teammate
  to correct me, so I leave it as-is.&lt;/p&gt;

  &lt;p&gt;One more feature to look at today, and that&amp;#8217;s the
  &lt;code&gt;compare with local history&lt;/code&gt;. It&amp;#8217;s a beautiful thing.
  Eclipse is becoming a very good friend to me.&lt;/p&gt;</description>
      <pubDate>Sat, 10 Feb 2007 21:44:00 -0600</pubDate>
      <guid isPermaLink="false">urn:uuid:412dba24-24df-4e5f-8dff-87133f58bc6d</guid>
      <author>tottinger</author>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in</link>
      <category>Tim's Tepid Torrent</category>
      <trackback:ping>http://blog.objectmentor.com/articles/trackback/158</trackback:ping>
    </item>
    <item>
      <title>"PySweeper: Digging In" by Hancy</title>
      <description>&lt;p&gt;Hello Friend,Whichever style of Fashion Shoes you&amp;#8217;re looking for, classical, fashionable, lovely or the latest design, you can find your favorite designer shoes in &lt;a href="http://www.dunkpage.com" rel="nofollow"&gt;www.dunkpage.com&lt;/a&gt; ,several days ago I bought one pair of shoes from there,It&amp;#8217;s beautiful and very comfortable!&lt;/p&gt;</description>
      <pubDate>Wed, 08 Jun 2011 10:58:44 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:31bfca44-e1bc-40ec-9c24-1da0d6cbff6b</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-109083</link>
    </item>
    <item>
      <title>"PySweeper: Digging In" by christian louboutin shoes on sale</title>
      <description>&lt;p&gt;Have the &lt;a href="http://www.blacklouboutinshoes.com/pumps-c-2.html" rel="nofollow"&gt;christian louboutin patent leather pumps&lt;/a&gt;  is a happy thing. 
Here have the most complete kinds of  &lt;a href="http://www.blacklouboutinshoes.com/platforms-c-3.html" rel="nofollow"&gt;christian louboutin leather platform pumps&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Fri, 03 Jun 2011 04:00:38 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:be239421-e5eb-4822-b5ac-4d9a168f9fe2</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-107584</link>
    </item>
    <item>
      <title>"PySweeper: Digging In" by Monster Beats By Dr. Dre Studio</title>
      <description>&lt;p&gt;The &lt;a href="http://www.drebeatsstudio.com/beats-by-dr-dre-studio-c-3.html" rel="nofollow"&gt;Monster Beats By Dr. Dre Studio Headphones&lt;/a&gt; are classic shoes.You will be proud of owning them.
Don&amp;#8217;t hesitate!Take &lt;a href="http://www.drebeatsstudio.com/beats-by-dr-dre-solo-c-5.html" rel="nofollow"&gt;Monster Beats By Dr. Dre Solo Headphones&lt;/a&gt; home!&lt;/p&gt;</description>
      <pubDate>Mon, 30 May 2011 07:31:09 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:0c111bbf-9c7b-48bb-a029-4160d08e6020</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-105466</link>
    </item>
    <item>
      <title>"PySweeper: Digging In" by marc jacob eyeglasses</title>
      <description>&lt;p&gt;&lt;a href="http://www.marcjacobsunglasses4.info" rel="nofollow"&gt;&lt;strong&gt;marc jacobs eyeglasses&lt;/strong&gt;&lt;/a&gt; is correctional eyesight or eye protection and make simple optical device. Composed by lens and frames. Vision correction use glasses have myopia &lt;a href="http://www.marcjacobsunglasses4.info" rel="nofollow"&gt;&lt;strong&gt;discount marc jacobs sunglasses&lt;/strong&gt;&lt;/a&gt; and farsightedness glasses, &lt;a href="http://www.marcjacobsunglasses4.info" rel="nofollow"&gt;&lt;strong&gt;marc jacobs&lt;/strong&gt;&lt;/a&gt; and astigmatism glasses four. Protect eyes with glasses have bond and basto protection lens, the degree of FengJing and fairy dean Laura cindylaura sunglasses, etc. &lt;a href="http://www.marcjacobsunglasses4.info/marc-jacob-sunglasses-c-71.html" rel="nofollow"&gt;&lt;strong&gt;marc jacobs sunglasses&lt;/strong&gt;&lt;/a&gt; is both eye protection tools, it is a kind of hairdressing decorations.&lt;/p&gt;</description>
      <pubDate>Mon, 23 May 2011 20:55:58 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:e04024b7-cc8a-415c-bb67-c9b76402c574</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-102890</link>
    </item>
    <item>
      <title>"PySweeper: Digging In" by okey oyunu oyna </title>
      <description>&lt;p&gt;thanks this post is useful&amp;#8230;.&lt;/p&gt;


	&lt;p&gt;D&#252;nyan?n en b&#252;y&#252;k online okey oyunu bu sitede sizleri bekliyor.
 Ger&#231;ek ki?ilerle sohbet ederek  &lt;a href="http://www.okeyoyunu-oyna.com" rel="nofollow"&gt;Okey Oyunu Oyna&lt;/a&gt; ve 
internette online oyun oynaman?n zevkini &#231;?kar&lt;/p&gt;</description>
      <pubDate>Fri, 22 Apr 2011 13:27:30 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:a18b294e-2a4c-4218-99cf-b391748f99d5</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-89642</link>
    </item>
    <item>
      <title>"PySweeper: Digging In" by Robert Schlee</title>
      <description>&lt;p&gt;I saw this blog site via Facebook (a friend of mine posted it). After reading through, I clicked like as well as shared it myseld. Much more electrical power.&lt;/p&gt;</description>
      <pubDate>Tue, 19 Apr 2011 04:57:54 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:0baf2faa-7ee1-4bc1-9b0e-6c98a6f5d5e6</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-87187</link>
    </item>
    <item>
      <title>"PySweeper: Digging In" by ipad bag</title>
      <description>&lt;p&gt;TopCombine Follow &lt;a href="http://www.voien.com/" rel="nofollow"&gt;ipad bag&lt;/a&gt;  the detail tips below, you can increase the laptop battery life of a year or more. &lt;a href="http://www.fjblcy.com/" rel="nofollow"&gt;Game Controllers&lt;/a&gt; first thing you should care about the  &lt;a href="http://www.dewkett.com/" rel="nofollow"&gt;USB Gadgets&lt;/a&gt;  END!111&lt;/p&gt;</description>
      <pubDate>Fri, 18 Mar 2011 03:25:42 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:319b97bb-b0b8-4555-8576-76e1db19cafd</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-73473</link>
    </item>
    <item>
      <title>"PySweeper: Digging In" by Tenant Screening</title>
      <description>&lt;p&gt;A list comp is very simple. The one above returns a list of (row,column) pairs by iterating over columns and rows, and only returns a pair if the row and column are both on the grid.&lt;/p&gt;</description>
      <pubDate>Wed, 23 Feb 2011 09:38:56 -0600</pubDate>
      <guid isPermaLink="false">urn:uuid:7db988a7-1647-4c14-814b-4ba726b15051</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-66154</link>
    </item>
    <item>
      <title>"PySweeper: Digging In" by Criminal Records</title>
      <description>&lt;p&gt;The issue is not with the use of filters, but that the function and the data it operates on are completely non-self-describing, and can only be understood by grasping the entirety of this absurd parade of intermediate forms, from program start to program end.&lt;/p&gt;</description>
      <pubDate>Mon, 21 Feb 2011 14:30:30 -0600</pubDate>
      <guid isPermaLink="false">urn:uuid:84a8db88-817b-4da2-a2b8-e25e7140fab1</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-65269</link>
    </item>
    <item>
      <title>"PySweeper: Digging In" by video to ipad converter</title>
      <description>&lt;p&gt;Thank you that you can take time from your busy schedule to provide this practical information for us, it really give us a lot of help .
&lt;a &gt;video to ipad converter&lt;/a rel="nofollow"&gt;&lt;/p&gt;</description>
      <pubDate>Wed, 03 Nov 2010 07:02:50 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:0eefbf9c-1c0e-4030-bf45-65f1b6b0116a</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-37466</link>
    </item>
    <item>
      <title>"PySweeper: Digging In" by DVD to ipad</title>
      <description>&lt;p&gt;ah  ha  ...it is a good post 
you can read it&lt;/p&gt;</description>
      <pubDate>Fri, 23 Apr 2010 00:44:30 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:590f6680-ce43-41b2-956c-66c732e7d5a7</guid>
      <link>http://blog.objectmentor.com/articles/2007/02/10/pysweeper-digging-in#comment-10509</link>
    </item>
  </channel>
</rss>

