PFC Lives Again?

Yes! At last!   12 votes - 100 %
No, no it does not.   0 votes - 0 %
 
12 Total Votes
How about by hulver (5.66 / 3) #1 Fri Dec 05, 2003 at 05:03:49 AM EST
You can give a starting state to the game. EG.

RB---
-----
-----
-----

And the program has to play from that point.

You could then test it against different starts and see how it does.
--
smart, pretty, sane. pick two - georgeha


Well by codemonkey uk (3.00 / 0) #4 Fri Dec 05, 2003 at 05:18:43 AM EST
Any decent solution would handle that anyway, with a little modification. No, I wanted to keep this one simple. Limiting the programs function to solving the problem and outputting a solution seemed like a good way to avoid forcing people to write a whole bunch of messy IO code.

--- Thad ---
developer of ... ?
[ Parent ]

Sorry by Rogerborg (5.00 / 1) #27 Fri Dec 05, 2003 at 06:22:37 AM EST
A solution that handles that is over engineered for the problem as stated.  We all know what happens when you go back and change the requirements after the implementation is complete. ;-P

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

I'm not sure that's guaranteed. by ObviousTroll (5.50 / 2) #37 Fri Dec 05, 2003 at 07:51:49 AM EST
I'm sure there are some initial conditions that would be unsolvable. Trivial example: 24 spaces are already filled with black checkers.


"If we do see stacks of ashtrays," she said, "it is tantamount to the potential that people are permitting smoking." - NYC Health Inspector
[ Parent ]

Yep. by komet (5.00 / 1) #2 Fri Dec 05, 2003 at 05:07:11 AM EST
I recently did a diary poll which shows that a nice PFC would be welcomed by the Husiists. Unfortunately I haven't had enough time to come up with a good problem (I do have one problem, but I'm not sure it's solvable yet...)

--
<ni> komet: You are functionally illiterate as regards trashy erotica.


Whoa. by Evil Cloaked User (5.00 / 1) #3 Fri Dec 05, 2003 at 05:17:38 AM EST
I have a basic program that I wrote when I was 14 that pretty much solves this. That's a bit odd.

Pretty sure my original would get it's ass kicked though. Count me in though.


--
Still, I think most of the problem is just a mental hurdle to overcome, - Cloaked User


Good good by codemonkey uk (3.00 / 0) #5 Fri Dec 05, 2003 at 05:20:18 AM EST
This is supposed to be easy to solve so anyone can enter. It'll be the subjective quality of the solution that will decide the winner. :D

--- Thad ---
developer of ... ?
[ Parent ]

Deadline? by Evil Cloaked User (5.00 / 1) #6 Fri Dec 05, 2003 at 05:23:13 AM EST
When is this due in?


--
Still, I think most of the problem is just a mental hurdle to overcome, - Cloaked User
[ Parent ]

Ah, deadlines... by codemonkey uk (3.00 / 0) #9 Fri Dec 05, 2003 at 05:34:23 AM EST
Dunno. How about I post a deadline 2 working days before I close entry? You'll have at least a week, 'cos I'm off work as of tomorrow, until till January. I'm in the UK from the 14th of December. I expect I'll do the judging one day I'm in the UK when Andie is working, and Dylan is at nursery. Or of an evening. Anyway. I will let you know! :)

--- Thad ---
developer of ... ?
[ Parent ]

Assumptions. by Evil Cloaked User (5.00 / 1) #12 Fri Dec 05, 2003 at 05:40:37 AM EST
Are we allowed to make any assumptions regarding the hardware this will be run on? I remember before that you made a point regarding the fact that ascii characters don't necessarily have be stored as an 8bit value on all hardware architectures. Will you be frowning upon anything that makes similar such assumptions?


--
Still, I think most of the problem is just a mental hurdle to overcome, - Cloaked User
[ Parent ]

Yes by codemonkey uk (3.00 / 0) #16 Fri Dec 05, 2003 at 05:45:22 AM EST
I frown at all sorts of things. ;)

--- Thad ---
developer of ... ?
[ Parent ]

I'll be sure by Evil Cloaked User (5.00 / 1) #17 Fri Dec 05, 2003 at 05:46:46 AM EST
To verify my assumptions then.

I feel a plan forming... Shame I have paid work to do this evening. Bah!


--
Still, I think most of the problem is just a mental hurdle to overcome, - Cloaked User
[ Parent ]

Nice problem by TPD (5.00 / 1) #7 Fri Dec 05, 2003 at 05:33:11 AM EST
Hopefully will get a chance to have a look at this, even if only a producing very simple brute forcer... How long have we got to work on the problem?

What will be the judgement criteria (for instance are micro-optimisations for the sake of speed worth while?)

Have you posted this to the PFC mailing list?

Rock Hard Abs are just a sw-sw-swivel away!


1 week, perhaps more by codemonkey uk (3.00 / 0) #10 Fri Dec 05, 2003 at 05:35:38 AM EST
See this comment for details.

--- Thad ---
developer of ... ?
[ Parent ]

Cool by TPD (5.00 / 1) #19 Fri Dec 05, 2003 at 05:52:14 AM EST
will aim to knock up a piss poor Pascal entry next week then!

Rock Hard Abs are just a sw-sw-swivel away!
[ Parent ]

quick Pascal entry by TPD (3.00 / 0) #44 Fri Dec 05, 2003 at 09:37:08 AM EST

program Swapsy;

{$APPTYPE CONSOLE}
Uses SysUtils;

Type
    TPoint= Record
    x,y: Integer;
    end;

procedure Output(APoint: TPoint; colour: char);
begin
writeln(format('%S %D,%D', [colour, APoint.X, APoint.y]));
end;

var
     Board: Array [1..5,1..5] of Integer;
     PointsToFill: Array [0..24] of TPoint;
     TmpPoint: TPoint;
     SwapWith: Integer;
     i: Integer;

     function EmptyNeighbours(APoint: TPoint): Integer;
     begin
     Result := 0;
     if APoint.x > 1 then
         begin
         Result := Result + (Board[APoint.x - 1,APoint.y]);
         end;
     if APoint.y > 1 then
         begin
         Result := Result + (Board[APoint.x,APoint.y - 1]);
         end;
     if APoint.x < 5 then
         begin
         Result := Result + (Board[APoint.x + 1,APoint.y]);
         end;
     if APoint.y < 5 then
         begin
         Result := Result + (Board[APoint.x,APoint.y + 1]);
         end;
     end;

begin
for i := 0 to 24 do
    begin
    PointsToFill[i].x := (i mod 5) + 1;
    PointsToFill[i].y := (i div 5) + 1;
    end;

for i := 24 downto 1 do
    begin
    TmpPoint := PointsToFill[i];
    SwapWith := Random(i + 1);
    PointsToFill[i] := PointsToFill[SwapWith];
    PointsToFill[SwapWith] := TmpPoint;
    end;
for i := 0 to 24 do
    begin
    if EmptyNeighbours(PointsToFill[i]) mod 2 = 1 then
        begin
        Output(PointsToFill[i], 'B');
        end
    else
        begin
        Output(PointsToFill[i], 'R');
        end;
    Board[PointsToFill[i].x, PointsToFill[i].y] := 1;
    end;
end.







should compile with Free pascal compiler (http://www.freepascal.org/) though it's not tested. All it does is add in a random order the appropriate colour depending on whether the sqare it is adding to has an odd or even number of empty neighbours!

Rock Hard Abs are just a sw-sw-swivel away!
[ Parent ]

This adds nothing by TPD (3.00 / 0) #52 Sat Dec 06, 2003 at 05:52:16 AM EST
hadn't read EBK's entry when I wrote this! Might as well ignore it!

Rock Hard Abs are just a sw-sw-swivel away!
[ Parent ]

TPD := FUCKWIT; //codebug by TPD (3.00 / 0) #53 Tue Dec 09, 2003 at 01:19:14 AM EST
if you are going to post piss poor code on teh intarweb might as make it working pisspoor code....

Still think it should be ignored just didn't want broken code to remain there....

<Text>
program Swapsy;

{$APPTYPE CONSOLE}
Uses SysUtils;

Type
    TPoint= Record
    x,y: Integer;
    end;

procedure Output(APoint: TPoint; colour: char);
begin
writeln(format('%S %D,%D', [colour, APoint.X, APoint.y]));
end;

var
     Board: Array [1..5,1..5] of Integer;
     PointsToFill: Array [0..24] of TPoint;
     TmpPoint: TPoint;
     SwapWith: Integer;
     i: Integer;

     function EmptyNeighbours(APoint: TPoint): Integer;
     begin
     Result := 0;
     if APoint.x > 1 then
         begin
         Result := Result + 1-(Board[APoint.x - 1,APoint.y]);
         end;
     if APoint.y > 1 then
         begin
         Result := Result + 1-(Board[APoint.x,APoint.y - 1]);
         end;
     if APoint.x < 5 then
         begin
         Result := Result + 1-(Board[APoint.x + 1,APoint.y]);
         end;
     if APoint.y < 5 then
         begin
         Result := Result + 1-(Board[APoint.x,APoint.y + 1]);
         end;
     end;

begin
for i := 0 to 24 do
    begin
    PointsToFill[i].x := (i mod 5) + 1;
    PointsToFill[i].y := (i div 5) + 1;
    end;

for i := 24 downto 1 do
    begin
    TmpPoint := PointsToFill[i];
    Board[TmpPoint.x, TmpPoint.y] := 0;
    SwapWith := Random(i + 1);
    PointsToFill[i] := PointsToFill[SwapWith];
    PointsToFill[SwapWith] := TmpPoint;
    end;
for i := 0 to 24 do
    begin
    if EmptyNeighbours(PointsToFill[i]) mod 2 = 1 then
        begin
        Output(PointsToFill[i], 'B');
        end
    else
        begin
        Output(PointsToFill[i], 'R');
        end;
    Board[PointsToFill[i].x, PointsToFill[i].y] := 1;
    end;
end.
</Text>

Rock Hard Abs are just a sw-sw-swivel away!
[ Parent ]

Three questions by yicky yacky (5.00 / 1) #8 Fri Dec 05, 2003 at 05:33:39 AM EST
  1. Any limits on which language?
  2. Grid is counted from 1 and not 0?
  3. Do the flips daisy-chain - e.g. flipping 2,2 causes 2,3 to flip - does this in turn cause 2,4 to flip (if occupied) given that it's adjacent to 2,3 but not 2,2? (this may seem like a stupid question but it makes a difference).

----
17 days left ...


Three answers by codemonkey uk (5.00 / 1) #11 Fri Dec 05, 2003 at 05:40:17 AM EST
  1. No. I expect I will be testing on an iMac, so availability may be an issue, in which case I will do my best to accommodate.
  2. Yes.
  3. No. Placing a counter flips directly adjacent counters. No diagonals, no chains.


--- Thad ---
developer of ... ?
[ Parent ]

placing != flipping [n/t] by Rogerborg (5.00 / 2) #15 Fri Dec 05, 2003 at 05:45:01 AM EST


-
Metus amatores matrum compescit, non clementia.
[ Parent ]

Oh by hulver (5.00 / 1) #13 Fri Dec 05, 2003 at 05:41:55 AM EST
I'm assuming Diagonals count as well?

IE.

1,1 Will flip when you play at 2,2?
--
smart, pretty, sane. pick two - georgeha


No by codemonkey uk (3.00 / 0) #14 Fri Dec 05, 2003 at 05:44:06 AM EST
Diagonals are not adjacent.

--- Thad ---
developer of ... ?
[ Parent ]

Hm, maybe I'm missing something by komet (5.00 / 1) #18 Fri Dec 05, 2003 at 05:50:49 AM EST
(spoiler in child comment)

--
<ni> komet: You are functionally illiterate as regards trashy erotica.


entry that seems way too simple by komet (6.00 / 3) #20 Fri Dec 05, 2003 at 05:54:44 AM EST
couldn't you just start with the board you want at the end (i.e. all red), take away tokens one at a time recording their colours and flipping properly, until you're left with an empty board? Or is that what you mean by "against the spirit"? In any case, here is my entry which does just that (output has to be piped through tac :)

#include <stdio.h>
#include <string.h>

char* flip(char* board, int n)
{
    if (board[n] == 'R')
        board[n] = 'B';
    else if (board[n] == 'B')
        board[n] = 'R';
    return board;
}

char* fxy(char* board, int x, int y)
{
    if (x < 0) return board;
    if (x >= 5) return board;
    if (y < 0) return board;
    if (y >= 5) return board;
    return flip(board, y * 5 + x);
}

char* go(char* board, int n)
{
    int x, y;
    x = n % 5;
    y = n / 5;
    printf("%c %d,%d\n", board[n], x + 1, y + 1);
    board[n] = '-';
    fxy(board, x - 1, y);
    fxy(board, x + 1, y);
    fxy(board, x, y - 1);
    fxy(board, x, y + 1);
    return board;
}

void main(void)
{
    int i;
    char* p;
    char board[26] = "RRRRRRRRRRRRRRRRRRRRRRRRR";

    while (strcmp(board, "-------------------------")) {
/*      printf("%s\n", board);*/
        if ((p = strchr(board, 'R')) == NULL)
            p = strchr(board, 'B');
        go(board, p - board);
    }
}


--
<ni> komet: You are functionally illiterate as regards trashy erotica.
[ Parent ]

I think by TPD (5.00 / 2) #22 Fri Dec 05, 2003 at 06:04:36 AM EST
Hulvers additional criteria might be needed!

Rock Hard Abs are just a sw-sw-swivel away!
[ Parent ]

I do think it's a bit simple by hulver (5.00 / 2) #23 Fri Dec 05, 2003 at 06:10:12 AM EST
If you don't have the option of a starting board, but I can see codemonkey's point.

It not to write the most sensible entry, but to write one that does it best

If you see what I mean.
--
smart, pretty, sane. pick two - georgeha
[ Parent ]

Codemonkey by TPD (5.00 / 1) #28 Fri Dec 05, 2003 at 06:25:32 AM EST
already specified that a good program would be expected to be able to work from a start position...

if he want to remove IO from the equation perhaps we should have a hardcoded (valid, non empty) start position as part of the problem.

Rock Hard Abs are just a sw-sw-swivel away!
[ Parent ]

I don't know why by hulver (5.00 / 2) #29 Fri Dec 05, 2003 at 06:29:18 AM EST
He thinks IO would be overly complicated. It's no more difficult to read in a start position, than it is to output the solution.

You could just assume that the input is going to be a valid format, and that makes it even simpler, it doesn't have to be robust.
--
smart, pretty, sane. pick two - georgeha
[ Parent ]

IIRC by Evil Cloaked User (5.00 / 1) #30 Fri Dec 05, 2003 at 06:41:15 AM EST
There had been complaints in previous PFCs that too much emphasis was put on IO and not enough on the algorithms employed. There was one where memory-mapping the IO was deemed faster than opening a file for reading and all sorts of other screwing around. I think he just wants to avoid that sort of thing.


--
Still, I think most of the problem is just a mental hurdle to overcome, - Cloaked User
[ Parent ]

That was mine by hulver (5.00 / 1) #31 Fri Dec 05, 2003 at 06:46:12 AM EST
Where reading a file as quickly as possible was the point of the PFC.

Reading in the initial state of a 5x5 board isn't exactly going to stress any sort of machine though.

Even a mac.
--
smart, pretty, sane. pick two - georgeha
[ Parent ]

Why so it was. by Evil Cloaked User (5.00 / 1) #33 Fri Dec 05, 2003 at 06:49:14 AM EST
Yeah, I cheated on that one. That was fun.


--
Still, I think most of the problem is just a mental hurdle to overcome, - Cloaked User
[ Parent ]

I still have a by TPD (5.00 / 1) #34 Fri Dec 05, 2003 at 07:13:55 AM EST
unenterred nice little Ternary tree entry, cause you moved the submission dates on that one!

Curses!

Rock Hard Abs are just a sw-sw-swivel away!
[ Parent ]

Yes by codemonkey uk (3.00 / 0) #32 Fri Dec 05, 2003 at 06:47:14 AM EST
The IO is a chore, and nothing more.

--- Thad ---
developer of ... ?
[ Parent ]

On second thoughts it doesn't help by TPD (5.00 / 2) #40 Fri Dec 05, 2003 at 08:24:49 AM EST
given any valid start position to work back to it each fixed square must have had the same number of swaps as it's just how many adjacent empty squares are in the orignal start position...

Therefore I think working backwards and not touching filled start position squares should always work!

Rock Hard Abs are just a sw-sw-swivel away!
[ Parent ]

Yup by Rogerborg (5.50 / 2) #26 Fri Dec 05, 2003 at 06:21:25 AM EST
I'd started on a recursive partitioning kajigger1, when I realised that this problem has:
  • A known start state.
  • A known end state.
  • 25 steps from one to the other.
Given that, your solution is 100% (well, 25/25ths) efficient.  I'm not sure how a more complicated solution can be considered more elegant, unless this is a competion to create a delicate, highly engineered machine, and then use it to hammer in a nail.

1 because I like writing recursive partitioning kajiggers, which perhaps is the point of this exercise.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

OPTIMIZED ENTRY by komet (6.00 / 1) #50 Fri Dec 05, 2003 at 01:28:28 PM EST
ok, it looks like it was the correct idea after all, however my solution above wasn't quite O(n) due to my superfluous usage of strchr.

Here, then, is my optimized entry, O(n) in time and memory, and it even gives the answer the right way round :)

#include <stdio.h>
#include <string.h>

char* flip(char* board, int n)
{
        if (board[n] == 'R')
                board[n] = 'B';
        else if (board[n] == 'B')
                board[n] = 'R';
        return board;
}

char* fxy(char* board, int x, int y)
{
        if (x < 0) return board;
        if (x >= 5) return board;
        if (y < 0) return board;
        if (y >= 5) return board;
        return flip(board, y * 5 + x);
}

char* go(char* board, int n)
{
        char buf[80];
        int x, y;
        x = n % 5;
        y = n / 5;
        sprintf(buf, "%c %d,%d", board[n], x + 1, y + 1);
        board[n] = '-';

        fxy(board, x - 1, y);
        fxy(board, x + 1, y);
        fxy(board, x, y - 1);
        fxy(board, x, y + 1);
        return strdup(buf);
}

void main(void)
{
        int i;
        char* p;
        char board[26] = "RRRRRRRRRRRRRRRRRRRRRRRRR";
        char *moves[25];

        for (i = 0; i < 25; i++)
                moves[i] = go(board, i);

        for (i = 24; i >= 0; i--)
                printf("%s\n", moves[i]);
}


--
<ni> komet: You are functionally illiterate as regards trashy erotica.
[ Parent ]

Hey! by Ranieri (5.00 / 1) #21 Fri Dec 05, 2003 at 05:57:31 AM EST
There is a 1D version of this puzzle in SW:KOTOR.



Quick stab by EyeballKid (5.00 / 1) #24 Fri Dec 05, 2003 at 06:16:20 AM EST
I think I'm probably misinterpreting the problem, but here's my entry anyway:

Compiling:
gcc -o bcpfc bcpfc.c

Usage:
bcpfc <width> <height>

Algorithm:
I count the number of free spaces around the space I'm considering. This is the number of times a counter placed there will be flipped between now and the board being filled. So if it's an even number I place a red, if it's odd I place a blue.

I've taken a couple of shortcuts (yeah yeah premature optimisation is the root of all evil and all that... but in this case it was less typing):

Because of the order I place down counters, I know that left and above slots will always be filled, so I don't even bother checking.

Also, I know that I'll never have more than two empty slots, so I do my odd/even test as a small lookup table.

Right. Now back to the day job.

Ben.




bcpfc source by EyeballKid (6.00 / 1) #25 Fri Dec 05, 2003 at 06:17:41 AM EST
/* bcpfc.c
 * by Ben Campbell
 */

#include <stdio.h>

int main( int argc, char* argv[] )
{
    int w,h,x,y,right,below;

    /* index this with empty-neighbour-count to get move */
    const char lookup[3] = "RBR";

    /* cmdline parsing */
    if( argc<3 )
    {
        printf( "usage: bcpfc <width> <height>\n" );
        return 1;
    }
    w = atoi(argv[1]);
    h = atoi(argv[2]);

    /* Make a decision for each position...
     * Our scanning order means that slots above and left are _never_ empty, so
     * we don't even need to check. */
    for( y=1; y<=h; ++y )
    {
        /* always a clear spot below, except on last line */
        below = (y==h) ? 0:1;
        for( x=1; x<=w; ++x )
        {
            /* always a clear spot right, except on last column */
            right = (x==w) ? 0:1;
            printf( "%c %d,%d\n", lookup[ below + right ], x, y );
        }
    }
    return 0;
}


[ Parent ]

Damn it! by ObviousTroll (5.00 / 1) #42 Fri Dec 05, 2003 at 08:53:06 AM EST
I wish I hadn't read your post...


"If we do see stacks of ashtrays," she said, "it is tantamount to the potential that people are permitting smoking." - NYC Health Inspector
[ Parent ]

Darn it. by jacob (5.00 / 1) #35 Fri Dec 05, 2003 at 07:34:26 AM EST
I did a solution that used what I thought was quite a clever algorithm, but realized komet did the same thing but beat me to it. I'll post mine anyway, because it shows a nice trick from the functional programming world, but don't consider this an official submission. Maybe I'll do up a forward-iterating program later on. Code and discussion follows in a child comment.

--



The code by jacob (6.00 / 1) #36 Fri Dec 05, 2003 at 07:45:15 AM EST
My program uses the same idea komet's does: rather than placing pieces on the board until you get the desired end state, start with a complete board at the desired end state and take pieces away until you have none left. This is a simple, clear, no-fuss-no-muss linear-time algorithm. (Technically implementation doesn't take linear time due to a representation choice, but I could easily fix that if scalability were a goal of the problem.)

My solution differs from komet's primarily because my program uses a novel representation of a board as a function that maps x,y coordinates to colors: see the function reverse for the best illustration of that. Due to this representation choice, it's trivial to scale the program to any size board (though it becomes increasingly inefficient), but note the funny quirk that in fact my board representation has a color mapping not just for 1,1 through 5,5 but for any number pair you present it with, and you could think of my loop as removing a 5*5 area from an infinite field of red tiles.

Anyway, here's the program:


(define-values (RED BLACK EMPTY) (values #\R #\B 'empty))
(define-struct move (color h w))
(define (show-move m) (printf "~a ~a,~a\n" (move-color m) (move-h m) (move-w m)))


(define init-board (lambda (h w) RED))
(define (remove x y b)
  (lambda (x2 y2)
    (cond
      [(and (= x2 x) (= y2 y)) EMPTY]
      [(or
        (and (= x2 (add1 x)) (= y2 y))
        (and (= x2 (sub1 x)) (= y2 y))
        (and (= x2 x) (= y2 (add1 y)))
        (and (= x2 x) (= y2 (sub1 y))))
       (flip (b x2 y2))]
      [else (b x2 y2)])))


(define (flip c)
  (cond
    [(eq? c RED) BLACK]
    [(eq? c BLACK) RED]
    [(eq? c EMPTY) EMPTY]))


(define (solve board)
  (define (outer i b)
    (cond
      [(> i 5) '()]
      [else (inner i 1 b)]))
  (define (inner i j b)
    (cond
      [(> j 5) (outer (add1 i) b)]
      [else (cons (make-move (b i j) i j) (inner i (add1 j) (remove i j b)))]))
  (reverse (outer 1 board)))
 


(for-each show-move (solve init-board))

Runs in PLT Scheme, probably any version in the last 10 years, but certainly in version 200+. Just open it in DrScheme and hit execute.

--

[ Parent ]

err, see the function 'remove', not 'reverse' [nt] by jacob (5.00 / 1) #38 Fri Dec 05, 2003 at 07:52:13 AM EST


--

[ Parent ]

Are you talking about a BFMI program? by ObviousTroll (5.00 / 1) #39 Fri Dec 05, 2003 at 08:12:41 AM EST
For smaller grids, it would be trivial to try every possible state. Since many states would repeat, I don't think the tree would even be that large. But for your full problem, I don't think Brute Force and Massive Ignorance is possible without getting my grid involved.

What's the theoretical limit, here 3^25 possible states? Yeah. About 850 billion possible states. Even with a sparse data representation that's probably not useful.

For example, you could encode the entire board as a 64 bit word (2 bits per cell). At this point, each board becomes its own "hash look up value". The overhead would come from maintaining transition information. Worst case might be the empty board, which has 50 possible transistions; but maybe not..

(thinking)

Yeah - I think that's so. Worst case is a node of the tree might have 50 children.  This means that any kind of tree span would be intolerable; it's almost guaranteed to waste as much storage as possible.

OTOH, an "intelligent" scoring algorithm would still need a tree for backtrack and undo. Hmmm...



"If we do see stacks of ashtrays," she said, "it is tantamount to the potential that people are permitting smoking." - NYC Health Inspector


Hmmm... by codemonkey uk (3.00 / 0) #41 Fri Dec 05, 2003 at 08:52:32 AM EST
The tree depth is 25. The branching factor is always less than 50, and getting smaller with every move. Roughly 3/4 of the search space is redundant. I've not tried it, but I think a dumb depth first search would find a solution fairly quickly.

Of course, this claim rests on my definition of "fairly quickly".

The the point is moot since two signficantly better solutions have already been posted.

--- Thad ---
developer of ... ?
[ Parent ]

Possible permutations... by ObviousTroll (5.00 / 1) #43 Fri Dec 05, 2003 at 09:03:46 AM EST
Yeah, I'm flip flopping on this. I think I might try it though; because neither given solution handles the arbitrary starting position.


"If we do see stacks of ashtrays," she said, "it is tantamount to the potential that people are permitting smoking." - NYC Health Inspector
[ Parent ]

my real entry by jacob (5.00 / 1) #45 Fri Dec 05, 2003 at 09:45:08 AM EST
follows as a child comment

--



here it is by jacob (6.00 / 1) #46 Fri Dec 05, 2003 at 09:49:29 AM EST
This one generates a random valid solution every time it's executed. It works on an odd/even principle: select an unoccupied square at random, and if it has an even number of occupied squares surrounding it put a red token there; otherwise put a black token there. This works because every square with an even number of unoccupied squares will in the course of the rest of the game be flipped an even number of times and therefore will end up the same color it started; the opposite is true for squares with an odd number of unoccupied neighbors.


(require (lib "1.ss" "srfi"))
(define HEIGHT 5)
(define WIDTH 5)


(define-struct move (color h w))
(define (show-move m) (printf "~a ~a,~a\n" (move-color m) (add1 (move-h m)) (add1 (move-w m))))
(define (randomly-select l)
  (let ((i (random (length l))))
    (values (list-ref l i) (append (take l i) (drop l (add1 i))))))
(define (neighbors p)
  (let ((x (car p))
        (y (cadr p)))
    (list (list x (add1 y))
          (list x (sub1 y))
          (list (add1 x) y)
          (list (sub1 x) y))))

(define (num-open-neighbors p b) (apply + (map b (neighbors p))))
(define (color-for-square p b) (if (even? (num-open-neighbors p b)) #\R #\B))
(define (place p b) (lambda (p2) (if (equal? p p2) 0 (b p2))))

(define (solve board)
  (define unplaced
    (let loop ((i 0) (j 0))
      (cond
        [(>= i HEIGHT) '()]
        [(>= j WIDTH) (loop (add1 i) 0)]
        [else (cons (list i j) (loop i (add1 j)))])))
  (define (place-pieces ps b)
    (cond
      [(null? ps) '()]
      [else
       (let-values ([(point rest) (randomly-select ps)])
         (cons (apply make-move (color-for-square point b) point)
               (place-pieces rest (place point b))))]))
  (place-pieces unplaced board))

(define initial-board
  (lambda (p)
    (let ((x (car p)) (y (cadr p)))
      (if (and (>= x 0) (>= y 0) (< x HEIGHT) (< y WIDTH))
          1
          0))))

(for-each show-move (solve initial-board))

Again, to run copy this code into DrScheme and hit execute.

--

[ Parent ]

God damn it!!!! by jacob (5.00 / 1) #47 Fri Dec 05, 2003 at 09:51:48 AM EST
Seems that eyeballkid beat me to the punch, making this the second time in a row my algorithm was already thought of. I'm not doing another one, though. So there.

--

[ Parent ]

here's the same thing in Haskell by jacob (6.00 / 1) #48 Fri Dec 05, 2003 at 12:58:39 PM EST
Haskell is very pretty. This one gives back the same answer every time, but compared to the Scheme version I think it's much much prettier.

type Point = (Int,Int)
type Board = Point -> Bool
data Color = Red | Black

neighbors                :: Point -> [Point]
neighbors (x,y)          = [(x-1,y),(x+1,y),(x,y-1),(x,y+1)]

numOpenNeighbors         :: Point -> Board -> Int
numOpenNeighbors p b     = sum (map (\ p -> if (b p) then 1 else 0) (neighbors p))

colorForPoint            :: Point -> Board -> Color
colorForPoint p b        = if even (numOpenNeighbors p b) then Red else Black

place                    :: Point -> Board -> Board
place p b                = (\ p' -> if p' = p then False else b p')

solve                    :: [Point] -> Board -> [(Color,Point)]
solve  []    b           = []
solve (p:ps) b           = ((colorForPoint p b),p):(solve ps (place p b))

initialBoard             :: Int -> Int -> Board
initialBoard h w (x,y)   = x > 0 && y > 0 && x <
h && y <= w

toStr  []                = ""
toStr ((Red,  (x,y)):ms) = "R "++(show x)++","++(show y)++"\n"++(toStr ms)
toStr ((Black,(x,y)):ms) = "B "++(show x)++","++(show y)++"\n"++(toStr ms)

main = putStr (toStr (solve [(x,y) | x <- [1..5], y <- [1..5]] (initialBoard 5 5)))

To run, save the code to a file called flip.hs, then download and install GHC and compile with ghc flip.hs. Then ./a.out will print the answer for you.

--

[ Parent ]

Heh. by celeriac (5.00 / 1) #49 Fri Dec 05, 2003 at 01:06:30 PM EST
Well it appears that komet solved it and EyeballKid solved it in the general case. I don't think there can be any substantial improvement on their algorithms. Meh.



You think *you* feel bad... by ObviousTroll (5.00 / 1) #51 Fri Dec 05, 2003 at 02:18:48 PM EST
I have a complete hash- and tree- based version built. Then they go and solve it in 30 lines!


"If we do see stacks of ashtrays," she said, "it is tantamount to the potential that people are permitting smoking." - NYC Health Inspector
[ Parent ]

Crap! I missed it. by tmoertel (5.00 / 2) #54 Wed Dec 10, 2003 at 08:03:54 PM EST
Look what happens when I step away from the keyboard for a few days.

Sigh.

--
Write Perl code? Check out LectroTest. Write markup-dense XML? Check out PXSL.



It's not finished yet by hulver (5.00 / 1) #55 Thu Dec 11, 2003 at 08:57:15 AM EST
Post an entry!
--
smart, pretty, sane. pick two - georgeha
[ Parent ]

My (possibly to be disqualified entry) by TPD (5.00 / 1) #56 Fri Dec 12, 2003 at 03:07:49 AM EST
as a little exercise I decided to try and solve the problem but using as few black placements as possible...

This will only play red squares where Height and width of the board are both odd (or even even), but is forced to play a black square where they differ (odd/even). It works by hugging edges and working on smaller and smaller boards as 2 connected edges are fully filled.

It's pretty much a hardcoded solution, so it's probably a good candidate for immediate disqualification.

It's only been tested against boards in my head so may be hideously broken/flawed!

Compiles under Delphi and fpc with the command line...

fpc mostlyred.dpr -Sd

Code to follow

Rock Hard Abs are just a sw-sw-swivel away!


Mostlyred.dpr by TPD (3.00 / 0) #57 Fri Dec 12, 2003 at 03:16:28 AM EST

program MostlyRed;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
    Height, Width, Tmp, i: Integer;
    lineswritten: Integer = 0;
    OrientationFormat: String = '%0:D %1:D %2:S';

    procedure output(x,y: Integer; colour: Char);
    begin
    writeln(format(OrientationFormat, [x, y, Colour]));
    inc(linesWritten);
    end;

begin
Width := 5;
Height := 5;

//add width and Height Params to change board size...
if ParamCount >= 2 then
    begin
    width := StrToInt(Paramstr(1));
    Height := StrToInt(Paramstr(2));
    end;

if Height > Width then
    begin
    Tmp := Width;
    Width := Height;
    Height := Tmp;
    OrientationFormat := '%1:D %0:D %2:S';
    end;

while Height > 1 do
    begin
    for i := 1 to Height - 1 do
        begin
        output(Width, i, 'R');
        end;
    for i := 1 to Width do
        begin
        output(i, Height, 'R');
        end;
    Dec(Height);
    Dec(Width);
    end;

//If we are left with an even strip then we need to add one black cell to get an odd one
if width mod 2 = 0 then
    begin
    output(width, 1, 'B');
    Dec(Width);
    end;

i := 2;
while i <= width do
    begin
    output(i, 1, 'R');
    inc(i,2);
    end;

i := 1;
while i <= width do
    begin
    output(i, 1, 'R');
    inc(i,2);
    end;

//was just a check so I could at least x*y moves had been made...
//writeln(linesWritten);
end.


Rock Hard Abs are just a sw-sw-swivel away!
[ Parent ]

Deadline by codemonkey uk (3.00 / 0) #58 Fri Dec 12, 2003 at 06:23:56 AM EST
The deadline is: 20:00 GMT Monday the 15th of December.

--- Thad ---
developer of ... ?


Scan line order by Alan Crowe (3.00 / 0) #59 Fri Dec 12, 2003 at 04:07:55 PM EST
I place my counters left to right, top to bottom. Most of the counters get reversed twice so must start red. They are reversed by the next counter, and by the counter in the same column, but on the row below. The exceptions are the right hand column and the bottom row, which only get one reversal, so must be placed black. The last counter is a special case. It doesn't get reversed at all so must be red.

My code is in ANSI Common Lisp. Load it, and run it with

(print-out-solution)

for the default 5x5 case.

(print-out-solution n m) for the general case.




ANSI Common Lisp by Alan Crowe (3.00 / 0) #60 Fri Dec 12, 2003 at 04:13:36 PM EST
(defun xor (a b)
  (if a (not b) b))

(defun character-code(boolean)
  (if boolean #\B #\R))

(defun print-out-solution (&optional (board-width 5)
                     (board-height 5))
  (loop for i from 1 to board-height do
    (loop for j from 1 to board-width do
      (format t "~c ~d,~d~%"
          (character-code
           (xor (= i board-height);bottom row
            (= j board-width)));right-hand column
          i j))))

[ Parent ]

Tentative try. by Soviet Russian (5.00 / 1) #61 Sun Dec 14, 2003 at 01:13:01 PM EST
I'm sure I'm doing something wrong here, or atleast cheating the spirits etc.
It's essentially based on Jacob's algorithm.



husipfc1.c by Soviet Russian (6.00 / 1) #62 Sun Dec 14, 2003 at 01:20:59 PM EST
#include <stdio.h>
#define NUM 5
main()
{
    int i,j;
    for (i=1;i<NUM+1;i++)
       for(j=1;j<NUM+1;j++)
          printf("%c %d,%d \n",((i<NUM)+(j<NUM))%2?'B':'R',i,j);
}


[ Parent ]

Winners by codemonkey uk (5.66 / 3) #63 Wed Dec 17, 2003 at 06:05:46 AM EST
And the winners are, according to Top Secret judging criteria, are, in joint first place: komet & EyeballKid, for their quick, simple, and insightful solutions.

Either winner can claim their token prize by contacting me via my the form on my website.

Everyone else came 3rd. I hope you had fun! :)

--- Thad ---
developer of ... ?


shall we follow traditition by jacob (5.00 / 1) #64 Wed Dec 17, 2003 at 06:20:33 AM EST
by inviting either winner to host the next PFC?

--

[ Parent ]

Yes by codemonkey uk (5.00 / 1) #65 Wed Dec 17, 2003 at 06:23:26 AM EST
But I doubt EyeballKid will, so I expect it is up to komet.

--- Thad ---
developer of ... ?
[ Parent ]

Yes by komet (5.00 / 1) #69 Wed Dec 17, 2003 at 07:35:03 AM EST
It's been on my todo list for a while now.

--
<ni> komet: You are functionally illiterate as regards trashy erotica.
[ Parent ]

Hey! by EyeballKid (5.00 / 1) #71 Thu Dec 18, 2003 at 01:45:03 AM EST
I resent that!
But I don't deny it :-(

Nice one komet!


[ Parent ]

And thanks to codemonkey for organising it! by EyeballKid (5.00 / 1) #72 Thu Dec 18, 2003 at 01:46:50 AM EST


[ Parent ]

So do you want your prize? by codemonkey uk (3.00 / 0) #73 Thu Dec 18, 2003 at 09:38:33 AM EST
Or what? :P

--- Thad ---
developer of ... ?
[ Parent ]

I did it for humanity, not riches. by EyeballKid (5.00 / 2) #74 Tue Dec 23, 2003 at 03:20:56 AM EST
But yes. Of course I'll be claiming my loot.


[ Parent ]

and can we please , please by garlic (5.50 / 2) #66 Wed Dec 17, 2003 at 06:23:35 AM EST
not post answers to the same diary posting the question?

[ Parent ]

Seconded [nt] by gazbo (5.00 / 1) #70 Wed Dec 17, 2003 at 07:43:40 AM EST


"Engarde!" cried the larvae, huskily. - Scrymarch

[ Parent ]

Thanks for the competition... by TPD (5.00 / 2) #67 Wed Dec 17, 2003 at 06:49:41 AM EST
And more thanks for stepping up and kickstarting the PFCs again!

Had lots of fun dreaming up my only red playing entry, even though I knew it was never going to be a contender...

Hopefully we'll see a follow up pfc posted from Komet soon.

Rock Hard Abs are just a sw-sw-swivel away!
[ Parent ]

Hooray! by komet (5.00 / 1) #68 Wed Dec 17, 2003 at 07:34:17 AM EST


--
<ni> komet: You are functionally illiterate as regards trashy erotica.
[ Parent ]