Good Test

Discussion of anything and everything relating to chess playing software and machines.

Moderator: Ras

Dann Corbit
Posts: 12792
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: Good Test

Post by Dann Corbit »

Here are the EPD records I produced with a filter program afterwards:

This is a correct solution record with the best score:
[d]rnr3k1/pp2qnb1/3p1p2/2pPp1p1/2P1P2B/2N4P/PP3P2/R2QKN1R w KQ - acd 22; acn 2764158008; acs 1591240; bm Ne3; ce 133; pv Ne3 gxh4 Nf5 Qf8 Qg4 Na6 O-O-O Nc7 Rhg1 Ng5 Nxh4 Ne8 Nf5 Nh7 f4 Rc7 Kb1 Kh8 h4 a6 h5 Bh6 fxe5 Bg5 e6 Ng7 Nh4 Bxh4 Qxh4 Ng5;

This is an alternative evaluation created via multi-pv output with a lower score:
[d]rnr3k1/pp2qnb1/3p1p2/2pPp1p1/2P1P2B/2N4P/PP3P2/R2QKN1R w KQ - acd 22; acn 2148883533; acs 1591240; bm Bg3; ce 130; pv Bg3 Nh6 h4 Nd7 Ne3 a6 Qe2 Rcb8 a3 g4 h5 Kh8 Rg1 Qf7 O-O-O Qxh5 Rh1 Qg5 Qxg4 Qxg4 Nxg4 Kh7;

This is an alternative evaluation created via multi-pv output with a lower score:
[d]rnr3k1/pp2qnb1/3p1p2/2pPp1p1/2P1P2B/2N4P/PP3P2/R2QKN1R w KQ - acd 22; acn 3612117277; acs 1591240; bm Rg1; ce 108; pv Rg1 Qd7 Bg3 Qxh3 Ne3 Rd8 Qf3 Qh7 Rh1 Qg6 Nf5 Bf8 Qe2 Na6 O-O-O Nc7 Rdg1 Re8 Kb1;

This is an alternative evaluation created via multi-pv output with a lower score:
[d]rnr3k1/pp2qnb1/3p1p2/2pPp1p1/2P1P2B/2N4P/PP3P2/R2QKN1R w KQ - acd 22; acn 4688624964; acs 1591240; bm Qh5; ce 106; pv Qh5 b5 Bg3 b4;
User avatar
Eelco de Groot
Posts: 4671
Joined: Sun Mar 12, 2006 2:40 am
Full name:   Eelco de Groot

Re: Good Test

Post by Eelco de Groot »

Dann Corbit wrote:
Eelco de Groot wrote:Thanks for the analysis by Rybka 3, Dann. I do have a question about the output though; from the score and the last ouput it seems that in the 22nd iteration Rybka is finally successful in finding Kasparov's move:

Code: Select all

     22	7:22:40	2.764.158,008	186.020	+1.33	Nf1e3 g5xh4 Ne3f5 Qe7f8 Qd1g4 Nb8a6 OOO Na6c7 Rh1g1 Nf7g5 Nf5xh4 Nc7e8 Nh4f5 Ng5h7 f2f4 Rc8c7 Kc1b1 Kg8h8 h3h4 a7a6 h4h5 Bg7h6 f4xe5 Bh6g5 e5e6 Ne8g7 Nf5h4 Bg5xh4 Qg4xh4 Nh7g5
But then I can't understand the rest of the comments, at the beginning and end, starting the EPD output with:

Code: Select all

1) Ne3;                 
    Searching move: Nf1-e3
    Best move (Rybka 3 multi-pv): Nf1-g3
    Not found in: 10:00:00
Arena is simply confused here. Rybka found the right answer.
and then the last line:

Code: Select all

0 of 1 matching moves
Is this a bug in Rybka, that Vas maybe does not know about or am I reading something wrong, higher scores are meant to be from White's point of view, it's White to move so there can be no ambivalence about that? You probably explained how you get these EPD records Dann, but I forgot...Sorry!

Regards, Eelco
It's a bug in Arena. The problem is solved, but Arena does not understand multiline output.
Thanks Dann, also for the EPD clarification! This Arena output was a bit confusing, and I don't believe I had seen anything like this before, I think because usually you posted results not from multi-PV analysis and then the comments seemed correct.

I am not very familiar with Arena quirks, maybe the Fritz team can use this in an anti-free software thread :) But they never post anywhere :? In the past I believe sometimes Frederic Friedel used to post in CCC. I vaguely remember a post about a Robert Heinlein book or something of that nature. Did Frans Morsch ever post in CCC or RGCCC? Maybe he did before I joined.

I am still looking also at this position but plagued with "run away" -extensions or at least I hope that is it, I get no new output after a while so that makes it impossible to tune anything because there is just no output :shock: and debugging with the compiler I'm not very good at. So I just will have to study my latest code changes of maybe fifty versions and try to understand what I am doing there :)

This is with a very experimental version that is now hanging again it seems, but the output so far was not a complete disaster, I don't get negative scores yet, +.20 for Black after 1. Ne3 gxh4 but the score for 1... b5 is dropping as in the earlier slightly more solid build 312. Also the multi-PV output was not much slower in spite of some evaluation changes that need some extra bitboard code. I would have expected a lower score for gxh4 but this is usually counterintuitive stuff if you change the eval.

After 1. Ne3

[d]rnr3k1/pp2qnb1/3p1p2/2pPp1p1/2P1P2B/2N1N2P/PP3P2/R2QK2R b KQ -

Engine: Ancalagon 1.3 Weak Squares 180 Board Control middlegame 50 endgame 50
Build 327 (Athlon 2009 MHz, 256 MB) by Romstad, Costalba, Kiiski, de Groot

7 0:27 0.00 1...gxh4 2.Nf5 Qd8 3.Nb5 Qa5+ 4.Kf1 Rd8
5.Qh5 Qd2 6.Ne7+ Kf8 7.Ng6+ Kg8
8.Ne7+ (12.661.756) 465

7 0:27 -0.54 1...b5 2.Bg3 b4 3.Ne2 Nd7 4.O-O a5
5.Nf5 Qe8 6.f3 a4 (12.661.756) 465

7 0:27 -1.05 1...Nh6 2.Bg3 Na6 3.h4 Qf7 4.hxg5 fxg5
5.Qh5 Qxh5 6.Rxh5 Nf7 7.Nf5 (12.661.756) 465
___________________________________________________________________

8 1:17 +1.18 1...gxh4 2.Nf5 Qf8 3.Rg1 Ng5 4.Nb5 Na6
5.Nbxd6 Rd8 6.f4 exf4 7.Nxb7 Rd7 (34.824.143) 450

8 1:17 -0.67 1...b5 2.Bg3 b4 3.Na4 Nh6 4.h4 Nd7
5.Qh5 gxh4 6.Rxh4 Qf7 7.f4 Qxh5
8.Rxh5 Kf7 (34.824.143) 450

8 1:17 -1.35 1...Nh6 2.Bg3 Na6 3.h4 Kf8 4.Kf1 Rd8
5.hxg5 fxg5 6.a3 Qf6 7.Kg1 Rd7 8.Qh5 (34.824.143) 450
__________________________________________________________________

9 2:41 +1.29 1...gxh4 2.Nf5 Qf8 3.Rg1 Ng5 4.Nb5 Na6
5.Nbxd6 Rd8 6.Nxb7 Rd7 7.Na5 Qb8
8.Qb3 Qb4+ 9.Qxb4 Nxb4 10.Ke2 Nxe4
11.Nxh4 (72.289.755) 447

9 2:41 -0.74 1...b5 2.Bg3 b4 3.Na4 Nh6 4.h4 Nd7
5.Qh5 gxh4 6.Rxh4 Qf7 7.f4 Qxh5
8.Rxh5 Kf7 9.Kd2 (72.289.755) 447

9 2:41 -1.19 1...Nh6 2.Bg3 Qf7 3.h4 Na6 4.hxg5 fxg5
5.Qh5 Qxh5 6.Rxh5 Nf7 7.Kd2 Rd8
8.Rah1 (72.289.755) 447
_________________________________________________________________

10 33:49 +0.55 1...gxh4 2.Nf5 Qf8 3.Nxh4 Rc7 4.Qg4 Nh6
5.Qe6+ Qf7 6.Qxd6 Na6 (852.436.769) 420

10 33:49 -1.12 1...b5 2.Qg4 Qd7 3.Nf5 bxc4 4.Bg3 Nh6
5.Ne7+ Kh7 6.Qxd7 Nxd7 7.Nxc8 Rxc8 8.Nb5 Nf7
9.Nxa7 (852.436.769) 420

10 33:49 -1.35 1...Nh6 2.Bg3 Qf7 3.h4 Na6 4.hxg5 fxg5
5.Qh5 Qxh5 6.Rxh5 Nf7 7.Nf5 Rd8 8.O-O-O Rab8
(852.436.769) 420
_________________________________________________________________

11 48:14 +0.40 1...gxh4 2.Nf5 Qf8 3.Nxh4 Rc7 4.Qg4 Nh6
5.Qe6+ Qf7 6.Nb5 Qxe6 7.dxe6 Re7
8.Ng6 Re8 9.Rd1 Nc6 10.Rxd6 Rac8
11.Rd7 Rcd8 12.Rxd8 Rxd8 13.Ke2 f5 (1.245.795.992) 430

11 48:14 -1.31 1...Nh6 2.Bg3 Qf7 3.h4 Qg6 4.hxg5 fxg5
5.Qh5 Qxh5 6.Rxh5 Nf7 7.Nf5 Rd8
8.Nb5 Na6 (1.245.795.992) 430

11 48:14 -1.48 1...b5 2.Nf5 (1.245.795.992) 430
________________________________________________________________

12 154:22 +0.20 1...gxh4 2.Nf5 Qf8 3.Nxh4 Rc7 4.Qg4 Nh6
5.Qe6+ Qf7 6.Nb5 Na6 7.O-O-O Re7 8.Qxf7+ Rxf7
9.Nxd6 Rd7 10.Ndf5 Kf7 11.Rhg1 Bf8 12.Kc2 Rad8
13.Kb3 Nxf5 14.Nxf5 (3.946.302.282) 426

12 154:22 -1.40 1...Nh6 2.Bg3 Nd7 3.h4 a6 4.hxg5 fxg5
5.Qh5 Rcb8 6.f3 b5 7.O-O-O Kf8 8.Kb1 b4
9.Ne2 a5 10.Bf2 a4 (3.946.302.282) 426

12 154:22 -2.55 1...b5 2.cxb5 Nh6 3.Bg3 Qf7 4.h4 Rd8
5.hxg5 fxg5 6.Qh5 Qxh5 (3.946.302.282) 426
________________________________________________________________

12 163:31 +0.20 1...gxh4 2.Nf5 Qf8 3.Nxh4 Rc7 4.Qg4 Nh6
5.Qe6+ Qf7 6.Nb5 Na6 7.O-O-O Re7
8.Qxf7+ Rxf7 9.Nxd6 Rd7 10.Ndf5 Kf7
11.Rhg1 Bf8 12.Kc2 Rad8 13.Kb3 Nxf5
14.Nxf5 (4.182.299.254) 426

12 163:31 -1.40 1...Nh6 2.Bg3 Nd7 3.h4 a6 4.hxg5 fxg5
5.Qh5 Rcb8 6.f3 b5 7.O-O-O Kf8 8.Kb1 b4
9.Ne2 a5 10.Bf2 a4 (4.182.299.254) 426

12 163:31 -2.28 1...Qd8 2.Bg3 Nh6 3.h4 Nd7 4.Qh5 a6
5.hxg5 fxg5 6.Qh3 Qe7 7.Qe6+ Qxe6
8.dxe6 Nf6 9.Ned5 Nxd5 10.Nxd5 Rf8
11.Rh5 b5 12.cxb5 axb5 13.Rxg5 (4.182.299.254) 426

Some new code in place, because I could not find much in Stockfish and I also had not implemented anything in Ancalagon related to Rooks and Queens supporting Passed Pawns from behind, at least not that I could find, while on the other hand the equivalent code of the opponent attacking those pawns from behind with the heavy pieces, was already in place. In such cases Tord has made it very easy to adapt the existing Stockfish/Glaurung code for some new rules and because eval for the opponent is already in place, I can hope the new code maybe is just a counterbalance to that existing rule and not upsetting any equilibrium you may already have by introducing new code and new rules.

It is completely untuned and introduced some overlap with King Safety but that seemed to be hard to avoid. I have to check if I really did not have anything yet about own Rooks and Queens behind Passed Pawns or if I overlooked code in Stockfish about this, because it seems very fundamental. I vaguely remember writing something similar for the earlier Ancalagons that were not based on Stockfish.

Some new code related to Passed Pawns in build 327

Code: Select all


                // If the pawn is free to advance, increase bonus
                if (pos.square_is_empty(blockSq))
                {
                   Value bonuspoints;

                    b2 = squares_in_front_of(us, s);
                    b3 = b2 & ei.attacked_by(them);
                    b4 = b2 & ei.attacked_by(us);
                    b5 = EmptyBoardBB; // New bitboard, used for computing a bonus for the support of passed pawns by Rooks and Queens. 

                    // If there is an enemy rook or queen attacking the pawn from behind,
                    // add all X-ray attacks by the rook or queen.
                    if (    bit_is_set(ei.attacked_by(them,ROOK) | ei.attacked_by(them,QUEEN),s)
                        && (squares_behind(us, s) & pos.rooks_and_queens(them)))
                        b3 = b2; // The following 'else' clause is new and counterweight to the existing 'if' clause.
                    else if (bit_is_set(ei.attacked_by(us,ROOK) | ei.attacked_by(us,QUEEN),s)
                       && (squares_behind(us, s) & pos.rooks_and_queens(us)))
                    {
                        b5 = b2;
                        if (b5 & ei.kingZone[them]) mbonus += Value((tr * 0x100 * WeightKingSafety[them])/(100 * 0x100)); // This now influences King Safety calculations but this rule is probably rarely invoked.
                    }

The lay-out of the sourcecode is completely off when I copy and paste into a code block here, something with tabstops I don't see in the MSVC compiler IDE, so I just give a small fragment to give the general idea. It is both untuned and not tested yet, so not much sense reproducing everything related to this, b5 is used a few times further on, I hope the idea is clear.

Regards, Eelco
Debugging is twice as hard as writing the code in the first
place. Therefore, if you write the code as cleverly as possible, you
are, by definition, not smart enough to debug it.
-- Brian W. Kernighan
User avatar
Eelco de Groot
Posts: 4671
Joined: Sun Mar 12, 2006 2:40 am
Full name:   Eelco de Groot

Re: Good Test

Post by Eelco de Groot »

Eelco de Groot wrote:

12 154:22 +0.20 1...gxh4 2.Nf5 Qf8 3.Nxh4 Rc7 4.Qg4 Nh6
5.Qe6+ Qf7 6.Nb5 Na6 7.O-O-O Re7 8.Qxf7+ Rxf7
9.Nxd6 Rd7 10.Ndf5 Kf7 11.Rhg1 Bf8 12.Kc2 Rad8
13.Kb3 Nxf5 14.Nxf5 (3.946.302.282) 426

12 154:22 -1.40 1...Nh6 2.Bg3 Nd7 3.h4 a6 4.hxg5 fxg5
5.Qh5 Rcb8 6.f3 b5 7.O-O-O Kf8 8.Kb1 b4
9.Ne2 a5 10.Bf2 a4 (3.946.302.282) 426

12 154:22 -2.55 1...b5 2.cxb5 Nh6 3.Bg3 Qf7 4.h4 Rd8
5.hxg5 fxg5 6.Qh5 Qxh5 (3.946.302.282) 426
________________________________________________________________

12 163:31 +0.20 1...gxh4 2.Nf5 Qf8 3.Nxh4 Rc7 4.Qg4 Nh6
5.Qe6+ Qf7 6.Nb5 Na6 7.O-O-O Re7
8.Qxf7+ Rxf7 9.Nxd6 Rd7 10.Ndf5 Kf7
11.Rhg1 Bf8 12.Kc2 Rad8 13.Kb3 Nxf5
14.Nxf5 (4.182.299.254) 426

12 163:31 -1.40 1...Nh6 2.Bg3 Nd7 3.h4 a6 4.hxg5 fxg5
5.Qh5 Rcb8 6.f3 b5 7.O-O-O Kf8 8.Kb1 b4
9.Ne2 a5 10.Bf2 a4 (4.182.299.254) 426

12 163:31 -2.28 1...Qd8 2.Bg3 Nh6 3.h4 Nd7 4.Qh5 a6
5.hxg5 fxg5 6.Qh3 Qe7 7.Qe6+ Qxe6
8.dxe6 Nf6 9.Ned5 Nxd5 10.Nxd5 Rf8
11.Rh5 b5 12.cxb5 axb5 13.Rxg5 (4.182.299.254) 426
The rest of iteration 12 did not change much except some new moves in third place, and resolving this took a long time. Then on iteration 13 I think gxh4 would have fallen a lot but resolving this (with re-searches) took so long that it clearly was not practical anymore, I stopped the analysis after some 47 hours without a thirteen ply result :(


12 429:52 +0.20 1...gxh4 2.Nf5 Qf8 3.Nxh4 Rc7 4.Qg4 Nh6
5.Qe6+ Qf7 6.Nb5 Na6 7.O-O-O Re7 8.Qxf7+ Rxf7
9.Nxd6 Rd7 10.Ndf5 Kf7 11.Rhg1 Bf8 12.Kc2 Rad8
13.Kb3 Nxf5 14.Nxf5 (10.969.392.824) 425

12 429:52 -1.40 1...Nh6 2.Bg3 Nd7 3.h4 a6 4.hxg5 fxg5
5.Qh5 Rcb8 6.f3 b5 7.O-O-O Kf8 8.Kb1 b4
9.Ne2 a5 10.Bf2 a4 (10.969.392.824) 425

12 429:52 -1.90 1...Qe8 2.Bg3 Nh6 3.h4 Qg6 4.hxg5 fxg5
5.Qh5 Qxh5 6.Rxh5 Nf7 (10.969.392.824) 425
________________________________________________________________

12 443:57 +0.20 1...gxh4 2.Nf5 Qf8 3.Nxh4 Rc7 4.Qg4 Nh6
5.Qe6+ Qf7 6.Nb5 Na6 7.O-O-O Re7
8.Qxf7+ Rxf7 9.Nxd6 Rd7 10.Ndf5 Kf7
11.Rhg1 Bf8 12.Kc2 Rad8 13.Kb3 Nxf5
14.Nxf5 (11.328.005.077) 425

12 443:57 -1.40 1...Nh6 2.Bg3 Nd7 3.h4 a6 4.hxg5 fxg5
5.Qh5 Rcb8 6.f3 b5 7.O-O-O Kf8 8.Kb1 b4
9.Ne2 a5 10.Bf2 a4 (11.328.005.077) 425

12 443:57 -1.61 1...Nd7 2.Bg3 Nh6 3.h4 a6 4.hxg5 fxg5
5.Qh5 b5 6.cxb5 Rcb8 7.Qe2 axb5
8.Nxb5 Ra4 9.f3 Rb4 10.a4 Qf8 11.O-O Nb6
12.Nc3 Nd7 13.Rab1 Nb6 (11.328.005.077) 425
________________________________________________________________

12 460:31 +0.20 1...gxh4 2.Nf5 Qf8 3.Nxh4 Rc7 4.Qg4 Nh6
5.Qe6+ Qf7 6.Nb5 Na6 7.O-O-O Re7
8.Qxf7+ Rxf7 9.Nxd6 Rd7 10.Ndf5 Kf7
11.Rhg1 Bf8 12.Kc2 Rad8 13.Kb3 Nxf5
14.Nxf5 (11.751.084.685) 425

12 460:31 -1.40 1...Nh6 2.Bg3 Nd7 3.h4 a6 4.hxg5 fxg5
5.Qh5 Rcb8 6.f3 b5 7.O-O-O Kf8 8.Kb1 b4
9.Ne2 a5 10.Bf2 a4 (11.751.084.685) 425

12 460:31 -1.42 1...Rd8 2.Bg3 Nh6 3.h4 Qf7 4.hxg5 fxg5
5.Qh5 Qxh5 6.Rxh5 Nf7 (11.751.084.685) 425

best move: Rc8-d8 time: 2826:55.672 min n/s: 379.586 nodes: 64.383.751.877

Build 328 is maybe a little step in the better direction with King Safety of the Rook or Queen supported Passed Pawn now also counting in the endgame;

Code: Select all

else if (bit_is_set(ei.attacked_by(us,ROOK) | ei.attacked_by(us,QUEEN),s)
          && (squares_behind(us, s) & pos.rooks_and_queens(us)))
{
	b5 = b2;
	if (b5 & ei.kingZone[them])
	{
		mbonus += Value((tr * 0x100 * WeightKingSafety[them])/(100 * 0x100)); // This now influences King Safety calculations.
		ebonus += Value((tr * 0x100 * WeightKingSafety[them])/(200 * 0x100));
	}						
}
The results for build 328 are just in :) ; With this one line change the deep analysis result for the position after 1. Ne3 seems to be changed much more than I would have expected, and once more changes in eval for specific situations can have a dramatic impact. At least compared to that 2826 min without a thirteenth ply result for the previous build.

[d]rnr3k1/pp2qnb1/3p1p2/2pPp1p1/2P1P2B/2N1N2P/PP3P2/R2QK2R b KQ -

Engine: Ancalagon 1.3 Weak Squares 180 Board Control middlegame 50 endgame 50
Build 328 (Athlon 2009 MHz, 256 MB) by Romstad, Costalba, Kiiski, de Groot

2.00 0:01 +0.60 1...gxh4 2.Nf5 Qd7 3.Nb5 Na6 4.Rg1 Ng5
5.Nbxd6 (676.627) 393

3.01 0:02 +1.92 1...gxh4 2.Qh5 Qf8 3.Nf5 (1.036.408) 414

4.01 0:06 +0.54 1...gxh4 2.Nf5 Qf8 3.Nb5 Ng5 4.Qh5 Nxe4
5.Rg1 Ng5 6.Nbxd6 (2.865.118) 429

5.01 0:07 +1.06 1...gxh4 2.Nf5 Qf8 3.Nb5 Ng5 4.Rg1 Rd8
5.Nc7 Nd7 6.Nxa8 Rxa8 (3.075.853) 439

6.01 0:16 +0.84 1...gxh4 2.Nf5 Qf8 3.Rg1 Ng5 4.Nb5 Na6
5.Nbxd6 Rd8 6.Nxb7 Rd7 7.Na5 Nxh3
8.Rg4 (7.450.370) 450

7.01 0:18 +1.25 1...gxh4 2.Nf5 Qf8 3.Rg1 Ng5 4.Nb5 Na6
5.Nbxd6 Rc7 6.Qb3 Rd7 7.Nxb7 Nxe4 (8.569.071) 461

8.01 0:23 +1.12 1...gxh4 2.Nf5 Qf8 3.Rg1 Ng5 4.Nb5 Na6
5.Nbxd6 Rd8 6.Nb5 Nb4 7.Kf1 a6 (11.346.875) 473

9.01 0:59 +0.46 1...gxh4 2.Nf5 (28.289.785) 478

10.01 38:25 -1.04 1...gxh4 2.Qg4 Na6 3.Qxh4 Nb4 4.Nf5 Qf8
5.O-O-O Nh6 6.Nxg7 Kxg7 (1.000.655.584) 433

11.01 44:14 -1.00 1...gxh4 2.Qg4 Na6 3.Qxh4 Nb4 4.Nf5 Qf8
5.O-O-O Nh6 6.Nxg7 Kxg7 7.Rhg1+ Kh7
8.a3 Qe7 9.Rg3 Rg8 10.axb4 Rxg3
11.fxg3 cxb4 (1.146.055.745) 431

12.01 177:11 -2.62 1...gxh4 2.Nf5 Qd7 3.Qh5 Ng5 4.O-O-O Rf8
5.Nxh4 Qf7 6.Qg4 Kh8 (4.730.746.998) 444

12.02 200:58 -2.00 1...Na6 2.Bg3 Nh6 3.h4 Rc7 4.hxg5 fxg5
5.Qh5 Qf6 6.O-O-O b6 7.a3 Rb8 8.Rdg1 Rf7
9.Bh2 Qxf2 10.Qxg5 Qf6 (5.322.438.252) 441

12.05 225:42 -1.41 1...Nh6 2.Bg3 Nd7 3.h4 a6 4.hxg5 fxg5
5.Qh5 Kf8 6.Rg1 b5 7.Bh2 g4 8.Nxg4 Qf7
9.Qxf7+ Kxf7 10.Ne3 b4 11.Ne2 Bf6
12.f3 Rg8 13.Kf2 (5.973.524.356) 441

13.01 314:25 -1.59 1...Nh6 2.Bg3 (8.210.691.644) 435
Debugging is twice as hard as writing the code in the first
place. Therefore, if you write the code as cleverly as possible, you
are, by definition, not smart enough to debug it.
-- Brian W. Kernighan