Omnimaga

General Discussion => Technology and Development => Computer Projects and Ideas => Topic started by: Juju on July 29, 2013, 12:42:20 am

Title: 60 lines Binary Puzzle in php and ncurses
Post by: Juju on July 29, 2013, 12:42:20 am
I decided to try implementing a binary puzzle as well, but in php and ncurses and, to my amazement, I managed to do it under 75 lines of code. Paste this in a php file, uncomment the ncurses and gmp extentions in php.ini and run this in command line. Supports color, multiple grid sizes, multiple puzzles and all the conditions to win! Also optionally takes a puzzle set filename and puzzle number as argument.

puzzle.php:
Code: [Select]
<?php // 75 lines Binary Puzzle by Juju v1.0 | http://juju2143.ca | Licensed under GPLv3
$puzzles explode("\n"trim(file_get_contents(isset($argv[1])?$argv[1]:"puzzles.dat"), "\n\r"));
function 
initpuzzle($no)
{
        global 
$puzzles,$puzzle,$field,$x,$y,$size;
        
$puzzle explode("#"trim($puzzles[$no-1], "\n\r"), 2);
        
$field $puzzle[0];
        
$size sqrt(strlen($puzzle[0]));
        if(
$size != round($size) || $size%2==1)
        {
                
ncurses_end();
                die(
"Error: Puzzle #".$no." is invalid\n");
        }
        
$size = (int)$size;
        
$x $y 0;
        
ncurses_color_set(0);
        
ncurses_erase();
        
ncurses_addstr("Puzzle #".$no.(isset($puzzle[1])?(" - ".$puzzle[1]):"")."\n");
        for(
$i=0;$i<$size*$size;$i+=$size)
                
ncurses_addstr(substr($puzzle[0],$i,$size)."\n");
        
ncurses_move(1,0);
        
ncurses_color_set(1);
}
function 
checkline($str)
{
        if(
strstr($str" ")!==false) return false;
        if(
strstr($str"000")!==false) return false;
        if(
strstr($str"111")!==false) return false;
        return 
gmp_popcount(gmp_init($str2)) == strlen($str)/2;
}
$continue true;
$puzzleno = (isset($argv[2])&&$argv[2]>=1&&$argv[2]<=count($puzzles))?$argv[2]:1;
ncurses_init();
ncurses_start_color();
ncurses_init_pair(1NCURSES_COLOR_REDNCURSES_COLOR_BLACK);
ncurses_noecho();
initpuzzle($puzzleno);
while(
$continue)
{
        
$char ncurses_getch();
        if(
$char == 32)
        {
                
$pos=$y*$size+$x;
                if(
$puzzle[0][$pos] == " ")
                {
                        switch(
$field[$pos])
                        {
                                case 
"0"$field[$pos] = "1"; break;
                                case 
"1"$field[$pos] = " "; break;
                                case 
" "$field[$pos] = "0"; break;
                        }
                        
ncurses_addstr($field[$pos]);
                        
$points 0;
                        
$valh $valv = Array();
                        for(
$i=0;$i<$size;$i++)
                        {
                                
$vline ""; for($j=0;$j<$size;$j++) $vline .= $field[$j*$size+$i];
                                
$points += checkline(substr($field,$size*$i,$size)) + checkline($vline);
                                
$valh[] = bindec(substr($field,$size*$i,$size));
                                
$valv[] = bindec($vline);
                        }
                        if(
$points==2*$size && count($valh)==count(array_unique($valh)) && count($valv)==count(array_unique($valv)))
                        {
                                
ncurses_move($size+1,0);
                                
ncurses_addstr("You won!");
                        }
                }
        }
        if(
$char == ord("p") && $puzzleno 1initpuzzle(--$puzzleno);
        if(
$char == ord("n") && $puzzleno count($puzzles)) initpuzzle(++$puzzleno);
        if(
$char == ord("r")) initpuzzle($puzzleno);
        if(
$char == ord("q")) $continue false;
        
ncurses_move(($y=$y+($char==258&&$y<$size-1)-($char==259&&$y>0))+1,$x=$x+($char==261&&$x<$size-1)-($char==260&&$x>0));
        
ncurses_refresh(null);
}
ncurses_end();

puzzles.dat:
Code: [Select]
1  0    00 1 00  1      00 1   1  00#6x6 Easy 1
  0  11 00   1        1   1  000 1  #6x6 Easy 2
    00       1    01 1  0   0   1   #6x6 Medium 1
 0    00       0        1 11  1  1  #6x6 Medium 2
       0 00  1   0   1 0  1     00 1  1     1   11   0 1 1     1#8x8 Easy 1
 1 1  0 0 0  1 10  1   1 0         0   11  0 0 1    1   1  0  1 #8x8 Easy 2
    0 0 0 0 0 0             1 1 0  0    0  00          1 1 1    #8x8 Medium 1
   11    1   10       0 0 11   0 11          10     1    0 0   1#8x8 Medium 2

Controls:
Arrow keys: Move
Space: Set value
p: Previous puzzle
n: Next puzzle
r: Restart
q: Quit
Title: Re: 75 lines Binary Puzzle in php and ncurses
Post by: blue_bear_94 on July 29, 2013, 12:55:26 am
How'd you get the funky syntax coloring?
Title: Re: 75 lines Binary Puzzle in php and ncurses
Post by: Juju on July 29, 2013, 01:41:58 am
Blame the code tag plugin I guess?
Title: Re: 75 lines Binary Puzzle in php and ncurses
Post by: Sorunome on July 29, 2013, 05:00:47 am
Why is everypony suddenly making binary puzzels ???
Also, sounds awesome, i should try it :P
Title: Re: 75 lines Binary Puzzle in php and ncurses
Post by: Streetwalrus on July 29, 2013, 05:13:33 am
In Firefox I can't see the content of your code tags. It just says "Array". Though it works fine in Konqueror. Weird. ???
Title: Re: 75 lines Binary Puzzle in php and ncurses
Post by: Juju on July 29, 2013, 10:26:45 am
Now it should work. And yeah everyone is doing those lol. But in my case I wanted to see how optimized I could do this.
Title: Re: 75 lines Binary Puzzle in php and ncurses
Post by: stevon8ter on July 29, 2013, 01:13:20 pm
omg that's small :o

i already have 600 lines...

but this includes a start screen... stage select... level select.. and a custom button class (there is no standard button :/ )
Title: Re: 75 lines Binary Puzzle in php and ncurses
Post by: Juju on July 29, 2013, 01:20:41 pm
Yeah, I kept it to the strict minimum, so drawing all the stuff takes like 2 lines. I have a level select though.
Title: Re: 75 lines Binary Puzzle in php and ncurses
Post by: stevon8ter on July 29, 2013, 02:35:23 pm
well in lua there are a lot of functions i had to write myself (my ipad app works with lua 5.1 ...)

like all the bitmath functions... i had to write the myself
Title: Re: 75 lines Binary Puzzle in php and ncurses
Post by: harold on July 29, 2013, 02:47:04 pm
Lol I have 2900 lines of C#, 500 lines of C++ and 60 lines of assembly, and that's not counting anything that has to do with user interaction (there's not a lot of code there, maybe 200 lines).
About 1300 lines have to do with tutorial mode, but those are also used in puzzle generation (to make sure that lower-level puzzles don't require hard steps, as well as to ensure that higher-level puzzles do require hard steps).
Most of the rest is puzzle generation.
Title: Re: 60 lines Binary Puzzle in php and ncurses
Post by: Juju on July 29, 2013, 08:17:40 pm
Slimmed it down to less than 60 lines while adding mouse support. Now it's just damn crazy >:D

Code: [Select]
<?php // 60 lines Binary Puzzle v1.1 by Juju | http://juju2143.ca | Licensed under GPLv3
$puzzles explode("\n"trim(file_get_contents(isset($argv[1])?$argv[1]:"puzzles.dat"), "\n\r"));
function 
initpuzzle($no){
        global 
$puzzles,$puzzle,$field,$x,$y,$size;
        
$puzzle explode("#"trim($puzzles[$no-1], "\n\r"), 2);
        
$field $puzzle[0];
        
$size sqrt(strlen($puzzle[0]));
        if(
$size != round($size) || $size%2==1){ncurses_end(); die("Error: Puzzle #".$no." is invalid\n");}
        
$size = (int)$size$x $y 0;
        
ncurses_color_set(0);
        
ncurses_erase();
        
ncurses_addstr("Puzzle #".$no." - ".$size."x".$size.(isset($puzzle[1])?(" - ".$puzzle[1]):"")."\n");
        for(
$i=0;$i<$size*$size;$i+=$sizencurses_addstr(substr($puzzle[0],$i,$size)."\n");
        
ncurses_move(1,0);
        
ncurses_color_set(1);
}
function 
checkline($str){
        if(
strstr($str" ")!==false||strstr($str"000")!==false||strstr($str"111")!==false) return false;
        return 
gmp_popcount(gmp_init($str2)) == strlen($str)/2;
}
$continue true;
$puzzleno = (isset($argv[2])&&$argv[2]>=1&&$argv[2]<=count($puzzles))?$argv[2]:1;
ncurses_init();
ncurses_start_color();
ncurses_init_pair(1NCURSES_COLOR_REDNCURSES_COLOR_BLACK);
ncurses_noecho();
ncurses_mousemask(NCURSES_BUTTON1_CLICKED$oldmask);
initpuzzle($puzzleno);
while(
$continue){
        
$char ncurses_getch(); $clicked false;
        if(
$char == NCURSES_KEY_MOUSE){
                
ncurses_getmouse($e);
                if(
$e["mmask"]&NCURSES_BUTTON1_CLICKED&&$e["x"]>=0&&$e["x"]<$size&&$e["y"]>0&&$e["y"]<=$size){
                        
ncurses_move(($y=$e["y"]-1)+1$x=$e["x"]); $clicked=true;
                }
        }
        if((
$char == 32 || $clicked) && $puzzle[0][$pos=$y*$size+$x] == " "){
                switch(
$field[$pos]){
                        case 
"0"$field[$pos] = "1"; break;
                        case 
"1"$field[$pos] = " "; break;
                        case 
" "$field[$pos] = "0"; break;
                }
                
ncurses_addstr($field[$pos]);
                
$points 0$valh $valv = Array();
                for(
$i=0;$i<$size;$i++){
                        
$valv[$i]=""; for($j=0;$j<$size;$j++) $valv[$i] .= $field[$j*$size+$i];
                        
$points += checkline($valh[$i]=substr($field,$size*$i,$size)) + checkline($valv[$i]);
                }
                if(
$points==2*$size&&count($valh)==count(array_unique($valh))&&count($valv)==count(array_unique($valv))){
                        
ncurses_move($size+1,0); ncurses_addstr("You won!");
                }
        }
        if(
$char == ord("p") && $puzzleno 1initpuzzle(--$puzzleno);
        if(
$char == ord("n") && $puzzleno count($puzzles)) initpuzzle(++$puzzleno);
        if(
$char == ord("r")) initpuzzle($puzzleno);
        if(
$char == ord("q")) $continue false;
        
ncurses_move(($y=$y+($char==258&&$y<$size-1)-($char==259&&$y>0))+1,$x=$x+($char==261&&$x<$size-1)-($char==260&&$x>0));
        
ncurses_refresh(null);
}
ncurses_end();

EDIT: DJ Omnimaga, just for you I condensed this in one line:
Code: [Select]
<?php $puzzles=explode("\n",trim(file_get_contents(isset($argv[1])?$argv[1]:"puzzles.dat"),"\n\r"));function initpuzzle($no){global $puzzles,$puzzle,$field,$x,$y,$size;$puzzle=explode("#",trim($puzzles[$no-1],"\n\r"),2);$field=$puzzle[0];$size=sqrt(strlen($puzzle[0]));if($size!=round($size)||$size%2==1){ncurses_end();die("Error: Puzzle #".$no." is invalid\n");}$size=(int)$size;$x=$y=0;ncurses_color_set(0);ncurses_erase();ncurses_addstr("Puzzle #".$no." - ".$size."x".$size.(isset($puzzle[1])?(" - ".$puzzle[1]):"")."\n");for($i=0;$i<$size*$size;$i+=$size)ncurses_addstr(substr($puzzle[0],$i,$size)."\n");ncurses_move(1,0);ncurses_color_set(1);}function checkline($str){if(strstr($str," ")!==false||strstr($str,"000")!==false||strstr($str,"111")!==false)return false;return gmp_popcount(gmp_init($str,2))==strlen($str)/2;}$continue=true;$puzzleno=(isset($argv[2])&&$argv[2]>=1&&$argv[2]<=count($puzzles))?$argv[2]:1;ncurses_init();ncurses_start_color();ncurses_init_pair(1,NCURSES_COLOR_RED,NCURSES_COLOR_BLACK);ncurses_noecho();ncurses_mousemask(NCURSES_BUTTON1_CLICKED,$oldmask);initpuzzle($puzzleno);while($continue){$char=ncurses_getch();$clicked=false;if($char==NCURSES_KEY_MOUSE){ncurses_getmouse($e);if($e["mmask"]&NCURSES_BUTTON1_CLICKED&&$e["x"]>=0&&$e["x"]<$size&&$e["y"]>0&&$e["y"]<=$size){ncurses_move(($y=$e["y"]-1)+1,$x=$e["x"]);$clicked=true;}}if(($char==32||$clicked)&&$puzzle[0][$pos=$y*$size+$x]==" "){switch($field[$pos]){case "0":$field[$pos]="1";break;case "1":$field[$pos]=" ";break;case" ":$field[$pos]="0";break;}ncurses_addstr($field[$pos]);$points=0;$valh=$valv=Array();for($i=0;$i<$size;$i++){$valv[$i]="";for($j=0;$j<$size;$j++)$valv[$i].=$field[$j*$size+$i];$points+=checkline($valh[$i]=substr($field,$size*$i,$size))+checkline($valv[$i]);}if($points==2*$size&&count($valh)==count(array_unique($valh))&&count($valv)==count(array_unique($valv))){ncurses_move($size+1,0);ncurses_addstr("You won!");}}if($char==ord("p")&&$puzzleno>1)initpuzzle(--$puzzleno);if($char==ord("n")&&$puzzleno<count($puzzles))initpuzzle(++$puzzleno);if($char==ord("r"))initpuzzle($puzzleno);if($char==ord("q"))$continue=false;ncurses_move(($y=$y+($char==258&&$y<$size-1)-($char==259&&$y>0))+1,$x=$x+($char==261&&$x<$size-1)-($char==260&&$x>0));ncurses_refresh(null);}ncurses_end();
Title: Re: 60 lines Binary Puzzle in php and ncurses
Post by: DJ Omnimaga on July 29, 2013, 09:27:49 pm
Lol nice one juju. :P I really meant making the code 60 times smaller, though. But of course I was kidding, since I'm not even sure if that's possible. :P
Title: Re: 60 lines Binary Puzzle in php and ncurses
Post by: ruler501 on July 30, 2013, 01:05:35 am
I think a better comparison would be how many bytes does it use up because it could be written in one gigantic line.
Title: Re: 60 lines Binary Puzzle in php and ncurses
Post by: stevon8ter on July 30, 2013, 03:40:21 am
lolol, nice one juju xd