Omnimaga
General Discussion => Technology and Development => Computer Projects and Ideas => Topic started 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:
<?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($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();
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 > 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();
puzzles.dat:
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
-
How'd you get the funky syntax coloring?
-
Blame the code tag plugin I guess?
-
Why is everypony suddenly making binary puzzels ???
Also, sounds awesome, i should try it :P
-
In Firefox I can't see the content of your code tags. It just says "Array". Though it works fine in Konqueror. Weird. ???
-
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.
-
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 :/ )
-
Yeah, I kept it to the strict minimum, so drawing all the stuff takes like 2 lines. I have a level select though.
-
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
-
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.
-
Slimmed it down to less than 60 lines while adding mouse support. Now it's just damn crazy >:D
<?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+=$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();
EDIT: DJ Omnimaga, just for you I condensed this in one line:
<?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();
-
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
-
I think a better comparison would be how many bytes does it use up because it could be written in one gigantic line.
-
lolol, nice one juju xd