Skip to content

Instantly share code, notes, and snippets.

@benthebear
Last active September 22, 2021 13:01
Show Gist options
  • Save benthebear/8198f6fc93515824de47abc1074faff3 to your computer and use it in GitHub Desktop.
Save benthebear/8198f6fc93515824de47abc1074faff3 to your computer and use it in GitHub Desktop.
tilescape.php
<?php
/*
Any given tile
1 | 2 | 3 | 4 | 5
-----------------------
6 | 7 | 8 | 9 | 10
-----------------------
11 | 12 | 13 | 14 | 15
-----------------------
16 | 17 | 18 | 19 | 20
----------------------
21 | 22 | 23 | 24 | 25
*/
?>
<html>
<head>
<style type="text/css">
html {
}
h1 {
margin:auto;
text-align: center;
}
table {
font-size:10px;
font-family: sans-serif;
border-collapse: collapse;
}
table, tr, td {
margin:0px;
padding:0px;
box-sizing: border-box;
}
td {
}
.room {
border:1px solid black;
margin:auto;
background-color:dimgray;
padding:20px;
}
/* The Outer Table */
.tabletop {
background-color:dimgray;
margin:auto;
}
.tabletop-row {
}
.tabletop,
.tabeltop th,
.tabletop td {
}
/* Each Tile */
.tile {
visibility:hidden;
}
.tile,
.tile th,
.tile td {
border:1px solid gray;
}
.tile td {
text-align: center;
width:20px;
height:21px;
}
.tile td div {
}
.solid {
color: white;
background-color:black;
}
.open {
background-color: ivory;
}
.library .all-tiles {
display:flex;
flex-wrap:wrap;
align-items: end;
align-content: flex-start;
justify-content: flex-start;
}
.library .single-tile {
margin-left:10px;
width:120px;
}
.library .single-tile h3 {
font-size:12px;
}
</style>
</head>
<body>
<h1 id="title" data-show="0">Tilescape</h1>
<?php
class tile {
public $grid;
public $sides;
public $opensides_count;
public $type;
public $name;
public $position_x;
public $position_y;
public $number;
public function __construct($type, $number){
$this->type = $type;
$this->number = $number;
$this->init_grid();
if(!is_array($grid)){
$this->grid = array();
}else{
$this->grid = $grid;
}
$this->fill_grid_by_type($type);
$this->calculate_open_sides();
}
public function init_grid(){
$this->set_all_fields("open");
}
public function set_all_fields($state){
for($i=1; $i<=25; $i++){
$this->grid[$i] = $state;
}
}
public function set_fields_open($fields){
$this->set_field_state($fields, "open");
}
public function set_fields_solid($fields){
$this->set_field_state($fields, "solid");
}
public function set_field_state($fields, $state){
foreach($fields as $fieldid){
$this->grid[$fieldid] = $state;
}
}
public function calculate_open_sides(){
$opensides_count = 0;
if($this->grid[3] == "open"){
$this->opensides_count ++;
$this->sides['top'] = "open";
}else{
$this->sides['top'] = "solid";
}
if($this->grid[11] == "open"){
$this->opensides_count ++;
$this->sides['left'] = "open";
}else{
$this->sides['left'] = "solid";
}
if($this->grid[15] == "open"){
$this->opensides_count ++;
$this->sides['right'] = "open";
}else{
$this->sides['right'] = "solid";
}
if($this->grid[23] == "open"){
$this->opensides_count ++;
$this->sides['bottom'] = "open";
}else{
$this->sides['bottom'] = "solid";
}
}
public function fill_grid_by_type($type){
switch($type){
case(0):
$this->name = "Start Tile";
$this->set_all_fields("open");
break;
case(1):
$this->name = "Narrow dead end";
$this->set_all_fields("solid");
$this->set_fields_open(array(8,13,18,23));
break;
case(2):
$this->name = "Narrow straight corridor";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,8,13,18,23));
break;
case(3):
$this->name = "Narrow full-junction";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,8,11,12,13,14,15,18,23));
break;
case(4):
$this->name = "Narrow y-junction";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,8,13,14,15,18,23));
break;
case(5):
$this->name = "Narrow turn";
$this->set_all_fields("solid");
$this->set_fields_open(array(13,14,15,18,23));
break;
case(6):
$this->name = "Dead end Room";
$this->set_all_fields("solid");
$this->set_fields_open(array(7,8,9,12,13,14,17,18,19,23));
break;
case(7):
$this->name = "Walk-through room Room";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,7,8,9,12,13,14,17,18,19,23));
break;
case(8):
$this->name = "Narrow turn room";
$this->set_all_fields("solid");
$this->set_fields_open(array(7,8,9,12,13,14,15,17,18,19,23));
break;
case(9):
$this->name = "4 Doors room";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,7,8,9,11,12,13,14,15,17,18,19,23));
break;
case(10):
$this->name = "Y-junction room";
$this->set_all_fields("solid");
$this->set_fields_open(array(7,8,9,11,12,13,14,15,17,18,19,23));
break;
case(11):
$this->name = "Dead end smalll Room";
$this->set_all_fields("solid");
$this->set_fields_open(array(7,8,9,12,13,14,18,23));
break;
case(12):
$this->name = "Twisting corridor";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,8,9,14,18,19,23));
break;
case(13):
$this->name = "Alcoves";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,7,8,9,13,17,18,19,23));
break;
case(14):
$this->name = "Narrow straight corridor with bulge";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,8,9,13,14,18,19,23));
break;
case(15):
$this->name = "Narrow diagonal y-junction";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,8,9,14,15,18,19,23));
break;
case(16):
$this->name = "Wide straight corridor";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,5,6,10,11,15,16,21,25));
break;
case(17):
$this->name = "Wide turn";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,2,3,4,5,6,11,16,21,25));
break;
case(18):
$this->name = "Wide y-junction";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,2,3,4,5,21,25));
break;
case(19):
$this->name = "Wide full junction";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,5,21,25));
break;
case(20):
$this->name = "Wide diagonal y-junction";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,5,6,7,11,12,13,14,16,17,21,25));
break;
case(21):
$this->name = "Narrowing straight corridor";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,8,12,13,14,17,18,19,22,23,24));
break;
case(22):
$this->name = "Wide t-junction with narrow corridor";
$this->set_all_fields("solid");
$this->set_fields_open(array(11,12,13,14,15,17,18,19,22,23,24));
break;
case(23):
$this->name = "Wide t-junction with narrow corridor";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,8,11,12,13,14,15,17,18,19,22,23,24));
break;
case(24):
$this->name = "Wide straight corridor with two narrow junctions";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,5,6,10,16,20,21,25));
break;
case(25):
$this->name = "Wide straight corridor with one narrow junctions";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,5,6,10,15,16,20,21,25));
break;
case(26):
$this->name = "Open area";
$this->set_all_fields("open");
$this->set_fields_solid(array());
break;
case(27):
$this->name = "Almost open area";
$this->set_all_fields("open");
$this->set_fields_solid(array(21,25));
break;
case(28):
$this->name = "Wide junction with one narrow turn";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,2,4,5,21,25));
break;
case(29):
$this->name = "Wide turn with two narrow junctions";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,2,4,5,6,16,21,25));
break;
case(30):
$this->name = "Wide corridor end three narrow junctions";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,2,4,5,6,10,16,20,21,25));
break;
case(31):
$this->name = "Wide dead end";
$this->set_all_fields("open");
$this->set_fields_solid(array(1,2,3,4,5,6,10,11,15,16,20,21,25));
break;
case(32):
$this->name = "Double turn";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,7,8,11,12,14,15,18,19,23));
break;
case(33):
$this->name = "Stronger Double turn";
$this->set_all_fields("solid");
$this->set_fields_open(array(2,3,7,11,12,23,24,19,14,15));
break;
case(34):
$this->name = "Central Pillar";
$this->set_all_fields("open");
$this->set_fields_solid(array(8,12,13,14,18));
break;
case(35):
$this->name = "Four Pillars";
$this->set_all_fields("open");
$this->set_fields_solid(array(7,9,17,19));
break;
case(36):
$this->name = "Narrow full-junction with pillar";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,7,8,9,11,12,14,15,17,18,19,23));
break;
case(37):
$this->name = "Narrow full-junction with pillar";
$this->set_all_fields("solid");
$this->set_fields_open(array(3,7,8,9,12,14,15,17,18,19,23));
break;
}
}
public function rotate_tile_cockwise(){
$new_grid = array();
$new_grid[1] = $this->grid[21];
$new_grid[2] = $this->grid[16];
$new_grid[3] = $this->grid[11];
$new_grid[4] = $this->grid[6];
$new_grid[5] = $this->grid[1];
$new_grid[6] = $this->grid[22];
$new_grid[7] = $this->grid[17];
$new_grid[8] = $this->grid[12];
$new_grid[9] = $this->grid[7];
$new_grid[10] = $this->grid[2];
$new_grid[11] = $this->grid[23];
$new_grid[12] = $this->grid[18];
$new_grid[13] = $this->grid[13];
$new_grid[14] = $this->grid[8];
$new_grid[15] = $this->grid[3];
$new_grid[16] = $this->grid[24];
$new_grid[17] = $this->grid[19];
$new_grid[18] = $this->grid[14];
$new_grid[19] = $this->grid[9];
$new_grid[20] = $this->grid[4];
$new_grid[21] = $this->grid[25];
$new_grid[22] = $this->grid[20];
$new_grid[23] = $this->grid[15];
$new_grid[24] = $this->grid[10];
$new_grid[25] = $this->grid[5];
$this->grid = $new_grid;
$this->calculate_open_sides();
}
public function render($print = false, $visibility = "hidden"){
$output = "";
$output .= "<table id='tile-number-".$this->number."' class='table-tile tile tile-type-".$this->type." tile-number-".$this->number."' style='visibility:".$visibility.";'>\n";
for($y = 1; $y<=5; $y++){
$output .= "<tr>\n";
for($x = 1; $x<=5; $x++){
$pos = (($y*5)-5)+$x;
$output .= "<td class='".$this->grid[$pos]."'>";
if($pos == 13){
$output .= $this->number;
}else{
$output .= " ";
}
$output .= "</td>\n";
}
$output .= "</tr>\n";
}
$output .= "</table>\n";
if($print){
print $output;
return true;
}else{
return $output;
}
}
}
class tabletop {
public $grid = array();
public $tiles = array();
public $availables = array(); // An array of X/Y-positions on the table currently avaiable to add a new tile.
public $logs = array();
public $lowest_x = -1;
public $lowest_y = -1;
public $highest_x = 1;
public $highest_y = 1;
public function __construct(){
$start_tile = new tile(0,0);
$position_x = 0;
$position_y = 0;
$start_tile->position_x = $position_x;
$start_tile->position_y = $position_y;
$this->grid[$position_x][$position_x] = $start_tile;
$this->tiles[] = $start_tile;
}
public function calculate_all_availables(){
// Reset all Availables
$this->availables = array();
// Go through each current tile
foreach($this->tiles as $tile){
$position_x = $tile->position_x;
$position_y = $tile->position_y;
// Check wether the 4 postions around that tile a available
// if so, add that position to the list of Availables.
if(!isset($this->grid[$position_x][$position_y-1])){
$this->availables[] = array($position_x, $position_y-1);
}
if(!isset($this->grid[$position_x+1][$position_y])){
$this->availables[] = array($position_x+1, $position_y);
}
if(!isset($this->grid[$position_x][$position_y+1])){
$this->availables[] = array($position_x, $position_y+1);
}
if(!isset($this->grid[$position_x-1][$position_y])){
$this->availables[] = array($position_x-1, $position_y);
}
}
}
public function add_a_tile($type = 1, $number){
$new_tile = new tile($type, $number);
$this->log[] = "<b>Trying to add Tile No. ".$new_tile->number." type ".$new_tile->type." </b>";
$new_tile = $this->try_to_add_tile($new_tile);
if($new_tile){
// Place the Tile in the Grid
$this->calculate_new_maximums($new_tile->position_x, $new_tile->position_y);
$this->grid[$new_tile->position_x][$new_tile->position_y] = $new_tile;
$this->tiles[] = $new_tile;
}else{
$this->log[] = "Couldn't place tile! Skipping it.";
}
}
public function try_to_add_tile($new_tile){
// Position the Tile
$this->calculate_all_availables();
$rand_available_position = rand(0,count($this->availables)-1);
$new_position = $this->availables[$rand_available_position];
// Set new positions
$new_x = $new_position[0];
$new_y = $new_position[1];
$new_tile->position_x = $new_x;
$new_tile->position_y = $new_y;
$this->log[] = "Trying to add Tile at $new_x / $new_y";
// Adjust current maximum expansion of the table;
$this->calculate_new_maximums($new_x, $new_y);
// Maybe rotate the Tile.
$result = $this->rotate_tile_best($new_tile);
if(!$result and count($this->availables)>0){
$this->log[] = "Could not find a matching rotation, trying another available";
unset($this->availables[$rand_available_position]);
$result = $this->try_to_add_tile($new_tile);
}else{
$this->log[] = "No matching available position";
}
return $result;
}
public function calculate_new_maximums($new_x, $new_y){
if($new_x < $this->lowest_x){
$this->lowest_x = $new_x;
}
if($new_x > $this->highest_x){
$this->highest_x = $new_x;
}
if($new_y < $this->lowest_y){
$this->lowest_y = $new_y;
}
if($new_y > $this->highest_y){
$this->highest_y = $new_y;
}
}
public function render($print = false){
$output = "";
$output .= "<div class='room'>";
$output .= "<table class='tabletop'>\n";
for($i = $this->lowest_y; $i <= $this->highest_y; $i++){
$output .= "<tr class='tabletop-row'>\n";
for($j = $this->lowest_x; $j <= $this->highest_x; $j++){
$output .= "<td>\n";
if(isset($this->grid[$j][$i]->type)){
$output .= "".$this->grid[$j][$i]->render();
}else{
$output .= " ";
}
$output .= "</td>\n";
}
$output .= "</tr>\n";
}
$output .= "</table>\n";
$output .= "</div>";
return $this->print_or_return($output, $print);
}
public function get_all_adjacent_tiles($x, $y){
$adjacent_tiles = array();
if(isset($this->grid[$x][$y-1])){
$adjacent_tiles['top'] = $this->grid[$x][$y-1];
}
if(isset($this->grid[$x+1][$y])){
$adjacent_tiles['right'] = $this->grid[$x+1][$y];
}
if(isset($this->grid[$x][$y+1])){
$adjacent_tiles['bottom'] = $this->grid[$x][$y+1];
}
if(isset($this->grid[$x-1][$y])){
$adjacent_tiles['left'] = $this->grid[$x-1][$y];
}
return $adjacent_tiles;
}
public function rotate_tile_random($title){
$rotations = rand(1,4);
for($i = 1; $i<$rotations; $i++){
$new_tile->rotate_tile_cockwise();
$this->log[] = "Turned current Tile randomly";
}
return $tile;
}
public function rotate_tile_best($tile){
// Get the adjacent tiles
$adjacent_tiles = $this->get_all_adjacent_tiles($tile->position_x, $tile->position_y);
// Calculate the fitting connection for each possible rotation
$this->log[] = "Tile ".$tile->number." is open ".print_r($tile->sides, true);
// Fist: Search the best fitting rotation
$highest_hits = 0;
$highest_rotation = 0;
for($rotation = 0; $rotation < 4; $rotation++){
$current_hits = 0;
if($tile->sides['top'] == "open" and isset($adjacent_tiles['top']) and $adjacent_tiles['top']->sides['bottom'] == "open"){
$current_hits ++;
$this->log[] = "Top hit";
}
if($tile->sides['right'] == "open" and isset($adjacent_tiles['right']) and $adjacent_tiles['right']->sides['left'] == "open"){
$current_hits ++;
$this->log[] = "Right hit";
}
if($tile->sides['bottom'] == "open" and isset($adjacent_tiles['bottom']) and $adjacent_tiles['bottom']->sides['top'] == "open"){
$current_hits ++;
$this->log[] = "Bottom hit";
}
if($tile->sides['left'] == "open" and isset($adjacent_tiles['left']) and $adjacent_tiles['left']->sides['right'] == "open"){
$current_hits ++;
$this->log[] = "Left hit";
}
$this->log[] = "Rotation $rotation with $current_hits hits.";
$tile->rotate_tile_cockwise();
if($current_hits > $highest_hits){
$highest_hits = $current_hits;
$highest_rotation = $rotation;
}
}
// Second: Turn the Tile that often, again
for($i = 1; $i <= $highest_rotation; $i++){
$tile->rotate_tile_cockwise();
}
if($highest_hits == 0){
return false;
}else{
$this->log[] = "Rotated tile to best position with $highest_hits as the highest hit $highest_rotation times.";
return $tile;
}
}
public function print_logs($print = false){
$output = "";
$output .= "<h2>Logs</h2>\n";
$output .= "<ol>";
foreach($this->log as $log){
$output .= "<li>$log</li>\n";
}
$output .= "</ol>\n";
return $this->print_or_return($output, $print);
}
public function print_or_return($output, $print=false){
if($print){
print $output;
return true;
}else{
return $output;
}
}
public function render_library(){
$output = "";
$output .= "<div class='library'>\n";
$output .= "<h2>Tile Library</h2>\n";
$output .= "<div class='all-tiles'>\n";
for($i = 0; $i<38; $i++){
$tile = new tile($i, $i);
$output .= "<div class='single-tile'>\n";
$output .= "<h3>".$tile->name."</h3>";
$output .= $tile->render(false, "visible");
$output .= "</div>\n";
}
$output .= "</div>\n";
$output .= "</div>\n";
return $output;
}
}
$tabletop = new tabletop();
for($i=1; $i<32; $i++){
$tabletop->add_a_tile(rand(1,37), $i);
}
print $tabletop->render();
print $tabletop->render_library();
print $tabletop->print_logs();
?>
<script type="text/javascript">
function show(tileid){
//alert(tileid);
if(document.getElementById(tileid)){
if (document.getElementById(tileid).style.visibility == "hidden"){
document.getElementById(tileid).style.visibility = "visible";
}
}
}
function showtiles(){
var number;
number = document.getElementById('title').getAttribute('data-show');
show("tile-number-"+number);
number = Number(number)+1;
document.getElementById('title').setAttribute('data-show', number);
}
var myVar = setInterval(showtiles, 1000);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment