Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

connect four (game)

124 views
Skip to first unread message

namenob...@gmail.com

unread,
Nov 24, 2017, 10:33:34 AM11/24/17
to
hi all

i've just finished my first excursion into artificial intelligence with a game less trivial than tictactoe, and here it is in case anybody can offer criticism/suggestions/etc

peace
stm


###############################
#) connectfour - python 3.6.1
###############################

from tkinter import *
from random import choice

class infinity:
def __init__(self,signum): self.signum = signum
def __repr__(self): return '+oo' if self.signum > 0 else '-oo'
def __lt__(self,other): return False if self.signum > 0 else True
def __le__(self,other): return False if self.signum > 0 else True
def __gt__(self,other): return True if self.signum > 0 else False
def __ge__(self,other): return True if self.signum > 0 else False
def __eq__(self,other): return isinstance(other,infinity) and self.signum == other.signum

ex, oh, blank = 'red black white' .split()

startboard = {(i,j):blank for i in range(6) for j in range(7)}

def getlines(board):
horizontal = [[(i, j+k) for k in range(4)] for i in range(6) for j in range(7)]
vertical = [[(i+k, j) for k in range(4)] for i in range(6) for j in range(7)]
positive = [[(i+k, j+k) for k in range(4)] for i in range(6) for j in range(7)]
negative = [[(i+k, j-k) for k in range(4)] for i in range(6) for j in range(7)]
linear = horizontal + vertical + positive + negative
lines = [line for line in linear if all(i in range(6) and j in range(7) for (i,j) in line)]
return [[board[square] for square in line] for line in lines]

def getwinner(board):
lines = getlines(board)
return ex if [ex]*4 in lines else oh if [oh]*4 in lines else None

def getmover(board):
boardvalues = list(board.values())
return ex if boardvalues.count(ex)==boardvalues.count(oh) else oh

def getoptimum(mover):
return max if mover == ex else min

def getaccessibles(board):
return [j for j in range(7) if board[0,j] == blank]

def getvalue(winner,accessibles):
return infinity(+1) if winner == ex else infinity(-1) if winner == oh else 0 if not accessibles else None

def makemove(board,column,mover):
board = board.copy()
empties = [row for row in range(6) if board[row,column] == blank]
if not empties: return board
board[max(empties),column] = mover
return board

def takemoveback(board,column):
board = board.copy()
occupied = [row for row in range(6) if board[row,column] != blank]
if not occupied: return board
board[min(occupied),column] = blank
return board

def guessvalue(board):
lines = getlines(board)
exs = [line for line in lines if line.count(ex)==3 and line.count(oh)==0]
ohs = [line for line in lines if line.count(oh)==3 and line.count(ex)==0]
return len(exs)-len(ohs)

def heuristicvalue(board,depth):
winner = getwinner(board)
accessibles = getaccessibles(board)
value = getvalue(winner,accessibles)
if value != None: return value
if depth == 0: return guessvalue(board)
mover = getmover(board)
optimum = getoptimum(mover)
children = [makemove(board,column,mover) for column in accessibles]
return optimum(heuristicvalue(child,depth-1) for child in children)

def getmoves(board,depth):
accessibles = getaccessibles(board)
if not accessibles: return []
mover = getmover(board)
optimum = getoptimum(mover)
children = [makemove(board,column,mover) for column in accessibles]
values = [heuristicvalue(child,depth) for child in children]
bestvalue = optimum(values)
return [accessibles[index] for index in range(len(accessibles)) if values[index] == bestvalue]

class grid:
def __init__(self,window):
self.window = window
self.boardframe = Frame(window.root)
self.rowframes = [Frame(self.boardframe) for anonymous in range(6)]
self.squarebuttons = [Button(self.rowframes[number//7], width=3, command=self.window.squarecommand(number), background=blank) for number in range(42)]
def pack(self):
self.boardframe .pack(side=TOP)
[frame .pack(side=TOP) for frame in self.rowframes]
[button .pack(side=LEFT) for button in self.squarebuttons]

class caption:
def __init__(self,window):
self.window = window
self.statusframe = Frame(window.root)
self.statuslabel = Label(self.statusframe, height=2)
def pack(self):
self.statusframe .pack(side=TOP)
self.statuslabel .pack(side=LEFT)

class buttonpanel:
def __init__(self,window,depth):
self.window = window
self.controlframe = Frame(window.root)
self.makemoveframe = Frame(self.controlframe)
self.takebackframe = Frame(self.controlframe)
self.startoverframe = Frame(self.controlframe)
self.makemovebutton = Button(self.makemoveframe, text='make move', command=self.window.movecommand(depth))
self.takebackbutton = Button(self.takebackframe, text='take back', command=self.window.takeback)
self.startoverbutton = Button(self.startoverframe, text='start over', command=self.window.startover)
def pack(self):
self.controlframe .pack(side=TOP)
self.makemoveframe .pack(side=LEFT)
self.takebackframe .pack(side=LEFT)
self.startoverframe .pack(side=RIGHT)
self.makemovebutton .pack(side=TOP)
self.takebackbutton .pack(side=TOP)
self.startoverbutton .pack(side=TOP)

class window:
def __init__(self, depth=2):
self.root = Tk()
self.grid = grid (self)
self.caption = caption (self)
self.buttonpanel = buttonpanel(self, depth=2)
self.grid .pack()
self.caption .pack()
self.buttonpanel .pack()
self.startover()
self.root.title('connect four')
self.root.mainloop()
def startover(self):
self.board = startboard
self.movelist = []
self.display()
def display(self):
winner = getwinner(self.board)
mover = getmover (self.board)
tie = blank not in self.board.values()
status = winner + ' wins' if winner else 'tied game' if tie else mover + ' to move'
[self.grid.squarebuttons[number].config(background=self.board[divmod(number,7)]) for number in range(42)]
self.caption.statuslabel.config(text = status.upper() if winner or tie else status)
def squarecommand(self,number):
def returnvalue():
if getwinner(self.board) or blank not in self.board.values(): return
column = number % 7
self.board = makemove(self.board, column, getmover(self.board))
self.display()
self.grid.squarebuttons[column].flash()
self.movelist += [column]
return returnvalue
def movecommand(self,depth):
def returnvalue():
if getwinner(self.board) or blank not in self.board.values(): return
column = choice(getmoves(self.board,depth))
self.board = makemove(self.board, column, getmover(self.board))
self.display()
self.grid.squarebuttons[column].flash()
self.movelist += [column]
return returnvalue
def takeback(self):
if not self.movelist: return
self.board = takemoveback(self.board, self.movelist[-1])
self.display()
self.movelist = self.movelist[:-1]

Chris Angelico

unread,
Nov 24, 2017, 11:07:07 AM11/24/17
to
On Sat, Nov 25, 2017 at 2:33 AM, <namenob...@gmail.com> wrote:
> hi all
>
> i've just finished my first excursion into artificial intelligence with a game less trivial than tictactoe, and here it is in case anybody can offer criticism/suggestions/etc
>

Hi!

You don't have a lot of comments or docstrings or anything, so it's
not going to be easy to track down bugs. (I haven't tested your code,
so in theory it could be 100% bug-free, but frankly I doubt it. No
code is ever perfect :) )

> class infinity:
> def __init__(self,signum): self.signum = signum
> def __repr__(self): return '+oo' if self.signum > 0 else '-oo'
> def __lt__(self,other): return False if self.signum > 0 else True
> def __le__(self,other): return False if self.signum > 0 else True
> def __gt__(self,other): return True if self.signum > 0 else False
> def __ge__(self,other): return True if self.signum > 0 else False
> def __eq__(self,other): return isinstance(other,infinity) and self.signum == other.signum

In Python, it's normal to name classes with a capital first letter, so
"class Infinity" would be more normal.

Instead of "True if some_condition else False", you can simply write
"some_condition", and instead of "False if some_condition else True",
you can write "not some_condition".

> def getlines(board):
> horizontal = [[(i, j+k) for k in range(4)] for i in range(6) for j in range(7)]
> vertical = [[(i+k, j) for k in range(4)] for i in range(6) for j in range(7)]
> positive = [[(i+k, j+k) for k in range(4)] for i in range(6) for j in range(7)]
> negative = [[(i+k, j-k) for k in range(4)] for i in range(6) for j in range(7)]
> linear = horizontal + vertical + positive + negative
> lines = [line for line in linear if all(i in range(6) and j in range(7) for (i,j) in line)]
> return [[board[square] for square in line] for line in lines]

Lining up your code vertically just looks ugly if you change to a
different font. I wouldn't bother, personally.

This is the kind of function that needs a docstring and some comments.
What exactly is this doing? What are the "lines" of the board? What's
the difference between "linear" and "lines"? What exactly is it
returning?

> def getwinner(board):
> lines = getlines(board)
> return ex if [ex]*4 in lines else oh if [oh]*4 in lines else None

You seem to have fallen in love with the ternary 'if' expression.
While it's normal for young lovers to shower each other with
affection, it tends to get awkward for those watching you. I would
recommend breaking some of these into straight-forward 'if'
statements.

> def getmover(board):
> boardvalues = list(board.values())
> return ex if boardvalues.count(ex)==boardvalues.count(oh) else oh

This is a very expensive way to avoid maintaining a "whose turn is it,
anyway?" variable.

> def getoptimum(mover):
> return max if mover == ex else min

I *think* this might be a critical part of your algorithm, but again,
in the absence of explanatory information, I can't be sure. Are you
following a basic minimax algorithm, where you assume that your
opponent will always play optimally, and you attempt to minimize your
potential losses? If so, definitely needs to be stated somewhere.
(Also, if that's the case, your code is probably locked down to having
the AI always playing the same side. Again, that needs to be stated
clearly.)

> def getvalue(winner,accessibles):
> return infinity(+1) if winner == ex else infinity(-1) if winner == oh else 0 if not accessibles else None

Uhhhhh.... I don't even know what this is doing. Value of what? Why so
much if/else in a single expression?

> def heuristicvalue(board,depth):
> winner = getwinner(board)
> accessibles = getaccessibles(board)
> value = getvalue(winner,accessibles)
> if value != None: return value
> if depth == 0: return guessvalue(board)
> mover = getmover(board)
> optimum = getoptimum(mover)
> children = [makemove(board,column,mover) for column in accessibles]
> return optimum(heuristicvalue(child,depth-1) for child in children)

Anything with "heuristic" in the name is probably an important part of
your algorithm. But I've looked at the code and I don't understand
what it's doing.

> def getmoves(board,depth):
> accessibles = getaccessibles(board)
> if not accessibles: return []
> mover = getmover(board)
> optimum = getoptimum(mover)
> children = [makemove(board,column,mover) for column in accessibles]
> values = [heuristicvalue(child,depth) for child in children]
> bestvalue = optimum(values)
> return [accessibles[index] for index in range(len(accessibles)) if values[index] == bestvalue]

And this looks very similar to the previous one. Or at least, there
are several identical lines. Hmm.

> [self.grid.squarebuttons[number].config(background=self.board[divmod(number,7)]) for number in range(42)]

Hrm. If this is the whole line of code, it's a list comp that discards
its result. If so, it would be far better written as a
straight-forward loop.

General summary of all of the above comments: Assume that you have to
collaborate with another programmer, and try to make his/her life
easy. You'll appreciate it six months from now, by which time you will
yourself be a different programmer, with no memory of what you were
doing as you wrote this :)

All the best!

ChrisA

Terry Reedy

unread,
Nov 24, 2017, 3:13:18 PM11/24/17
to
On 11/24/2017 10:33 AM, namenob...@gmail.com wrote:
> hi all
>
> i've just finished my first excursion into artificial intelligence with a game less trivial than tictactoe, and here it is in case anybody can offer criticism/suggestions/etc

Since you did not start with tests or write tests as you wrote code,
write a test file now. It will probably be at least as long as your
current file. You will learn a lot about your code by doing so.

--
Terry Jan Reedy

namenob...@gmail.com

unread,
Nov 24, 2017, 9:06:11 PM11/24/17
to
On Friday, November 24, 2017 at 12:13:18 PM UTC-8, Terry Reedy wrote:

> Since you did not start with tests or write tests as you wrote code, ...

why on earth would you assume that? instantiate "window" and you'll see it works exactly as i intended; nobody's asking you to debug code for free; i'm looking for the kind of feedback the other respondent gave

peace
stm


Chris Angelico

unread,
Nov 24, 2017, 9:58:51 PM11/24/17
to
Tests, in this sense, means *automated* tests. Check out the
"unittest" module, and perhaps read up on techniques of software
testing.

ChrisA

Ian Kelly

unread,
Nov 24, 2017, 11:44:23 PM11/24/17
to
Since you're being a bit of an ass about it, I took the liberty of
writing some tests for you. This only covers the very first class in
the file (I don't have all night). Two of the tests pass. The others
don't.

Since the interface is unclear (is signum allowed to be any signed
number, or only +/-1? The ordered comparison methods suggest the
former, but __eq__ only works with the latter) I chose to be
conservative and only wrote tests with +/-1. Otherwise test_eq would
also fail.

Please understand the point of this is not to shame you or anything.
As you said, we're not going to debug your code for you, but you asked
for criticism/suggestions, and I hope to make you see that suggesting
you write tests is a very valid and useful criticism of its own.


###############################
#) connectfour_test - python 3.6.1
###############################

import unittest

from connectfour import infinity


class InfinityTest(unittest.TestCase):

def test_repr(self):
self.assertEqual('+oo', repr(infinity(+1)))
self.assertEqual('-oo', repr(infinity(-1)))

def test_lt(self):
self.assertLess(infinity(-1), infinity(+1))
self.assertFalse(infinity(-1) < infinity(-1))
self.assertFalse(infinity(+1) < infinity(+1))
self.assertFalse(infinity(+1) < infinity(-1))

def test_le(self):
self.assertLessEqual(infinity(-1), infinity(+1))
self.assertLessEqual(infinity(-1), infinity(-1))
self.assertLessEqual(infinity(+1), infinity(+1))
self.assertFalse(infinity(+1) <= infinity(-1))

def test_gt(self):
self.assertFalse(infinity(-1) > infinity(+1))
self.assertFalse(infinity(-1) > infinity(-1))
self.assertFalse(infinity(+1) > infinity(+1))
self.assertGreater(infinity(+1), infinity(-1))

def test_ge(self):
self.assertFalse(infinity(-1) >= infinity(+1))
self.assertGreaterEqual(infinity(-1), infinity(-1))
self.assertGreaterEqual(infinity(+1), infinity(+1))
self.assertGreaterEqual(infinity(+1), infinity(-1))

def test_eq(self):
self.assertEqual(infinity(-1), infinity(-1))
self.assertEqual(infinity(+1), infinity(+1))
self.assertNotEqual(infinity(-1), infinity(+1))
self.assertNotEqual(infinity(+1), infinity(-1))


if __name__ == '__main__':
unittest.main()

Terry Reedy

unread,
Nov 25, 2017, 3:48:38 AM11/25/17
to
On 11/24/2017 9:05 PM, namenob...@gmail.com wrote:
> On Friday, November 24, 2017 at 12:13:18 PM UTC-8, Terry Reedy wrote:
>
>> Since you did not start with tests or write tests as you wrote code, ...

that I could tell ...

I agree that I should have stuck in a qualifier, such as 'apparently'.

> why on earth would you assume that?

I inferred (not assumed) that because
a) people routinely post code here and on Stackoverflow without
including or mentioning runnable automated tests;
b) you said 'here it is' without a word about tests;
c) your code has no docstrings or other function by function doc, and
one can hardly write tests without them.

Was I right or are you exceptional?

> instantiate "window" and you'll see it works exactly as i intended;

I did, and it looks buggy to me. The top and left frame lines are
missing. If I click a square, the bottom square in the column lights
up. But then I have no idea whether those are your intentions or not.

nobody's asking you to debug code for free; i'm looking for the kind of
feedback the other respondent gave.

I read Chris's answer and intentionally did not repeat. Anyway, I think
the best advice I could give you, based on experience writing and
reviewing code, if you do not already have complete coverage, is to
write (more?) automated tests.

--
Terry Jan Reedy

bartc

unread,
Nov 25, 2017, 8:00:12 AM11/25/17
to
Where are your unittests for these unittests?

Or is this kind of code immune from testing?

Actually I've no idea what these tests are supposed to prove. They are
to do with one class called 'infinity', which is never used in the rest
of the program apart from one line.

I established that within a few seconds, and I would concentrate on what
'infinity' is actually for, rather than go to considerable lengths to
test a class that may not actually be needed.

And there's a quite lot left of the rest of the program to worry about too!

If you add 'window()' at the end of the program, then it seems to run on
Python 3. I'd play around with it first before thinking up strategies
for testing it.

--
bartc

Ian Kelly

unread,
Nov 25, 2017, 11:37:35 AM11/25/17
to
On Sat, Nov 25, 2017 at 6:00 AM, bartc <b...@freeuk.com> wrote:
> Where are your unittests for these unittests?

Taking this question more seriously than it deserves: the tests for
the unittest module itself are at
https://hg.python.org/cpython/file/tip/Lib/unittest/test. Yes,
unittest has tests of itself.

As for tests of the tests, that's getting a bit absurd, don't you
think? Then we'd have to write tests of the tests of the tests. And
then those tests would need tests. It's turtles all the way down.

No, the point of having unit tests is to build confidence that the
code in question works correctly. It's *possible* that the code is
broken, and that the test is also broken in a way that hides the
brokenness of the code, but this is much less likely than the case
where just the code is broken. This is also the reason why the
philosophy of test-drive development stipulates that one should write
the test *first*, run it and watch it fail (this ensures that the test
is actually testing *something*) and then and only then write the code
to make the test pass.

> Or is this kind of code immune from testing?

It is the production code, not the test code, that we wish to have
confidence in.

> Actually I've no idea what these tests are supposed to prove. They are to do
> with one class called 'infinity', which is never used in the rest of the
> program apart from one line.

As I stated in my earlier reply, I just started at the top of the file
and wrote some tests. I didn't do anything for the rest of the program
because I was merely trying to demonstrate the technique, not write
hundreds of lines of tests for the OP.

> I established that within a few seconds, and I would concentrate on what
> 'infinity' is actually for, rather than go to considerable lengths to test a
> class that may not actually be needed.

If the class is used, then it's needed. There is a concept in software
testing called "code coverage". This represents the idea that every
statement in a program should be exercised at least once by the tests.
This is one of the reasons why much software testing focuses on unit
testing: if we break the program apart into units, and we thoroughly
test each unit, then we should end up with complete coverage of the
program as a whole.

> If you add 'window()' at the end of the program, then it seems to run on
> Python 3. I'd play around with it first before thinking up strategies for
> testing it.

"Seems to run" and "works correctly" are very different things.

Chris Angelico

unread,
Nov 25, 2017, 12:02:56 PM11/25/17
to
On Sun, Nov 26, 2017 at 3:36 AM, Ian Kelly <ian.g...@gmail.com> wrote:
> On Sat, Nov 25, 2017 at 6:00 AM, bartc <b...@freeuk.com> wrote:
>> Where are your unittests for these unittests?
>
> No, the point of having unit tests is to build confidence that the
> code in question works correctly. It's *possible* that the code is
> broken, and that the test is also broken in a way that hides the
> brokenness of the code, but this is much less likely than the case
> where just the code is broken. This is also the reason why the
> philosophy of test-drive development stipulates that one should write
> the test *first*, run it and watch it fail (this ensures that the test
> is actually testing *something*) and then and only then write the code
> to make the test pass.

To be fair, TDD doesn't actually prove that the test isn't broken. It
only protects you against one class of error: tests that actually
aren't testing anything. Proponents of TDD will argue that this class
of error is quite common; true or not, it's still only one particular
kind of failure. It's definitely possible for tests to be wrong in
such a way that they don't detect faulty code.

So what do we do? WE TEST BY HAND. Ultimately, unit testing is a tool,
not a magic wand. It's up to us to actually put it to use to improve
code quality.

ChrisA

Ian Kelly

unread,
Nov 25, 2017, 12:24:13 PM11/25/17
to
On Sat, Nov 25, 2017 at 10:02 AM, Chris Angelico <ros...@gmail.com> wrote:
> On Sun, Nov 26, 2017 at 3:36 AM, Ian Kelly <ian.g...@gmail.com> wrote:
>> On Sat, Nov 25, 2017 at 6:00 AM, bartc <b...@freeuk.com> wrote:
>>> Where are your unittests for these unittests?
>>
>> No, the point of having unit tests is to build confidence that the
>> code in question works correctly. It's *possible* that the code is
>> broken, and that the test is also broken in a way that hides the
>> brokenness of the code, but this is much less likely than the case
>> where just the code is broken. This is also the reason why the
>> philosophy of test-drive development stipulates that one should write
>> the test *first*, run it and watch it fail (this ensures that the test
>> is actually testing *something*) and then and only then write the code
>> to make the test pass.
>
> To be fair, TDD doesn't actually prove that the test isn't broken. It
> only protects you against one class of error: tests that actually
> aren't testing anything. Proponents of TDD will argue that this class
> of error is quite common; true or not, it's still only one particular
> kind of failure. It's definitely possible for tests to be wrong in
> such a way that they don't detect faulty code.
>
> So what do we do? WE TEST BY HAND. Ultimately, unit testing is a tool,
> not a magic wand. It's up to us to actually put it to use to improve
> code quality.

Certainly. I wasn't trying to advocate for TDD here, which I don't
even practice regularly myself.

Christopher Reimer

unread,
Nov 25, 2017, 1:49:29 PM11/25/17
to
On Nov 25, 2017, at 9:16 AM, Ian Kelly <ian.g...@gmail.com> wrote:
>
>> On Sat, Nov 25, 2017 at 10:02 AM, Chris Angelico <ros...@gmail.com> wrote:
>>> On Sun, Nov 26, 2017 at 3:36 AM, Ian Kelly <ian.g...@gmail.com> wrote:
>>>> On Sat, Nov 25, 2017 at 6:00 AM, bartc <b...@freeuk.com> wrote:
>>>> Where are your unittests for these unittests?
>>>
>>> No, the point of having unit tests is to build confidence that the
>>> code in question works correctly. It's *possible* that the code is
>>> broken, and that the test is also broken in a way that hides the
>>> brokenness of the code, but this is much less likely than the case
>>> where just the code is broken. This is also the reason why the
>>> philosophy of test-drive development stipulates that one should write
>>> the test *first*, run it and watch it fail (this ensures that the test
>>> is actually testing *something*) and then and only then write the code
>>> to make the test pass.
>>
>> To be fair, TDD doesn't actually prove that the test isn't broken. It
>> only protects you against one class of error: tests that actually
>> aren't testing anything. Proponents of TDD will argue that this class
>> of error is quite common; true or not, it's still only one particular
>> kind of failure. It's definitely possible for tests to be wrong in
>> such a way that they don't detect faulty code.
>>
>> So what do we do? WE TEST BY HAND. Ultimately, unit testing is a tool,
>> not a magic wand. It's up to us to actually put it to use to improve
>> code quality.
>
> Certainly. I wasn't trying to advocate for TDD here, which I don't
> even practice regularly myself.
> --
> https://mail.python.org/mailman/listinfo/python-list

For anyone who is interested, "Test-Driven Development with Python: Obey the Testing Goat: Using Django, Selenium, and JavaScript" by Harry J.W. Percival. The second edition came out this year. A good introduction to unit and function testing.

Chris R.

Michael Torrie

unread,
Nov 25, 2017, 2:50:53 PM11/25/17
to
On 11/25/2017 06:00 AM, bartc wrote:
> And there's a quite lot left of the rest of the program to worry about too!
>
> If you add 'window()' at the end of the program, then it seems to run on
> Python 3. I'd play around with it first before thinking up strategies
> for testing it.

Actually, no. Unit testing ideally should be done for each and every
class as they are being written (before they are written in fact), no
matter how small and trivial the class. That way as you compose larger
and larger units of code, the chances of things being right is greater
compared to doing it the other way around.

You may argue that testing doesn't matter for his small game, written
for his own education and amusement. The fact is that software in
general is of abysmal quality across the boards, and promoting a habit
of unit testing is good, even for trivial, home-grown stuff.


namenob...@gmail.com

unread,
Nov 25, 2017, 2:59:12 PM11/25/17
to
On Saturday, November 25, 2017 at 5:00:12 AM UTC-8, bartc wrote:

> Actually I've no idea what these tests are supposed to prove.

me neither; i think you guys may be getting me out of my depth now


> They are to do with one class called 'infinity', which is never used in the rest
> of the program apart from one line.
>
> I established that within a few seconds, and I would concentrate on what
> 'infinity' is actually for, rather than go to considerable lengths to
> test a class that may not actually be needed.

my current version of "infinity" looks like this

class Infinity:
def __init__(self,signum): self.signum = (+1) if signum > 0 else (-1)
def __repr__(self): return '+oo' if self.signum == (+1) else '-oo'
def __lt__(self,other): return self.signum == (-1)
def __le__(self,other): return self.signum == (-1)
def __gt__(self,other): return self.signum == (+1)
def __ge__(self,other): return self.signum == (+1)
def __eq__(self,other): return isinstance(other,Infinity) and self.signum == other.signum

the idea is that there should be exactly one object posinf (positive infinity) that compares as strictly greater than any number ever considered, and exactly one object neginf that compares as strictly less; as the code stands now there is no reason not to use +/-70 in that capacity; the "infinity" class is there so that the game-playing parts of the code (which at present are intentionally as primitive as possible) can be modified more smoothly later; the single place where "infinity" is instantiated is in the function "getvalue", which returns the value of a finished game:

def getvalue(winner,accessibles):
return Infinity(+1) if winner == ex else Infinity(-1) if winner == oh else 0 if not accessibles else None

if ex has won then the value of the game is posinf; if oh has won then it's neginf; if the game is tied (no winner but no accessible columns remaining) then the value of the game is zero; otherwise the game is not finished and its finished value is None

peace
stm







namenob...@gmail.com

unread,
Nov 25, 2017, 3:27:03 PM11/25/17
to
On Friday, November 24, 2017 at 8:07:07 AM UTC-8, Chris Angelico wrote:

> This is the kind of function that needs a docstring and some comments.
> What exactly is this doing? What are the "lines" of the board? What's
> the difference between "linear" and "lines"? What exactly is it
> returning?

producing documentation is an extremely difficult task for me, but i've come up with the following:

"""
makelines(length,numrows,numcolumns) IS THE LIST OF ALL LISTS L, WITH LENGTH length, OF COORDINATES
FROM A numrows x numcolumns MATRIX, SUCH THAT THE ENTRIES OF L ALL LIE IN A LINE:

LET horizontal BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A HORIZONTAL LINE
LET vertical BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A VERTICAL LINE
LET downward BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A DOWNWARD-SLOPING DIAGONAL LINE
LET upward BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN AN UPWARD-SLOPING DIAGONAL LINE
THEN makelines(length,numrows,numcolumns) IS THE UNION OF ALL THE AFOREMENTIONED SETS
"""

def makelines(length,numrows,numcolumns):
horizontal = [[(i, j+k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)]
vertical = [[(i+k, j) for k in range(length)] for i in range(numrows) for j in range(numcolumns)]
downward = [[(i+k, j+k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)]
upward = [[(i+k, j-k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)]
linear = horizontal + vertical + downward + upward
return [line for line in linear if all(i in range(6) and j in range(7) for (i,j) in line)]

def getlines(board):
coordlines = makelines(4,6,7) ## GLOBAL
return [[board[square] for square in line] for line in coordlines


i tried to remove all the superfluous spaces from that, but lining up code vertically is very helpful to me, so i don't think i can really dispense with the practice

peace
stm

namenob...@gmail.com

unread,
Nov 25, 2017, 4:57:21 PM11/25/17
to
On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote:

> I did, and it looks buggy to me. The top and left frame lines are
> missing. If I click a square, the bottom square in the column lights
> up. But then I have no idea whether those are your intentions or not.

i hadn't noticed about the frame lines, but it's the same for me; but i'm hoping you meant to write that the TOP square in a column flashes when you "drop a token" down that column; if you really meant the bottom one then i'm totally baffled that it could be the top one for me and the bottom one for you ... is that something that can happen because of a bug?

sorry if you were offended by what i wrote before; i didn't understand what you meant

peace
stm

Terry Reedy

unread,
Nov 25, 2017, 6:50:21 PM11/25/17
to
On 11/25/2017 4:57 PM, namenob...@gmail.com wrote:
> On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote:
>
>> I did, and it looks buggy to me. The top and left frame lines are
>> missing. If I click a square, the bottom square in the column lights
>> up. But then I have no idea whether those are your intentions or not.
> i hadn't noticed about the frame lines, but it's the same for me; but i'm hoping you meant to write that the TOP square in a column flashes when you "drop a token" down that column;

All squares start white. Only the bottom square turns red or black,
after perhaps a .3 second delay during which there is some jitter in
white squares above, which could be the effect of white flashing white.

> if you really meant the bottom one then i'm totally baffled that it could be the top one for me and the bottom one for you ... is that something that can happen because of a bug?

I am running on Windows 10 from IDLE (which should not affect your code)
with 3.7.0a2 with tk 8.6.6. The OS and tk version could have an effect,
though top versus bottom is hard to fathom.

--
Terry Jan Reedy

alister

unread,
Nov 26, 2017, 6:24:51 AM11/26/17
to
the documentation should come after the def statement
that way is becomes a "Doc String" & can be accessed using the help
function
you may also want to check out the recommended way of structuring a doc
string, it could help you with your difficulty in writing them (a problem
shared by many)



--
This door is baroquen, please wiggle Handel.
(If I wiggle Handel, will it wiggle Bach?)
-- Found on a door in the MSU music building

bartc

unread,
Nov 26, 2017, 9:12:17 AM11/26/17
to
On 25/11/2017 16:07, Michael Torrie wrote:
> On 11/25/2017 06:00 AM, bartc wrote:
>> And there's a quite lot left of the rest of the program to worry about too!
>>
>> If you add 'window()' at the end of the program, then it seems to run on
>> Python 3. I'd play around with it first before thinking up strategies
>> for testing it.
>
> Actually, no. Unit testing ideally should be done for each and every
> class as they are being written (before they are written in fact), no
> matter how small and trivial the class. That way as you compose larger
> and larger units of code, the chances of things being right is greater
> compared to doing it the other way around.

The way I write code isn't incrementally top down or bottom up. It's
backwards and forwards. Feedback from different parts means the thing
develops as a whole. Sometimes parts are split into distinct sections,
sometimes different parts are merged.

Sometimes you realise you're on the wrong track, and sections have to be
redone or a different approach used, which can be done in the earlier
stages.

If I had to bother with such systematic tests as you suggest, and finish
and sign off everything before proceeding further, then nothing would
ever get done. (Maybe it's viable if working from an exacting
specification that someone else has already worked out.)

I've also found that many of the bugs that do appear, also do so in ways
you never anticipated. Or in circumstances you would never have thought of.

(I've always thought that programming is a bit like creating new laws.
The same laws need to work for everyone and in any circumstances, but no
one can foresee everything, and laws need to be tweaked and added to.
Perhaps unit tests can apply there too...)

> You may argue that testing doesn't matter for his small game, written
> for his own education and amusement. The fact is that software in
> general is of abysmal quality across the boards, and promoting a habit
> of unit testing is good, even for trivial, home-grown stuff.

I thought people were being hard on the OP.

As for testing, I remember in a company I worked in, a complicated
circuit was submitted to a company that would put it into a
mass-produced chip. This company did massive numbers of emulated tests
shown on a huge printout that showed that all combinations of inputs and
outputs worked exactly as intended.

Except the actual chip didn't work. As for the printout, the designer
took it home and used it as an underlay for a new carpet. A rather
expensive underlay.

--
bartc

bartc

unread,
Nov 26, 2017, 9:26:09 AM11/26/17
to
On 25/11/2017 23:49, Terry Reedy wrote:
> On 11/25/2017 4:57 PM, namenob...@gmail.com wrote:
>> On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote:
>>
>>> I did, and it looks buggy to me.  The top and left frame lines are
>>> missing.  If I click a square, the bottom square in the column lights
>>> up.  But then I have no idea whether those are your intentions or not.
>> i hadn't noticed about the frame lines, but it's the same for me; but
>> i'm hoping you meant to write that the TOP square in a column flashes
>> when you "drop a token" down that column;
>
> All squares start white.  Only the bottom square turns red or black,
> after perhaps a .3 second delay during which there is some jitter in
> white squares above, which could be the effect of white flashing white.

There are a couple of lines that look like this:

self.grid.squarebuttons[column].flash()

If you comment out those two lines, then the flashing disappears, and it
still works.

Of course, if I'd used unit tests, I'd have figured that out a lot
sooner. I would just have had the somewhat bigger problem of devising a
unit test that would detect this.


--
bartc

Chris Angelico

unread,
Nov 26, 2017, 9:31:07 AM11/26/17
to
On Mon, Nov 27, 2017 at 1:11 AM, bartc <b...@freeuk.com> wrote:
> The way I write code isn't incrementally top down or bottom up. It's
> backwards and forwards. Feedback from different parts means the thing
> develops as a whole. Sometimes parts are split into distinct sections,
> sometimes different parts are merged.
>
> Sometimes you realise you're on the wrong track, and sections have to be
> redone or a different approach used, which can be done in the earlier
> stages.
>
> If I had to bother with such systematic tests as you suggest, and finish and
> sign off everything before proceeding further, then nothing would ever get
> done. (Maybe it's viable if working from an exacting specification that
> someone else has already worked out.)

Everyone in the world has the same problem, yet many of us manage to
write useful tests. I wonder whether you're somehow special in that
testing fundamentally doesn't work for you, or that you actually don't
need to write tests. Or maybe tests would still be useful for you too.
Could go either way.

> As for testing, I remember in a company I worked in, a complicated circuit
> was submitted to a company that would put it into a mass-produced chip. This
> company did massive numbers of emulated tests shown on a huge printout that
> showed that all combinations of inputs and outputs worked exactly as
> intended.
>
> Except the actual chip didn't work. As for the printout, the designer took
> it home and used it as an underlay for a new carpet. A rather expensive
> underlay.

So there was something else wrong with the chip. I'm not sure what
your point is.

ChrisA

bartc

unread,
Nov 26, 2017, 10:39:33 AM11/26/17
to
On 26/11/2017 14:23, Chris Angelico wrote:
> On Mon, Nov 27, 2017 at 1:11 AM, bartc <b...@freeuk.com> wrote:
>> The way I write code isn't incrementally top down or bottom up. It's
>> backwards and forwards. Feedback from different parts means the thing
>> develops as a whole. Sometimes parts are split into distinct sections,
>> sometimes different parts are merged.
>>
>> Sometimes you realise you're on the wrong track, and sections have to be
>> redone or a different approach used, which can be done in the earlier
>> stages.
>>
>> If I had to bother with such systematic tests as you suggest, and finish and
>> sign off everything before proceeding further, then nothing would ever get
>> done. (Maybe it's viable if working from an exacting specification that
>> someone else has already worked out.)
>
> Everyone in the world has the same problem, yet many of us manage to
> write useful tests. I wonder whether you're somehow special in that
> testing fundamentally doesn't work for you, or that you actually don't
> need to write tests. Or maybe tests would still be useful for you too.
> Could go either way.

Testing everything comprehensively just wouldn't be useful for me who
works on whole applications, whole concepts, not just a handful of
functions with well-defined inputs and outputs. And even then, it might
work perfectly, but be too slow, or they take up too much space.

Take one example of a small program I've mentioned in the past, a jpeg
decoder. I had to port this into several languages (one of which was
Python actually).

It was hard because I didn't know how it was meant to work. Only as a
whole when the input is a .jpeg file, and the output might be a .ppm
file that ought to look like the one produced by a working program, or
the original jpeg displayed by a working viewer. (Which is not possible
in all applications.)

How to do an automatic test? Directly doing a binary compare on the
output doesn't work because in jpeg, there can be differences of +/- 1
bit in the results. And even if the test detected a mismatch, then what?
I now know there is a problem, but I could figure that out by looking at
the output!

And actually, after it ostensibly worked, there WAS a minor problem:
some types of images exhibited excessive chroma noise around sharp
transitions.

The problem was traced to two lines that were in the wrong order (in the
original program). I can't see how unit tests can have helped in any way
at all, and it would probably have taken much longer.

And THIS was a small, well-defined task which had already been written.

>> Except the actual chip didn't work. As for the printout, the designer took
>> it home and used it as an underlay for a new carpet. A rather expensive
>> underlay.
>
> So there was something else wrong with the chip. I'm not sure what
> your point is.

The extensive testing was like unit testing, but needed to be even more
thorough because of the commitment involved. It failed to spot a problem.

And actually I had a similar problem with a new car. I took it back to
the dealer, and they said they plugged the on-board computer into their
analyser, which did all sorts of tests and said there was nothing wrong
with it. But there was, and the problem has persisted for a decade [to
do with the central locking].

I'm saying you can rely too much on these tests, and waste too much time
on them.

Perhaps that is a necessity in a large organisation or in a large team,
where there is a leader to look at the big picture. It doesn't work for
individuals working on one project.

--
bartc

nospam.bartc

unread,
Nov 26, 2017, 2:08:34 PM11/26/17
to
On 25/11/2017 23:49, Terry Reedy wrote:
> On 11/25/2017 4:57 PM, namenob...@gmail.com wrote:
>> On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote:
>>
>>> I did, and it looks buggy to me.â The top and left frame lines are
>>> missing.â If I click a square, the bottom square in the column lights
>>> up.â But then I have no idea whether those are your intentions or not.
>> i hadn't noticed about the frame lines, but it's the same for me; but
>> i'm hoping you meant to write that the TOP square in a column flashes
>> when you "drop a token" down that column;
>
> All squares start white.â Only the bottom square turns red or black,

nospam.bartc

unread,
Nov 26, 2017, 2:08:34 PM11/26/17
to
On 25/11/2017 16:07, Michael Torrie wrote:
> On 11/25/2017 06:00 AM, bartc wrote:
>> And there's a quite lot left of the rest of the program to worry about too!
>>
>> If you add 'window()' at the end of the program, then it seems to run on
>> Python 3. I'd play around with it first before thinking up strategies
>> for testing it.
>
> Actually, no. Unit testing ideally should be done for each and every
> class as they are being written (before they are written in fact), no
> matter how small and trivial the class. That way as you compose larger
> and larger units of code, the chances of things being right is greater
> compared to doing it the other way around.

The way I write code isn't incrementally top down or bottom up. It's backwards
and forwards. Feedback from different parts means the thing develops as a
whole. Sometimes parts are split into distinct sections, sometimes different
parts are merged.

Sometimes you realise you're on the wrong track, and sections have to be redone
or a different approach used, which can be done in the earlier stages.

If I had to bother with such systematic tests as you suggest, and finish and
sign off everything before proceeding further, then nothing would ever get
done. (Maybe it's viable if working from an exacting specification that someone
else has already worked out.)

I've also found that many of the bugs that do appear, also do so in ways you
never anticipated. Or in circumstances you would never have thought of.

(I've always thought that programming is a bit like creating new laws. The same
laws need to work for everyone and in any circumstances, but no one can
foresee everything, and laws need to be tweaked and added to. Perhaps unit
tests can apply there too...)

> You may argue that testing doesn't matter for his small game, written
> for his own education and amusement. The fact is that software in
> general is of abysmal quality across the boards, and promoting a habit
> of unit testing is good, even for trivial, home-grown stuff.

I thought people were being hard on the OP.

As for testing, I remember in a company I worked in, a complicated circuit was
submitted to a company that would put it into a mass-produced chip. This
company did massive numbers of emulated tests shown on a huge printout that
showed that all combinations of inputs and outputs worked exactly as intended.

Except the actual chip didn't work. As for the printout, the designer took it
home and used it as an underlay for a new carpet. A rather expensive underlay.

--
bartc

namenobodywants

unread,
Nov 26, 2017, 2:08:34 PM11/26/17
to
On Saturday, November 25, 2017 at 5:00:12 AM UTC-8, bartc wrote:

> Actually I've no idea what these tests are supposed to prove.

me neither; i think you guys may be getting me out of my depth now


> They are to do with one class called 'infinity', which is never used in the
rest

namenobodywants

unread,
Nov 26, 2017, 2:08:34 PM11/26/17
to
On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote:

> I did, and it looks buggy to me. The top and left frame lines are
> missing. If I click a square, the bottom square in the column lights
> up. But then I have no idea whether those are your intentions or not.

i hadn't noticed about the frame lines, but it's the same for me; but i'm
hoping you meant to write that the TOP square in a column flashes when you
"drop a token" down that column; if you really meant the bottom one then i'm
totally baffled that it could be the top one for me and the bottom one for you
... is that something that can happen because of a bug?

nospam.alister

unread,
Nov 26, 2017, 2:08:34 PM11/26/17
to

nospam.Chris Angelico

unread,
Nov 26, 2017, 2:08:38 PM11/26/17
to
On Mon, Nov 27, 2017 at 1:11 AM, bartc <b...@freeuk.com> wrote:
> The way I write code isn't incrementally top down or bottom up. It's
> backwards and forwards. Feedback from different parts means the thing
> develops as a whole. Sometimes parts are split into distinct sections,
> sometimes different parts are merged.
>
> Sometimes you realise you're on the wrong track, and sections have to be
> redone or a different approach used, which can be done in the earlier
> stages.
>
> If I had to bother with such systematic tests as you suggest, and finish and
> sign off everything before proceeding further, then nothing would ever get
> done. (Maybe it's viable if working from an exacting specification that
> someone else has already worked out.)

Everyone in the world has the same problem, yet many of us manage to write
useful tests. I wonder whether you're somehow special in that testing
fundamentally doesn't work for you, or that you actually don't need to write
tests. Or maybe tests would still be useful for you too. Could go either way.

> As for testing, I remember in a company I worked in, a complicated circuit
> was submitted to a company that would put it into a mass-produced chip. This
> company did massive numbers of emulated tests shown on a huge printout that
> showed that all combinations of inputs and outputs worked exactly as
> intended.
>
> Except the actual chip didn't work. As for the printout, the designer took
> it home and used it as an underlay for a new carpet. A rather expensive
> underlay.

So there was something else wrong with the chip. I'm not sure what your point
is.

ChrisA

nospam.Michael Torrie

unread,
Nov 26, 2017, 2:08:38 PM11/26/17
to
On 11/25/2017 06:00 AM, bartc wrote:
> And there's a quite lot left of the rest of the program to worry about too!
>
> If you add 'window()' at the end of the program, then it seems to run on
> Python 3. I'd play around with it first before thinking up strategies
> for testing it.

Actually, no. Unit testing ideally should be done for each and every class as
they are being written (before they are written in fact), no matter how small
and trivial the class. That way as you compose larger and larger units of
code, the chances of things being right is greater compared to doing it the
other way around.

nospam.Terry Reedy

unread,
Nov 26, 2017, 2:08:38 PM11/26/17
to
On 11/25/2017 4:57 PM, namenob...@gmail.com wrote:
> On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote:
>
>> I did, and it looks buggy to me. The top and left frame lines are
>> missing. If I click a square, the bottom square in the column lights
>> up. But then I have no idea whether those are your intentions or not.
> i hadn't noticed about the frame lines, but it's the same for me; but i'm
hoping you meant to write that the TOP square in a column flashes when you
"drop a token" down that column;

All squares start white. Only the bottom square turns red or black, after
perhaps a .3 second delay during which there is some jitter in white squares
above, which could be the effect of white flashing white.

> if you really meant the bottom one then i'm totally baffled that it could be
the top one for me and the bottom one for you ... is that something that can
happen because of a bug?

namenobodywants

unread,
Nov 26, 2017, 2:08:38 PM11/26/17
to

nospam.bartc

unread,
Nov 26, 2017, 2:08:38 PM11/26/17
to
On 26/11/2017 14:23, Chris Angelico wrote:
> On Mon, Nov 27, 2017 at 1:11 AM, bartc <b...@freeuk.com> wrote:
>> The way I write code isn't incrementally top down or bottom up. It's
>> backwards and forwards. Feedback from different parts means the thing
>> develops as a whole. Sometimes parts are split into distinct sections,
>> sometimes different parts are merged.
>>
>> Sometimes you realise you're on the wrong track, and sections have to be
>> redone or a different approach used, which can be done in the earlier
>> stages.
>>
>> If I had to bother with such systematic tests as you suggest, and finish and
>> sign off everything before proceeding further, then nothing would ever get
>> done. (Maybe it's viable if working from an exacting specification that
>> someone else has already worked out.)
>
> Everyone in the world has the same problem, yet many of us manage to
> write useful tests. I wonder whether you're somehow special in that
> testing fundamentally doesn't work for you, or that you actually don't
> need to write tests. Or maybe tests would still be useful for you too.
> Could go either way.

Testing everything comprehensively just wouldn't be useful for me who works on
whole applications, whole concepts, not just a handful of functions with
well-defined inputs and outputs. And even then, it might work perfectly, but be
too slow, or they take up too much space.

Take one example of a small program I've mentioned in the past, a jpeg decoder.
I had to port this into several languages (one of which was Python actually).

It was hard because I didn't know how it was meant to work. Only as a whole
when the input is a .jpeg file, and the output might be a .ppm file that ought
to look like the one produced by a working program, or the original jpeg
displayed by a working viewer. (Which is not possible in all applications.)

How to do an automatic test? Directly doing a binary compare on the output
doesn't work because in jpeg, there can be differences of +/- 1 bit in the
results. And even if the test detected a mismatch, then what? I now know there
is a problem, but I could figure that out by looking at the output!

And actually, after it ostensibly worked, there WAS a minor problem: some types
of images exhibited excessive chroma noise around sharp transitions.

The problem was traced to two lines that were in the wrong order (in the
original program). I can't see how unit tests can have helped in any way at
all, and it would probably have taken much longer.

And THIS was a small, well-defined task which had already been written.

>> Except the actual chip didn't work. As for the printout, the designer took
>> it home and used it as an underlay for a new carpet. A rather expensive
>> underlay.
>
> So there was something else wrong with the chip. I'm not sure what
> your point is.

nospam.nospam.Michael Torrie

unread,
Nov 26, 2017, 3:07:37 PM11/26/17
to

nospam.nospam.Terry Reedy

unread,
Nov 26, 2017, 3:07:37 PM11/26/17
to

namenobodywants namenobodywants

unread,
Nov 26, 2017, 3:07:37 PM11/26/17
to
On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote:

> I did, and it looks buggy to me. The top and left frame lines are
> missing. If I click a square, the bottom square in the column lights
> up. But then I have no idea whether those are your intentions or not.

i hadn't noticed about the frame lines, but it's the same for me; but i'm
hoping you meant to write that the TOP square in a column flashes when you
"drop a token" down that column; if you really meant the bottom one then i'm
totally baffled that it could be the top one for me and the bottom one for you
... is that something that can happen because of a bug?

nospam.nospam.alister

unread,
Nov 26, 2017, 3:07:37 PM11/26/17
to
On Sat, 25 Nov 2017 12:26:52 -0800, namenobodywants wrote:

nospam.nospam.bartc

unread,
Nov 26, 2017, 3:07:37 PM11/26/17
to

nospam.nospam.bartc

unread,
Nov 26, 2017, 3:07:37 PM11/26/17
to
On 25/11/2017 23:49, Terry Reedy wrote:
> On 11/25/2017 4:57 PM, namenob...@gmail.com wrote:
>> On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote:
>>
>>> I did, and it looks buggy to me.â The top and left frame lines are
>>> missing.â If I click a square, the bottom square in the column lights
>>> up.â But then I have no idea whether those are your intentions or not.
>> i hadn't noticed about the frame lines, but it's the same for me; but
>> i'm hoping you meant to write that the TOP square in a column flashes
>> when you "drop a token" down that column;
>
> All squares start white.â Only the bottom square turns red or black,
> after perhaps a .3 second delay during which there is some jitter in
> white squares above, which could be the effect of white flashing white.

nospam.nospam.bartc

unread,
Nov 26, 2017, 3:07:42 PM11/26/17
to
On 25/11/2017 16:07, Michael Torrie wrote:
> On 11/25/2017 06:00 AM, bartc wrote:
>> And there's a quite lot left of the rest of the program to worry about too!
>>
>> If you add 'window()' at the end of the program, then it seems to run on
>> Python 3. I'd play around with it first before thinking up strategies
>> for testing it.
>
> Actually, no. Unit testing ideally should be done for each and every
> class as they are being written (before they are written in fact), no
> matter how small and trivial the class. That way as you compose larger
> and larger units of code, the chances of things being right is greater
> compared to doing it the other way around.

The way I write code isn't incrementally top down or bottom up. It's backwards
and forwards. Feedback from different parts means the thing develops as a
whole. Sometimes parts are split into distinct sections, sometimes different
parts are merged.

Sometimes you realise you're on the wrong track, and sections have to be redone
or a different approach used, which can be done in the earlier stages.

If I had to bother with such systematic tests as you suggest, and finish and
sign off everything before proceeding further, then nothing would ever get
done. (Maybe it's viable if working from an exacting specification that someone
else has already worked out.)

I've also found that many of the bugs that do appear, also do so in ways you
never anticipated. Or in circumstances you would never have thought of.

(I've always thought that programming is a bit like creating new laws. The same
laws need to work for everyone and in any circumstances, but no one can
foresee everything, and laws need to be tweaked and added to. Perhaps unit
tests can apply there too...)

> You may argue that testing doesn't matter for his small game, written
> for his own education and amusement. The fact is that software in
> general is of abysmal quality across the boards, and promoting a habit
> of unit testing is good, even for trivial, home-grown stuff.

I thought people were being hard on the OP.

As for testing, I remember in a company I worked in, a complicated circuit was
submitted to a company that would put it into a mass-produced chip. This
company did massive numbers of emulated tests shown on a huge printout that
showed that all combinations of inputs and outputs worked exactly as intended.

Except the actual chip didn't work. As for the printout, the designer took it
home and used it as an underlay for a new carpet. A rather expensive underlay.

--
bartc

namenobodywants namenobodywants

unread,
Nov 26, 2017, 3:07:42 PM11/26/17
to

namenobodywants namenobodywants

unread,
Nov 26, 2017, 3:07:42 PM11/26/17
to
On Saturday, November 25, 2017 at 5:00:12 AM UTC-8, bartc wrote:

> Actually I've no idea what these tests are supposed to prove.

me neither; i think you guys may be getting me out of my depth now


> They are to do with one class called 'infinity', which is never used in the
rest

Gregory Ewing

unread,
Nov 26, 2017, 5:53:14 PM11/26/17
to
bartc wrote:
> (Maybe it's viable if working from an exacting
> specification that someone else has already worked out.)

In my experience, for anything non-trivial that hasn't been
done before, these "exacting specifications" never exist.
Even if someone handles wnat they *think* are exact and
complete specifications, they're not. :-)

--
Greg

Gregory Ewing

unread,
Nov 26, 2017, 6:08:18 PM11/26/17
to
Chris Angelico wrote:

> On Mon, Nov 27, 2017 at 1:11 AM, bartc <b...@freeuk.com> wrote:
>
>>If I had to bother with such systematic tests as you suggest, and finish and
>>sign off everything before proceeding further, then nothing would ever get
>>done. (Maybe it's viable if working from an exacting specification that
>>someone else has already worked out.)
>
> I wonder whether you're somehow special in that
> testing fundamentally doesn't work for you, or that you actually don't
> need to write tests.

I think the point is that a strict test-first discipline goes
against the grain of exploratory programming.

When you're not sure how to approach a problem, it's useful
to be able to quickly try things out. If you have to write a
bunch of tests for every little thing before you can write
the code for it, you can end up writing a lot of tests for
code that never ends up getting used. That's a good way to
kill all your enthusiasm for a project.

Also, stopping to write tests all the time interrupts your
flow of thought. You're deep into details of the solution,
you realise you need class X, then you have to stop and write
tests for X. That makes you think a lot about all the details
of X, and by the time you're finished you've lost track of
the big picture.

I don't think anyone disputes that having a reasonably
complete set of tests is a good thing. The argument is
about whether it's strictly necessary to write the tests
*first* in all cases.

Maybe you find it's a useful discipline that helps ensure
the tests get written. That's fine, but it doesn't mean that
*everyone* should be forced to do it that way all the time,
even if they're just programming for a hobby. That's confusing
the desired end result with a particular means of achieving
it.

--
Greg

Chris Angelico

unread,
Nov 26, 2017, 6:13:14 PM11/26/17
to
On Mon, Nov 27, 2017 at 10:08 AM, Gregory Ewing
<greg....@canterbury.ac.nz> wrote:
> Chris Angelico wrote:
>
>> On Mon, Nov 27, 2017 at 1:11 AM, bartc <b...@freeuk.com> wrote:
>
>>
>>>
>>> If I had to bother with such systematic tests as you suggest, and finish
>>> and
>>> sign off everything before proceeding further, then nothing would ever
>>> get
>>> done. (Maybe it's viable if working from an exacting specification that
>>> someone else has already worked out.)
>>
>>
>> I wonder whether you're somehow special in that
>> testing fundamentally doesn't work for you, or that you actually don't
>> need to write tests.
>
>
> I think the point is that a strict test-first discipline goes
> against the grain of exploratory programming.
>
> When you're not sure how to approach a problem, it's useful
> to be able to quickly try things out. If you have to write a
> bunch of tests for every little thing before you can write
> the code for it, you can end up writing a lot of tests for
> code that never ends up getting used. That's a good way to
> kill all your enthusiasm for a project.

I agree, and that's why I don't tend to go for TDD. But writing tests
afterwards is a good thing, something I think bartc seems to disagree
with.

ChrisA

Gregory Ewing

unread,
Nov 26, 2017, 6:46:52 PM11/26/17
to
bartc wrote:
> Testing everything comprehensively just wouldn't be useful for me who
> works on whole applications, whole concepts, not just a handful of
> functions with well-defined inputs and outputs.

I had this experience with Pyrex (the precursor to Cython).
The various parts are so interdependent that it doesn't really
make sense to test individual classes or methods on their own.
It would require a huge amount of scaffolding and wouldn't
really prove much.

Instead, what I did was write tests for units of *functionality*.
(Can it compile an assignment statement? An expression that adds
two things? Subtracts them? etc.) I wrote a very large number of
them, plus a test framework to run them and compare the output
with known good output.

I can't claim that I always wrote the tests *first* (sometimes
I did, sometimes I didn't). But I never had any trouble motivating
myself to write the tests. Partly this is because the way my
test framework worked, there was very little difference between
a manual test and an automated one. I had to write a test file
to test it at all, and having done that, it was just as easy
to save it away together with its output so that it became
part of the automated test suite.

It was also partly because the benefits of having a comprehensive
automatic test suite were so blindingly obvious in that project.
Its complexity meant that it was particularly easy to break
something accidentally when adding a new feature. If that
happened, the tests would almost certainly pick it up immediately.
Without those tests, I would never have been able to develop
it to the point I did.

>> So there was something else wrong with the chip. I'm not sure what
>> your point is.
>
> The extensive testing was like unit testing, but needed to be even more
> thorough because of the commitment involved. It failed to spot a problem.

Testing obviously isn't guaranteed to find all problems in
a system with complex behaviour, but that doesn't mean
testing is useless. It would have been hugely more risky to
go ahead and build the chip without testing the design at
all!

BTW, hardware is a bit different from software. It's possible
for a design to be *logically* correct and pass all the
simulations, but for the hardware to fail for messy physics-
related reasons. (Charles Moore tells a story like that about
one of his Forth chips. A transistor driving a particular
signal was too small, and if you executed a particular
instruction too many times in too short a time interval,
it would overheat and produce incorrect results.)

--
Greg

Michael Torrie

unread,
Nov 26, 2017, 9:55:56 PM11/26/17
to
On 11/26/2017 07:11 AM, bartc wrote:
>> You may argue that testing doesn't matter for his small game, written
>> for his own education and amusement. The fact is that software in
>> general is of abysmal quality across the boards, and promoting a habit
>> of unit testing is good, even for trivial, home-grown stuff.
>
> I thought people were being hard on the OP.

I wasn't being hard on the OP. My observation is about the state of
*all* software. My software especially, your software, Microsoft's
software. It all is of rather poor quality compared to the rigors of
other industries like civil engineering, manufacturing, etc.

> As for testing, I remember in a company I worked in, a complicated
> circuit was submitted to a company that would put it into a
> mass-produced chip. This company did massive numbers of emulated tests
> shown on a huge printout that showed that all combinations of inputs and
> outputs worked exactly as intended.
>
> Except the actual chip didn't work. As for the printout, the designer
> took it home and used it as an underlay for a new carpet. A rather
> expensive underlay.

That's unfortunately, but seems to reinforce the notion that adequate
testing is required. Clearly for a microchip, theoretically testing the
chip's "software" (for lack of a better term) was not adequate. An
analogy to our software situation is that someone tested the algorithm,
but not the actual, in-use implementation of the algorithm.

Michael Torrie

unread,
Nov 26, 2017, 10:04:59 PM11/26/17
to
On 11/26/2017 08:39 AM, bartc wrote:
> The problem was traced to two lines that were in the wrong order (in the
> original program). I can't see how unit tests can have helped in any way
> at all, and it would probably have taken much longer.

What makes you think that? Surely other decoders were doing the right
thing and you could compare your output against theirs? JPEGs may be
lossy but the path through the decoder should be deterministic.

Or even if every decoder is slightly unique, at least yours should
output self-consistent data. In other words, once you know you fixed
the chroma problem, you can use that jpeg as a unit test to make sure
future big fixes and enhancements don't break something else.
Regression testing is very important. Many times I've fixed a bug, only
to introduce new ones that broke formerly correct behavior.

Anyway, unit testing is certainly a challenging concept, and I'm no more
good at it than you are.

Michael Torrie

unread,
Nov 26, 2017, 10:09:25 PM11/26/17
to
On 11/25/2017 12:58 PM, namenob...@gmail.com wrote:
> the idea is that there should be exactly one object posinf (positive infinity) that compares as strictly greater than any number ever considered, and exactly one object neginf that compares as strictly less; as the code stands now there is no reason not to use +/-70 in that capacity; the "infinity" class is there so that the game-playing parts of the code (which at present are intentionally as primitive as possible) can be modified more smoothly later; the single place where "infinity" is instantiated is in the function "getvalue", which returns the value of a finished game:
>
> def getvalue(winner,accessibles):
> return Infinity(+1) if winner == ex else Infinity(-1) if winner == oh else 0 if not accessibles else None
>
> if ex has won then the value of the game is posinf; if oh has won then it's neginf; if the game is tied (no winner but no accessible columns remaining) then the value of the game is zero; otherwise the game is not finished and its finished value is None

So you are using this Infinity class as a sentinel value of some kind?
Representing game state? There may be an easier way than a full on
custom type. Sometimes just a sentinel object is sufficient. Or an
enumeration.

Chris Angelico

unread,
Nov 26, 2017, 10:38:42 PM11/26/17
to
On Mon, Nov 27, 2017 at 1:55 PM, Michael Torrie <tor...@gmail.com> wrote:
> On 11/26/2017 07:11 AM, bartc wrote:
>>> You may argue that testing doesn't matter for his small game, written
>>> for his own education and amusement. The fact is that software in
>>> general is of abysmal quality across the boards, and promoting a habit
>>> of unit testing is good, even for trivial, home-grown stuff.
>>
>> I thought people were being hard on the OP.
>
> I wasn't being hard on the OP. My observation is about the state of
> *all* software. My software especially, your software, Microsoft's
> software. It all is of rather poor quality compared to the rigors of
> other industries like civil engineering, manufacturing, etc.

Not all software is poor quality compared to all examples of those
industries. You'll find the equivalent of software bugs in a lot of
hardware situations; the difference with software is that we have 100%
perfect reproduction in the end-user products, so we call it a design
flaw instead of a production artifact. (How often do you buy a box of
something and find that a couple of them just break?) Even in
large-scale civil engineering projects, there are plenty of
stupidities. The house I'm living in has a place where the tiled floor
doesn't quite align with the wall that it meets, and I can't figure
out why; somewhere, two things that ought to have been parallel just
aren't. Bridges have been known to crack, cars break down for no good
reason, your hamburger just doesn't taste right today.

Aviators have pinned down the best solution to this, I think. A pilot
is not expected to be perfect; he is expected to follow checklists. A
preflight checklist. A departure checklist. A landing checklist.
Everything that needs to be done right is mentioned on the list, and
you just go through the list and make sure you've done everything.
Interestingly enough, that approximately corresponds to unit testing
(or maybe integration testing) - you design a suite of tests, and
every time you do something, you make sure all the tests pass. Neither
test suites nor checklists can prevent all problems - but they CAN
prevent the same problems from cropping up again and again. (Which is
kinda important when you're dealing with airliners carrying hundreds
of people. They crash very rarely because the crew follow their
checklists religiously, and when they do, there's an investigation
that can result in new tests being added.)

ChrisA

Rustom Mody

unread,
Nov 26, 2017, 11:04:34 PM11/26/17
to
On Monday, November 27, 2017 at 9:08:42 AM UTC+5:30, Chris Angelico wrote:
And thats where the analogy breaks down.
Presumably a 50 person short-flight and a 600-person transcontinental may have
at least something in common in their pilot-checklists
What common will you find in a multi-million line OS, a thousand line script
and a student prime-numbers first-program?

No I am not dissing on testing and TDD; just that universality¹ of computing devices
is something that our civilization is nowhere near understanding, leave alone
dealing with — two programs can be more far apart than a bullock cart and a jet.
And yet they are both programs

¹ Ive seen CS PhDs ask a student why a student didnt incorporate some error-checking
into his compiler which amounted to solving the halting problem.
More mundanely I see students have a hard time seeing their phones and their
laptops as 'the same'

Chris Angelico

unread,
Nov 27, 2017, 1:42:24 AM11/27/17
to
On Mon, Nov 27, 2017 at 3:04 PM, Rustom Mody <rusto...@gmail.com> wrote:
>> Aviators have pinned down the best solution to this, I think. A pilot
>> is not expected to be perfect; he is expected to follow checklists. A
>> preflight checklist. A departure checklist. A landing checklist.
>> Everything that needs to be done right is mentioned on the list, and
>> you just go through the list and make sure you've done everything.
>
> And thats where the analogy breaks down.
> Presumably a 50 person short-flight and a 600-person transcontinental may have
> at least something in common in their pilot-checklists
> What common will you find in a multi-million line OS, a thousand line script
> and a student prime-numbers first-program?

You locate a pure function. I can pretty much guarantee that the first
two will have a number of them, and the third one may or may not, but
almost certainly should. Pure functions are the easiest to unit-test.
Then you build up from there.

> No I am not dissing on testing and TDD; just that universality¹ of computing devices
> is something that our civilization is nowhere near understanding, leave alone
> dealing with — two programs can be more far apart than a bullock cart and a jet.
> And yet they are both programs

... so?

> ¹ Ive seen CS PhDs ask a student why a student didnt incorporate some error-checking
> into his compiler which amounted to solving the halting problem.
> More mundanely I see students have a hard time seeing their phones and their
> laptops as 'the same'

Again: so? Testing methodologies don't require that.

ChrisA

namenob...@gmail.com

unread,
Nov 27, 2017, 5:02:01 AM11/27/17
to
On Sunday, November 26, 2017 at 7:09:25 PM UTC-8, Michael Torrie wrote:

> So you are using this Infinity class as a sentinel value of some kind?
> Representing game state? There may be an easier way than a full on
> custom type. Sometimes just a sentinel object is sufficient. Or an
> enumeration.

they're not sentinels; they're the maximum and minimum of the extended real numbers; the point is that, no matter how boards are evaluated (which is, of course, subject to change), a won game is always the most valuable and a lost game is always the least valuable; ordinary real numbers could be used for the purpose, but in that case i would have to figure out the maximum and minimum of the heuristic values the script assigns and then add/subtract one (for example) to get the value of a won/lost game

peace
stm

Chris Angelico

unread,
Nov 27, 2017, 5:10:56 AM11/27/17
to
Or you could use the floating-point values for positive and negative
infinity, which already compare as you need with all integers and
floats. But that's up to you.

ChrisA

bartc

unread,
Nov 27, 2017, 6:38:48 AM11/27/17
to
On 27/11/2017 03:04, Michael Torrie wrote:
> On 11/26/2017 08:39 AM, bartc wrote:
>> The problem was traced to two lines that were in the wrong order (in the
>> original program). I can't see how unit tests can have helped in any way
>> at all, and it would probably have taken much longer.
>
> What makes you think that? Surely other decoders were doing the right
> thing and you could compare your output against theirs? JPEGs may be
> lossy but the path through the decoder should be deterministic.
>
> Or even if every decoder is slightly unique, at least yours should
> output self-consistent data.

The original used some floating point code, I changed that to use
integer code (eg a combination of multiplying and shifting; it make a
difference on compiled version, perhaps not so much in .py).

But also (IIRC) there was a difference in taking the remainder of
negative integer division, where different compilers may round up or down.

So there can easily be differences when compared at the binary level,
but which shouldn't be noticeable with the human eye.

(https://pastebin.com/P7V1Bvkk
https://pastebin.com/raw/P7V1Bvkk raw version with no ads, or colour)

In other words, once you know you fixed
> the chroma problem, you can use that jpeg as a unit test to make sure
> future big fixes and enhancements don't break something else.
> Regression testing is very important. Many times I've fixed a bug, only
> to introduce new ones that broke formerly correct behavior.
>
> Anyway, unit testing is certainly a challenging concept, and I'm no more
> good at it than you are.

Some people are obsessed with having unit tests. Others are the same
about using debuggers, especially in compiled code.

I've never used either, but I do alright. Some of the stuff I do is
unsuitable for those for technical reasons, but also some of the
problems I've come across just don't fit into such patterns.

People should use what works best for them, unless they're in a team
where the have to use certain tools and working methods.


--
bartc

namenob...@gmail.com

unread,
Nov 27, 2017, 7:43:21 AM11/27/17
to
On Monday, November 27, 2017 at 2:10:56 AM UTC-8, Chris Angelico wrote:

> Or you could use the floating-point values for positive and negative
> infinity

perfecto! thank you!

peace
stm

Rustom Mody

unread,
Nov 27, 2017, 8:35:20 AM11/27/17
to
On Monday, November 27, 2017 at 12:12:24 PM UTC+5:30, Chris Angelico wrote:
> On Mon, Nov 27, 2017 at 3:04 PM, Rustom Mody wrote:
> >> Aviators have pinned down the best solution to this, I think. A pilot
> >> is not expected to be perfect; he is expected to follow checklists. A
> >> preflight checklist. A departure checklist. A landing checklist.
> >> Everything that needs to be done right is mentioned on the list, and
> >> you just go through the list and make sure you've done everything.
> >
> > And thats where the analogy breaks down.
> > Presumably a 50 person short-flight and a 600-person transcontinental may have
> > at least something in common in their pilot-checklists
> > What common will you find in a multi-million line OS, a thousand line script
> > and a student prime-numbers first-program?
>
> You locate a pure function. I can pretty much guarantee that the first
> two will have a number of them, and the third one may or may not, but
> almost certainly should. Pure functions are the easiest to unit-test.
> Then you build up from there.
>
> > No I am not dissing on testing and TDD; just that universality¹ of computing devices
> > is something that our civilization is nowhere near understanding, leave alone
> > dealing with — two programs can be more far apart than a bullock cart and a jet.
> > And yet they are both programs
>
> ... so?

I know how to drive a car… and various two-wheelers.
I not so sure of a bus/truck… I suppose I could get one from here to there
at a pinch… without killing someone… though not quite sure of that!
Doesn't translate into knowing how to 'drive' planes or bullock-carts


gcc is tested with dejagnu. Do you imagine that knowing python's unittest or
nose directly translates into dejagnu expertise?
And even if we stay with industry-strength programs — gcc, linux-kernel,
CPython, KDE — do you imagine that testing one helps in testing the other?
I doubt it (though I am hardly an expert with testing frameworks)

Once again let me end by saying that testing and TDD are good ideas
And it would be nice if there was more of it in/for python
[See http://osherove.com/tdd-kata-1/ one of the first hits that google
gives (me) for TDD python, and you find the python example
actually shows Ruby!]

Chris Angelico

unread,
Nov 27, 2017, 9:05:59 AM11/27/17
to
On Mon, Nov 27, 2017 at 10:38 PM, bartc <b...@freeuk.com> wrote:
> On 27/11/2017 03:04, Michael Torrie wrote:
>>
>> On 11/26/2017 08:39 AM, bartc wrote:
>>>
>>> The problem was traced to two lines that were in the wrong order (in the
>>> original program). I can't see how unit tests can have helped in any way
>>> at all, and it would probably have taken much longer.
>>
>>
>> What makes you think that? Surely other decoders were doing the right
>> thing and you could compare your output against theirs? JPEGs may be
>> lossy but the path through the decoder should be deterministic.
>>
>> Or even if every decoder is slightly unique, at least yours should
>> output self-consistent data.
>
>
> The original used some floating point code, I changed that to use integer
> code (eg a combination of multiplying and shifting; it make a difference on
> compiled version, perhaps not so much in .py).

The JPEG spec says what a given file should decode to. So you can use
a reference implementation to confirm that your code is correctly
decoding. Even if you might legitimately encode the same image in
different ways, each of those encoded files should decode to one exact
image, regardless of which decoder is used.

Your decoder was straight-up buggy, and tests would have proven this.

> But also (IIRC) there was a difference in taking the remainder of negative
> integer division, where different compilers may round up or down.

In every compiler, interpreter, and CPU that I've ever used, the
remainder has been well-defined. In what situation was it ill-defined,
such that different compilers could do different things?

> Some people are obsessed with having unit tests. Others are the same about
> using debuggers, especially in compiled code.
>
> I've never used either, but I do alright. Some of the stuff I do is
> unsuitable for those for technical reasons, but also some of the problems
> I've come across just don't fit into such patterns.
>
> People should use what works best for them, unless they're in a team where
> the have to use certain tools and working methods.

Yep, and if "producing buggy code that fails to comply with the spec"
is what works best for you, then please don't tell us that we're
advocating the wrong thing. Testing might not fix everything, but it
does help, especially in those easy cases where you're working with a
pure function that has a single correct output for a given input.
Which, if I'm not misunderstanding the specs, is the case for pretty
much every compression scheme in current use - including JPEG.

For myself, I don't write as many tests as I should. But I'm not going
to go around telling people that tests are a waste of time.

ChrisA

Ian Kelly

unread,
Nov 27, 2017, 9:52:29 AM11/27/17
to
On Nov 27, 2017 7:08 AM, "Chris Angelico" <ros...@gmail.com> wrote:


In every compiler, interpreter, and CPU that I've ever used, the
remainder has been well-defined. In what situation was it ill-defined,
such that different compilers could do different things?


In C89 the result of integer division and modulo with negative operands
were implementation-defined -- the result of division could be either
floored or truncated, and the modulo result also varied to match.

This was fixed in C99, with division results always being truncated
(whereas Python uses the floor).

bartc

unread,
Nov 27, 2017, 10:14:36 AM11/27/17
to
On 27/11/2017 13:57, Chris Angelico wrote:
> On Mon, Nov 27, 2017 at 10:38 PM, bartc <b...@freeuk.com> wrote:


> Your decoder was straight-up buggy, and tests would have proven this.

I created my Python version after the abysmal results from other Python
decoders I tried which didn't work at all, gave the wrong results,
didn't support other subsampling ratios, or hung. Or if they did work,
they took forever.

I suggest you compare my version with some of those.

The first time I looked at a jpeg decoder, it was a massive C library of
about 30 different source files. Sometimes you need to take short-cuts.
My version generates images which are indistinguishable from those
derived via other decoders.

>> But also (IIRC) there was a difference in taking the remainder of negative
>> integer division, where different compilers may round up or down.
>
> In every compiler, interpreter, and CPU that I've ever used, the
> remainder has been well-defined. In what situation was it ill-defined,
> such that different compilers could do different things?

In certain C implementations, rounding the results of integer division
could go up or down. This is a post from comp.lang.c from 2008:

"Nate Eldredge" <na...@vulcan.lan> wrote in message
news:8663mf1...@vulcan.lan...

> Mr. Burns <bu...@snpp.invalid> writes:
>
>> Hi group,
>>
>> suppose I have a grid of cells of size (R,C) and coordinates
>> (0..R-1,0..C-1) and
>> I'm translating pixel coordinates to grid coordinates by dividing by
cell
>> size.
>>
>> Now, all works well for values >= 0, but for values < 0 I'm getting
>> inconsistent results.
>>
>> On one platform, division of negative numbers rounds towards negative
>> infinity, i.e., (-1 / 10) gives -1. (this is what I want)
>>
>> On another platform (solaris), rounding is towards zero, and (-1 /
10) is
>> 0!
>>
>> All numbers are plain ints.
>
> The C99 standard specifies truncation towards zero (like your Solaris
> compiler). However, the previous C90 standard left it up to the
> implementation to decide which way to round when one of the operands is
> negative, as long as it is consistent with the % operator.


Exactly what the problem was with my jpeg program where a number from my
language and compiler ended up as 187, but on C compiled with gcc as
186, I can't remember. I /think/ it was to do with such rounding.

This is not a big deal: one program ends up with a pixel value of 186
(in a range of 0 to 255), and another with 187. The true value in the
original photo may have required a value somewhere between 186 and 187,
so both values could be considered wrong!

> Which, if I'm not misunderstanding the specs, is the case for pretty
> much every compression scheme in current use - including JPEG.

JPEG uses lossy compression. The resulting recovered data is an
approximation of the original.

> For myself, I don't write as many tests as I should. But I'm not going
> to go around telling people that tests are a waste of time.

I'm fairly certain the OP's program didn't work perfectly first time. So
some procedure had to be followed to try it and decide if it behaved
according to the specification they had in mind.

I believe that process can also be called 'testing'. And in this case,
involving a visual GUI, it really demands tests verified by a human
rather than spending the next six months writing automatic test
procedures that simulate mouse input and examine the pixels on the
screen to see if they correspond to what should happen.

> Your decoder was straight-up buggy, and tests would have proven this.

How did YOU determine it was buggy; unit-tests? And did you just do what
everyone else does?

--
Bartc

Chris Angelico

unread,
Nov 27, 2017, 12:42:27 PM11/27/17
to
On Tue, Nov 28, 2017 at 2:14 AM, bartc <b...@freeuk.com> wrote:
> JPEG uses lossy compression. The resulting recovered data is an
> approximation of the original.

Ah but it is a perfect representation of the JPEG stream. Any given
compressed stream must always decode to the same output. The lossiness
is on the ENcoding, not the DEcoding.

ChrisA

bartc

unread,
Nov 27, 2017, 1:57:33 PM11/27/17
to
You make it sound as bad as currency calculations where different
software must produce results that always match to the nearest cent.

We're talking about perhaps +1 or -1 difference in the least significant
bit of one channel of one pixels. If the calculation is consistent, then
you will not know anything is amiss.

By +1 or -1, I mean compared with the same jpeg converted by independent
means.

I also passed the same jpeg through another C program (not mine) using
its own algorithms. There some pixels varied by up to +/- 9 from the
others (looking at the first 512 bytes of the conversion to ppm).

Here's my test image:
https://github.com/bartg/langs/blob/master/card2.jpg (nothing naughty).

Tell me what the definitive values of the pixels in this part of the
image should be (I believe this corresponds to roughly the leftmost 180
pixels of the top line; there are two million pixels in all). And tell
me WHY you think those are the definitive ones.

Bear in mind also that this is not intended to be the world's most
perfect software. But it does do a good enough job. And the other two
Python versions I have, at the minute don't work at all.


--
bartc

Ned Batchelder

unread,
Nov 27, 2017, 2:15:48 PM11/27/17
to
Surely the details of JPEG decompression, and the possible presence of
flaws in certain decoders, is beyond the scope of this thread?

--Ned.

nospam.Chris Angelico

unread,
Nov 27, 2017, 5:08:06 PM11/27/17
to
On Mon, Nov 27, 2017 at 10:08 AM, Gregory Ewing
<greg....@canterbury.ac.nz> wrote:

nospam.nospam.nospam.bartc

unread,
Nov 27, 2017, 5:08:06 PM11/27/17
to
On 25/11/2017 23:49, Terry Reedy wrote:
> On 11/25/2017 4:57 PM, namenob...@gmail.com wrote:
>> On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote:
>>
>>> I did, and it looks buggy to me.â The top and left frame lines are
>>> missing.â If I click a square, the bottom square in the column lights
>>> up.â But then I have no idea whether those are your intentions or not.
>> i hadn't noticed about the frame lines, but it's the same for me; but
>> i'm hoping you meant to write that the TOP square in a column flashes
>> when you "drop a token" down that column;
>
> All squares start white.â Only the bottom square turns red or black,
> after perhaps a .3 second delay during which there is some jitter in
> white squares above, which could be the effect of white flashing white.

There are a couple of lines that look like this:

self.grid.squarebuttons[column].flash()

If you comment out those two lines, then the flashing disappears, and it still
works.

Of course, if I'd used unit tests, I'd have figured that out a lot sooner. I
would just have had the somewhat bigger problem of devising a unit test that
would detect this.


--
bartc

nospam.Michael Torrie

unread,
Nov 27, 2017, 5:08:06 PM11/27/17
to
On 11/26/2017 08:39 AM, bartc wrote:
> The problem was traced to two lines that were in the wrong order (in the
> original program). I can't see how unit tests can have helped in any way
> at all, and it would probably have taken much longer.

What makes you think that? Surely other decoders were doing the right thing
and you could compare your output against theirs? JPEGs may be lossy but the
path through the decoder should be deterministic.

Or even if every decoder is slightly unique, at least yours should output
self-consistent data. In other words, once you know you fixed the chroma

nospam.Gregory Ewing

unread,
Nov 27, 2017, 5:08:06 PM11/27/17
to
Chris Angelico wrote:

> On Mon, Nov 27, 2017 at 1:11 AM, bartc <b...@freeuk.com> wrote:
>
>>If I had to bother with such systematic tests as you suggest, and finish and
>>sign off everything before proceeding further, then nothing would ever get
>>done. (Maybe it's viable if working from an exacting specification that
>>someone else has already worked out.)
>
> I wonder whether you're somehow special in that
> testing fundamentally doesn't work for you, or that you actually don't
> need to write tests.

I think the point is that a strict test-first discipline goes against the grain
of exploratory programming.

When you're not sure how to approach a problem, it's useful to be able to
quickly try things out. If you have to write a bunch of tests for every little
thing before you can write the code for it, you can end up writing a lot of
tests for code that never ends up getting used. That's a good way to kill all
your enthusiasm for a project.

nospam.Chris Angelico

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
On Mon, Nov 27, 2017 at 10:38 PM, bartc <b...@freeuk.com> wrote:
> On 27/11/2017 03:04, Michael Torrie wrote:
>>
>> On 11/26/2017 08:39 AM, bartc wrote:
>>>
>>> The problem was traced to two lines that were in the wrong order (in the
>>> original program). I can't see how unit tests can have helped in any way
>>> at all, and it would probably have taken much longer.
>>
>>
>> What makes you think that? Surely other decoders were doing the right
>> thing and you could compare your output against theirs? JPEGs may be
>> lossy but the path through the decoder should be deterministic.
>>
>> Or even if every decoder is slightly unique, at least yours should
>> output self-consistent data.
>
>
> The original used some floating point code, I changed that to use integer
> code (eg a combination of multiplying and shifting; it make a difference on
> compiled version, perhaps not so much in .py).

The JPEG spec says what a given file should decode to. So you can use a
reference implementation to confirm that your code is correctly decoding. Even
if you might legitimately encode the same image in different ways, each of
those encoded files should decode to one exact image, regardless of which
decoder is used.

Your decoder was straight-up buggy, and tests would have proven this.

> But also (IIRC) there was a difference in taking the remainder of negative
> integer division, where different compilers may round up or down.

In every compiler, interpreter, and CPU that I've ever used, the remainder has
been well-defined. In what situation was it ill-defined, such that different
compilers could do different things?

> Some people are obsessed with having unit tests. Others are the same about
> using debuggers, especially in compiled code.
>
> I've never used either, but I do alright. Some of the stuff I do is
> unsuitable for those for technical reasons, but also some of the problems
> I've come across just don't fit into such patterns.
>
> People should use what works best for them, unless they're in a team where
> the have to use certain tools and working methods.

Yep, and if "producing buggy code that fails to comply with the spec" is what
works best for you, then please don't tell us that we're advocating the wrong
thing. Testing might not fix everything, but it does help, especially in those
easy cases where you're working with a pure function that has a single correct
output for a given input. Which, if I'm not misunderstanding the specs, is the
case for pretty much every compression scheme in current use - including JPEG.

For myself, I don't write as many tests as I should. But I'm not going to go
around telling people that tests are a waste of time.

ChrisA

nospam.Gregory Ewing

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
bartc wrote:
> (Maybe it's viable if working from an exacting
> specification that someone else has already worked out.)

In my experience, for anything non-trivial that hasn't been done before, these
"exacting specifications" never exist. Even if someone handles wnat they
*think* are exact and complete specifications, they're not. :-)

--
Greg

nospam.nospam.nospam.alister

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
On Sat, 25 Nov 2017 12:26:52 -0800, namenobodywants wrote:

> On Friday, November 24, 2017 at 8:07:07 AM UTC-8, Chris Angelico wrote:
>
>> This is the kind of function that needs a docstring and some comments.
>> What exactly is this doing? What are the "lines" of the board? What's
>> the difference between "linear" and "lines"? What exactly is it
>> returning?
>
> producing documentation is an extremely difficult task for me, but i've
> come up with the following:
>
> """
> makelines(length,numrows,numcolumns) IS THE LIST OF ALL LISTS L, WITH
> LENGTH length, OF COORDINATES FROM A numrows x numcolumns MATRIX, SUCH
> THAT THE ENTRIES OF L ALL LIE IN A LINE:
>
> LET horizontal BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN
> A HORIZONTAL LINE LET vertical BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE
> ENTRIES LIE IN A VERTICAL LINE LET downward BE ALL THE
> APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A DOWNWARD-SLOPING
> DIAGONAL LINE LET upward BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE
> ENTRIES LIE IN AN UPWARD-SLOPING DIAGONAL LINE THEN
> makelines(length,numrows,numcolumns) IS THE UNION OF ALL THE
> AFOREMENTIONED SETS """
>
> def makelines(length,numrows,numcolumns):
> horizontal = [[(i, j+k) for k in range(length)] for i in
> range(numrows) for j in range(numcolumns)]
> vertical = [[(i+k, j) for k in range(length)] for i in
> range(numrows) for j in range(numcolumns)] downward = [[(i+k, j+k)
> for k in range(length)] for i in range(numrows) for j in
> range(numcolumns)]
> upward = [[(i+k, j-k) for k in range(length)] for i in
> range(numrows) for j in range(numcolumns)] linear = horizontal +
> vertical + downward + upward return [line for line in linear if
> all(i in range(6) and j in range(7) for (i,j) in line)]
>
> def getlines(board):
> coordlines = makelines(4,6,7) ## GLOBAL return [[board[square] for
> square in line] for line in coordlines
>
>
> i tried to remove all the superfluous spaces from that, but lining up
> code vertically is very helpful to me, so i don't think i can really
> dispense with the practice
>
> peace stm

the documentation should come after the def statement that way is becomes a
"Doc String" & can be accessed using the help function you may also want to
check out the recommended way of structuring a doc string,
it could help you with your difficulty in writing them (a problem shared by
many)



--
This door is baroquen, please wiggle Handel. (If I wiggle Handel, will it
wiggle Bach?)
-- Found on a door in the MSU music building

nospam.nospam.nospam.bartc

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
On 25/11/2017 16:07, Michael Torrie wrote:
> On 11/25/2017 06:00 AM, bartc wrote:
>> And there's a quite lot left of the rest of the program to worry about too!
>>
>> If you add 'window()' at the end of the program, then it seems to run on
>> Python 3. I'd play around with it first before thinking up strategies
>> for testing it.
>
> Actually, no. Unit testing ideally should be done for each and every
> class as they are being written (before they are written in fact), no
> matter how small and trivial the class. That way as you compose larger
> and larger units of code, the chances of things being right is greater
> compared to doing it the other way around.

The way I write code isn't incrementally top down or bottom up. It's backwards
and forwards. Feedback from different parts means the thing develops as a
whole. Sometimes parts are split into distinct sections, sometimes different
parts are merged.

Sometimes you realise you're on the wrong track, and sections have to be redone
or a different approach used, which can be done in the earlier stages.

If I had to bother with such systematic tests as you suggest, and finish and
sign off everything before proceeding further, then nothing would ever get
done. (Maybe it's viable if working from an exacting specification that someone
else has already worked out.)

I've also found that many of the bugs that do appear, also do so in ways you
never anticipated. Or in circumstances you would never have thought of.

(I've always thought that programming is a bit like creating new laws. The same
laws need to work for everyone and in any circumstances, but no one can
foresee everything, and laws need to be tweaked and added to. Perhaps unit
tests can apply there too...)

> You may argue that testing doesn't matter for his small game, written
> for his own education and amusement. The fact is that software in
> general is of abysmal quality across the boards, and promoting a habit
> of unit testing is good, even for trivial, home-grown stuff.

I thought people were being hard on the OP.

As for testing, I remember in a company I worked in, a complicated circuit was
submitted to a company that would put it into a mass-produced chip. This
company did massive numbers of emulated tests shown on a huge printout that
showed that all combinations of inputs and outputs worked exactly as intended.

Except the actual chip didn't work. As for the printout, the designer took it
home and used it as an underlay for a new carpet. A rather expensive underlay.

--
bartc

nospam.Michael Torrie

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
On 11/25/2017 12:58 PM, namenob...@gmail.com wrote:
> the idea is that there should be exactly one object posinf (positive
infinity) that compares as strictly greater than any number ever considered,
and exactly one object neginf that compares as strictly less; as the code
stands now there is no reason not to use +/-70 in that capacity; the "infinity"
class is there so that the game-playing parts of the code (which at present
are intentionally as primitive as possible) can be modified more smoothly
later; the single place where "infinity" is instantiated is in the function
"getvalue", which returns the value of a finished game:
>
> def getvalue(winner,accessibles):
> return Infinity(+1) if winner == ex else Infinity(-1) if winner == oh
else 0 if not accessibles else None
>
> if ex has won then the value of the game is posinf; if oh has won then it's
neginf; if the game is tied (no winner but no accessible columns remaining)
then the value of the game is zero; otherwise the game is not finished and its
finished value is None

nospam.bartc

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
On 27/11/2017 13:57, Chris Angelico wrote:
> On Mon, Nov 27, 2017 at 10:38 PM, bartc <b...@freeuk.com> wrote:


> Your decoder was straight-up buggy, and tests would have proven this.

I created my Python version after the abysmal results from other Python
decoders I tried which didn't work at all, gave the wrong results, didn't
support other subsampling ratios, or hung. Or if they did work, they took
forever.

I suggest you compare my version with some of those.

The first time I looked at a jpeg decoder, it was a massive C library of about
30 different source files. Sometimes you need to take short-cuts. My version
generates images which are indistinguishable from those derived via other
decoders.

>> But also (IIRC) there was a difference in taking the remainder of negative
>> integer division, where different compilers may round up or down.
>
> In every compiler, interpreter, and CPU that I've ever used, the
> remainder has been well-defined. In what situation was it ill-defined,
> such that different compilers could do different things?

> Which, if I'm not misunderstanding the specs, is the case for pretty
> much every compression scheme in current use - including JPEG.

JPEG uses lossy compression. The resulting recovered data is an
approximation of the original.

> For myself, I don't write as many tests as I should. But I'm not going
> to go around telling people that tests are a waste of time.

I'm fairly certain the OP's program didn't work perfectly first time. So some
procedure had to be followed to try it and decide if it behaved according to
the specification they had in mind.

I believe that process can also be called 'testing'. And in this case,
involving a visual GUI, it really demands tests verified by a human rather than
spending the next six months writing automatic test procedures that simulate
mouse input and examine the pixels on the screen to see if they correspond to
what should happen.

> Your decoder was straight-up buggy, and tests would have proven this.

nospam.Chris Angelico

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
On Mon, Nov 27, 2017 at 1:55 PM, Michael Torrie <tor...@gmail.com> wrote:
> On 11/26/2017 07:11 AM, bartc wrote:
>>> You may argue that testing doesn't matter for his small game, written
>>> for his own education and amusement. The fact is that software in
>>> general is of abysmal quality across the boards, and promoting a habit
>>> of unit testing is good, even for trivial, home-grown stuff.
>>
>> I thought people were being hard on the OP.
>
> I wasn't being hard on the OP. My observation is about the state of
> *all* software. My software especially, your software, Microsoft's
> software. It all is of rather poor quality compared to the rigors of
> other industries like civil engineering, manufacturing, etc.

Not all software is poor quality compared to all examples of those industries.
You'll find the equivalent of software bugs in a lot of hardware situations;
the difference with software is that we have 100% perfect reproduction in the
end-user products, so we call it a design flaw instead of a production
artifact. (How often do you buy a box of something and find that a couple of
them just break?) Even in large-scale civil engineering projects, there are
plenty of stupidities. The house I'm living in has a place where the tiled
floor doesn't quite align with the wall that it meets, and I can't figure out
why; somewhere, two things that ought to have been parallel just aren't.
Bridges have been known to crack, cars break down for no good reason, your
hamburger just doesn't taste right today.

Aviators have pinned down the best solution to this, I think. A pilot is not
expected to be perfect; he is expected to follow checklists. A preflight
checklist. A departure checklist. A landing checklist. Everything that needs to
be done right is mentioned on the list, and you just go through the list and

namenobodywants

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
On Sunday, November 26, 2017 at 7:09:25 PM UTC-8, Michael Torrie wrote:

> So you are using this Infinity class as a sentinel value of some kind?
> Representing game state? There may be an easier way than a full on
> custom type. Sometimes just a sentinel object is sufficient. Or an
> enumeration.

they're not sentinels; they're the maximum and minimum of the extended real
numbers; the point is that, no matter how boards are evaluated (which is, of
course, subject to change), a won game is always the most valuable and a lost
game is always the least valuable; ordinary real numbers could be used for the
purpose, but in that case i would have to figure out the maximum and minimum of
the heuristic values the script assigns and then add/subtract one (for
example) to get the value of a won/lost game

peace
stm

nospam.bartc

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
On 27/11/2017 03:04, Michael Torrie wrote:
> On 11/26/2017 08:39 AM, bartc wrote:
>> The problem was traced to two lines that were in the wrong order (in the
>> original program). I can't see how unit tests can have helped in any way
>> at all, and it would probably have taken much longer.
>
> What makes you think that? Surely other decoders were doing the right
> thing and you could compare your output against theirs? JPEGs may be
> lossy but the path through the decoder should be deterministic.
>
> Or even if every decoder is slightly unique, at least yours should
> output self-consistent data.

The original used some floating point code, I changed that to use integer code
(eg a combination of multiplying and shifting; it make a difference on compiled
version, perhaps not so much in .py).

But also (IIRC) there was a difference in taking the remainder of negative
integer division, where different compilers may round up or down.

So there can easily be differences when compared at the binary level, but which
shouldn't be noticeable with the human eye.

(https://pastebin.com/P7V1Bvkk
https://pastebin.com/raw/P7V1Bvkk raw version with no ads, or colour)

In other words, once you know you fixed
> the chroma problem, you can use that jpeg as a unit test to make sure
> future big fixes and enhancements don't break something else.
> Regression testing is very important. Many times I've fixed a bug, only
> to introduce new ones that broke formerly correct behavior.
>
> Anyway, unit testing is certainly a challenging concept, and I'm no more
> good at it than you are.

Some people are obsessed with having unit tests. Others are the same about
using debuggers, especially in compiled code.

I've never used either, but I do alright. Some of the stuff I do is unsuitable
for those for technical reasons, but also some of the problems I've come across
just don't fit into such patterns.

People should use what works best for them, unless they're in a team where the
have to use certain tools and working methods.


--
bartc

nospam.Michael Torrie

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
On 11/26/2017 07:11 AM, bartc wrote:
>> You may argue that testing doesn't matter for his small game, written
>> for his own education and amusement. The fact is that software in
>> general is of abysmal quality across the boards, and promoting a habit
>> of unit testing is good, even for trivial, home-grown stuff.
>
> I thought people were being hard on the OP.

I wasn't being hard on the OP. My observation is about the state of
*all* software. My software especially, your software, Microsoft's
software. It all is of rather poor quality compared to the rigors of other
industries like civil engineering, manufacturing, etc.

> As for testing, I remember in a company I worked in, a complicated
> circuit was submitted to a company that would put it into a
> mass-produced chip. This company did massive numbers of emulated tests
> shown on a huge printout that showed that all combinations of inputs and
> outputs worked exactly as intended.
>
> Except the actual chip didn't work. As for the printout, the designer
> took it home and used it as an underlay for a new carpet. A rather
> expensive underlay.

That's unfortunately, but seems to reinforce the notion that adequate testing
is required. Clearly for a microchip, theoretically testing the chip's
"software" (for lack of a better term) was not adequate. An analogy to our
software situation is that someone tested the algorithm, but not the actual,
in-use implementation of the algorithm.

nospam.Rustom Mody

unread,
Nov 27, 2017, 5:08:10 PM11/27/17
to
On Monday, November 27, 2017 at 9:08:42 AM UTC+5:30, Chris Angelico wrote:
And thats where the analogy breaks down. Presumably a 50 person short-flight
and a 600-person transcontinental may have at least something in common in
their pilot-checklists What common will you find in a multi-million line OS, a
thousand line script and a student prime-numbers first-program?

No I am not dissing on testing and TDD; just that universalityā1 of computing
devices
is something that our civilization is nowhere near understanding, leave alone
dealing with ā ö two programs can be more far apart than a bullock cart and a
jet.
And yet they are both programs

ā1 Ive seen CS PhDs ask a student why a student didnt incorporate some
error-checking
into his compiler which amounted to solving the halting problem.
More mundanely I see students have a hard time seeing their phones and their
laptops as 'the same'

nospam.Chris Angelico

unread,
Nov 27, 2017, 5:09:12 PM11/27/17
to
On Mon, Nov 27, 2017 at 9:01 PM, <namenob...@gmail.com> wrote:

nospam.Ian Kelly

unread,
Nov 27, 2017, 5:09:16 PM11/27/17
to
On Nov 27, 2017 7:08 AM, "Chris Angelico" <ros...@gmail.com> wrote:


In every compiler, interpreter, and CPU that I've ever used, the remainder has
been well-defined. In what situation was it ill-defined, such that different
compilers could do different things?


nospam.Chris Angelico

unread,
Nov 27, 2017, 5:09:17 PM11/27/17
to
On Mon, Nov 27, 2017 at 3:04 PM, Rustom Mody <rusto...@gmail.com> wrote:
>> Aviators have pinned down the best solution to this, I think. A pilot
>> is not expected to be perfect; he is expected to follow checklists. A
>> preflight checklist. A departure checklist. A landing checklist.
>> Everything that needs to be done right is mentioned on the list, and
>> you just go through the list and make sure you've done everything.
>
> And thats where the analogy breaks down.
> Presumably a 50 person short-flight and a 600-person transcontinental may
have
> at least something in common in their pilot-checklists
> What common will you find in a multi-million line OS, a thousand line script
> and a student prime-numbers first-program?

You locate a pure function. I can pretty much guarantee that the first two will
have a number of them, and the third one may or may not, but almost certainly
should. Pure functions are the easiest to unit-test. Then you build up from
there.

> No I am not dissing on testing and TDD; just that universalityā1 of computing
devices
> is something that our civilization is nowhere near understanding, leave alone
> dealing with ā ö two programs can be more far apart than a bullock cart and a
jet.
> And yet they are both programs

... so?

> ā1 Ive seen CS PhDs ask a student why a student didnt incorporate some
error-checking
> into his compiler which amounted to solving the halting problem.
> More mundanely I see students have a hard time seeing their phones and
their
> laptops as 'the same'

Again: so? Testing methodologies don't require that.

ChrisA

nospam.bartc

unread,
Nov 27, 2017, 5:09:20 PM11/27/17
to
On 27/11/2017 17:41, Chris Angelico wrote:
> On Tue, Nov 28, 2017 at 2:14 AM, bartc <b...@freeuk.com> wrote:
>> JPEG uses lossy compression. The resulting recovered data is an
>> approximation of the original.
>
> Ah but it is a perfect representation of the JPEG stream. Any given
> compressed stream must always decode to the same output. The lossiness
> is on the ENcoding, not the DEcoding.

You make it sound as bad as currency calculations where different software must
produce results that always match to the nearest cent.

We're talking about perhaps +1 or -1 difference in the least significant bit of
one channel of one pixels. If the calculation is consistent, then you will not
know anything is amiss.

By +1 or -1, I mean compared with the same jpeg converted by independent means.

I also passed the same jpeg through another C program (not mine) using its own
algorithms. There some pixels varied by up to +/- 9 from the others (looking at
the first 512 bytes of the conversion to ppm).

Here's my test image:
https://github.com/bartg/langs/blob/master/card2.jpg (nothing naughty).

Tell me what the definitive values of the pixels in this part of the image
should be (I believe this corresponds to roughly the leftmost 180 pixels of the
top line; there are two million pixels in all). And tell me WHY you think
those are the definitive ones.

Bear in mind also that this is not intended to be the world's most perfect
software. But it does do a good enough job. And the other two Python versions I
have, at the minute don't work at all.


--
bartc

nospam.Gregory Ewing

unread,
Nov 27, 2017, 5:09:23 PM11/27/17
to
bartc wrote:
> Testing everything comprehensively just wouldn't be useful for me who
> works on whole applications, whole concepts, not just a handful of
> functions with well-defined inputs and outputs.

I had this experience with Pyrex (the precursor to Cython). The various parts
are so interdependent that it doesn't really make sense to test individual
classes or methods on their own. It would require a huge amount of scaffolding
and wouldn't really prove much.

Instead, what I did was write tests for units of *functionality*. (Can it
compile an assignment statement? An expression that adds two things? Subtracts
them? etc.) I wrote a very large number of them, plus a test framework to run
them and compare the output with known good output.

I can't claim that I always wrote the tests *first* (sometimes I did, sometimes
I didn't). But I never had any trouble motivating myself to write the tests.
Partly this is because the way my test framework worked, there was very little
difference between a manual test and an automated one. I had to write a test
file to test it at all, and having done that, it was just as easy to save it
away together with its output so that it became part of the automated test
suite.

It was also partly because the benefits of having a comprehensive automatic
test suite were so blindingly obvious in that project. Its complexity meant
that it was particularly easy to break something accidentally when adding a new
feature. If that happened, the tests would almost certainly pick it up
immediately. Without those tests, I would never have been able to develop it to
the point I did.

>> So there was something else wrong with the chip. I'm not sure what
>> your point is.
>
> The extensive testing was like unit testing, but needed to be even more
> thorough because of the commitment involved. It failed to spot a problem.

Testing obviously isn't guaranteed to find all problems in a system with
complex behaviour, but that doesn't mean testing is useless. It would have been
hugely more risky to go ahead and build the chip without testing the design at
all!

BTW, hardware is a bit different from software. It's possible
for a design to be *logically* correct and pass all the simulations, but for
the hardware to fail for messy physics- related reasons. (Charles Moore tells a
story like that about one of his Forth chips. A transistor driving a
particular signal was too small, and if you executed a particular instruction
too many times in too short a time interval, it would overheat and produce
incorrect results.)

--
Greg

nospam.Ned Batchelder

unread,
Nov 27, 2017, 5:09:28 PM11/27/17
to
On 11/27/17 1:57 PM, bartc wrote:

nospam.Rustom Mody

unread,
Nov 27, 2017, 5:09:35 PM11/27/17
to
On Monday, November 27, 2017 at 12:12:24 PM UTC+5:30, Chris Angelico wrote:
> On Mon, Nov 27, 2017 at 3:04 PM, Rustom Mody wrote:
> >> Aviators have pinned down the best solution to this, I think. A pilot
> >> is not expected to be perfect; he is expected to follow checklists. A
> >> preflight checklist. A departure checklist. A landing checklist.
> >> Everything that needs to be done right is mentioned on the list, and
> >> you just go through the list and make sure you've done everything.
> >
> > And thats where the analogy breaks down.
> > Presumably a 50 person short-flight and a 600-person transcontinental may
have
> > at least something in common in their pilot-checklists
> > What common will you find in a multi-million line OS, a thousand line
script
> > and a student prime-numbers first-program?
>
> You locate a pure function. I can pretty much guarantee that the first
> two will have a number of them, and the third one may or may not, but
> almost certainly should. Pure functions are the easiest to unit-test.
> Then you build up from there.
>
> > No I am not dissing on testing and TDD; just that universalityâ1 of
computing devices
> > is something that our civilization is nowhere near understanding, leave
alone
> > dealing with â ö two programs can be more far apart than a bullock cart and
a jet.
> > And yet they are both programs
>
> ... so?

I know how to drive a carâ | and various two-wheelers. I not so sure of a
bus/truckâ | I suppose I could get one from here to there at a pinchâ | without
killing someoneâ | though not quite sure of that! Doesn't translate into
knowing how to 'drive' planes or bullock-carts


gcc is tested with dejagnu. Do you imagine that knowing python's unittest or
nose directly translates into dejagnu expertise? And even if we stay with
industry-strength programs â ö gcc, linux-kernel, CPython, KDE â ö do you
imagine that testing one helps in testing the other? I doubt it (though I am
hardly an expert with testing frameworks)

Once again let me end by saying that testing and TDD are good ideas And it
would be nice if there was more of it in/for python [See
http://osherove.com/tdd-kata-1/ one of the first hits that google gives (me)
for TDD python, and you find the python example actually shows Ruby!]

namenobodywants

unread,
Nov 27, 2017, 5:13:49 PM11/27/17
to
On Monday, November 27, 2017 at 2:10:56 AM UTC-8, Chris Angelico wrote:

> Or you could use the floating-point values for positive and negative
> infinity

perfecto! thank you!

peace
stm

nospam.Chris Angelico

unread,
Nov 27, 2017, 5:14:15 PM11/27/17
to
On Tue, Nov 28, 2017 at 2:14 AM, bartc <b...@freeuk.com> wrote:
> JPEG uses lossy compression. The resulting recovered data is an
> approximation of the original.

Ah but it is a perfect representation of the JPEG stream. Any given compressed
stream must always decode to the same output. The lossiness is on the ENcoding,
not the DEcoding.

ChrisA

nospam.nospam.bartc

unread,
Nov 28, 2017, 2:04:44 PM11/28/17
to
On 27/11/2017 13:57, Chris Angelico wrote:
> On Mon, Nov 27, 2017 at 10:38 PM, bartc <b...@freeuk.com> wrote:


> Your decoder was straight-up buggy, and tests would have proven this.

I created my Python version after the abysmal results from other Python
decoders I tried which didn't work at all, gave the wrong results, didn't
support other subsampling ratios, or hung. Or if they did work, they took
forever.

I suggest you compare my version with some of those.

The first time I looked at a jpeg decoder, it was a massive C library of about
30 different source files. Sometimes you need to take short-cuts. My version
generates images which are indistinguishable from those derived via other
decoders.

>> But also (IIRC) there was a difference in taking the remainder of negative
>> integer division, where different compilers may round up or down.
>
> In every compiler, interpreter, and CPU that I've ever used, the
> remainder has been well-defined. In what situation was it ill-defined,
> such that different compilers could do different things?

JPEG uses lossy compression. The resulting recovered data is an
approximation of the original.

nospam.nospam.Gregory Ewing

unread,
Nov 28, 2017, 2:04:44 PM11/28/17
to
bartc wrote:
> (Maybe it's viable if working from an exacting
> specification that someone else has already worked out.)

nospam.nospam.Rustom Mody

unread,
Nov 28, 2017, 2:04:45 PM11/28/17
to

nospam.nospam.bartc

unread,
Nov 28, 2017, 2:04:46 PM11/28/17
to
On 27/11/2017 03:04, Michael Torrie wrote:
> On 11/26/2017 08:39 AM, bartc wrote:
>> The problem was traced to two lines that were in the wrong order (in the
>> original program). I can't see how unit tests can have helped in any way
>> at all, and it would probably have taken much longer.
>
> What makes you think that? Surely other decoders were doing the right
> thing and you could compare your output against theirs? JPEGs may be
> lossy but the path through the decoder should be deterministic.
>
> Or even if every decoder is slightly unique, at least yours should
> output self-consistent data.

The original used some floating point code, I changed that to use integer code
(eg a combination of multiplying and shifting; it make a difference on compiled
version, perhaps not so much in .py).

But also (IIRC) there was a difference in taking the remainder of negative
integer division, where different compilers may round up or down.

namenobodywants namenobodywants

unread,
Nov 28, 2017, 2:04:47 PM11/28/17
to

nospam.nospam.Gregory Ewing

unread,
Nov 28, 2017, 2:04:47 PM11/28/17
to
Chris Angelico wrote:

> On Mon, Nov 27, 2017 at 1:11 AM, bartc <b...@freeuk.com> wrote:
>
>>If I had to bother with such systematic tests as you suggest, and finish and
>>sign off everything before proceeding further, then nothing would ever get
>>done. (Maybe it's viable if working from an exacting specification that
>>someone else has already worked out.)
>
> I wonder whether you're somehow special in that
> testing fundamentally doesn't work for you, or that you actually don't
> need to write tests.

I think the point is that a strict test-first discipline goes against the grain
of exploratory programming.

When you're not sure how to approach a problem, it's useful to be able to
quickly try things out. If you have to write a bunch of tests for every little
thing before you can write the code for it, you can end up writing a lot of
tests for code that never ends up getting used. That's a good way to kill all
your enthusiasm for a project.

Also, stopping to write tests all the time interrupts your flow of thought.
You're deep into details of the solution, you realise you need class X, then
you have to stop and write tests for X. That makes you think a lot about all
the details of X, and by the time you're finished you've lost track of the big
picture.

I don't think anyone disputes that having a reasonably complete set of tests is
a good thing. The argument is about whether it's strictly necessary to write
the tests
*first* in all cases.

Maybe you find it's a useful discipline that helps ensure the tests get
written. That's fine, but it doesn't mean that
*everyone* should be forced to do it that way all the time,
even if they're just programming for a hobby. That's confusing the desired end
result with a particular means of achieving it.

--
Greg

namenobodywants namenobodywants

unread,
Nov 28, 2017, 2:04:54 PM11/28/17
to
On Sunday, November 26, 2017 at 7:09:25 PM UTC-8, Michael Torrie wrote:

> So you are using this Infinity class as a sentinel value of some kind?
> Representing game state? There may be an easier way than a full on
> custom type. Sometimes just a sentinel object is sufficient. Or an
> enumeration.

they're not sentinels; they're the maximum and minimum of the extended real
numbers; the point is that, no matter how boards are evaluated (which is, of
course, subject to change), a won game is always the most valuable and a lost
game is always the least valuable; ordinary real numbers could be used for the
purpose, but in that case i would have to figure out the maximum and minimum of
the heuristic values the script assigns and then add/subtract one (for
example) to get the value of a won/lost game

peace
stm

nospam.nospam.Rustom Mody

unread,
Nov 28, 2017, 2:04:54 PM11/28/17
to
On Monday, November 27, 2017 at 9:08:42 AM UTC+5:30, Chris Angelico wrote:
> On Mon, Nov 27, 2017 at 1:55 PM, Michael Torrie wrote:
> > On 11/26/2017 07:11 AM, bartc wrote:
> >>> You may argue that testing doesn't matter for his small game, written
> >>> for his own education and amusement. The fact is that software in
> >>> general is of abysmal quality across the boards, and promoting a habit
> >>> of unit testing is good, even for trivial, home-grown stuff.
> >>
> >> I thought people were being hard on the OP.
> >
> > I wasn't being hard on the OP. My observation is about the state of
> > *all* software. My software especially, your software, Microsoft's
> > software. It all is of rather poor quality compared to the rigors of
> > other industries like civil engineering, manufacturing, etc.
>
> Not all software is poor quality compared to all examples of those
> industries. You'll find the equivalent of software bugs in a lot of
> hardware situations; the difference with software is that we have 100%
> perfect reproduction in the end-user products, so we call it a design
> flaw instead of a production artifact. (How often do you buy a box of
> something and find that a couple of them just break?) Even in
> large-scale civil engineering projects, there are plenty of
> stupidities. The house I'm living in has a place where the tiled floor
> doesn't quite align with the wall that it meets, and I can't figure
> out why; somewhere, two things that ought to have been parallel just
> aren't. Bridges have been known to crack, cars break down for no good
> reason, your hamburger just doesn't taste right today.
>
> Aviators have pinned down the best solution to this, I think. A pilot
> is not expected to be perfect; he is expected to follow checklists. A
> preflight checklist. A departure checklist. A landing checklist.
> Everything that needs to be done right is mentioned on the list, and
> you just go through the list and make sure you've done everything.

And thats where the analogy breaks down. Presumably a 50 person short-flight
and a 600-person transcontinental may have at least something in common in
their pilot-checklists What common will you find in a multi-million line OS, a
thousand line script and a student prime-numbers first-program?

No I am not dissing on testing and TDD; just that universalityā1 of computing
devices
is something that our civilization is nowhere near understanding, leave alone
dealing with ā ö two programs can be more far apart than a bullock cart and a
jet.
And yet they are both programs

ā1 Ive seen CS PhDs ask a student why a student didnt incorporate some
error-checking
into his compiler which amounted to solving the halting problem.
More mundanely I see students have a hard time seeing their phones and their
laptops as 'the same'

0 new messages