Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div class="container">
  <button class="btn" id="btnCreate">Create</button>
  <button class="btn" id="btnPlay">Play</button>
  <br/><br/>  

  <div class="center crossword" id="crossword"></div><br/>

  <div class="center">

    <div class="line">
      <input class="word" type="text" value="Tucan" />
      <input class="clue" value="A tropical bird with a large beak" />
    </div>

    <div class="line">
      <input class="word" type="text" value="Dingo" />
      <input class="clue" value="This free-ranging dog is at home in the outback." />
    </div>

    <div class="line">
      <input class="word" type="text" value="Dolphin" />
      <input class="clue" value="A friendly finned non-fish" />
    </div>

    <div class="line">
      <input class="word" type="text" value="Pig"/>
      <input class="clue" value="Bosses of the farm in Orwell's world" />
    </div>

    <div class="line">
      <input class="word" type="text" value="Kangaroo"/>
      <input class="clue" value="Boxing champions of the outback" />
    </div>

    <div class="line">
      <input class="word" type="text" value="Octopus"/>
      <input class="clue" value="Eight legged sea creature" />
    </div>

    <div class="line">
      <input class="word" type="text" value="Hamster"/>
      <input class="clue" value="Furry rodent whose teeth never stop growing" />
    </div>

    <div class="line">
      <input class="word" type="text" value="Alligator"/>
      <input class="clue" value="Dating back further than the T-rex, this reptile is a modern day dinosaur" />
    </div>

    <div class="line">
      <input class="word" type="text" value="Ostrich"/>
      <input class="clue" value="Flightless bird not know for its people skills" />
    </div>

    <div class="line">
      <input class="word" type="text" value="Koala"/>
      <input class="clue" value="Friendly version of the infamous Australian tourist terrorizing tree-dwellers" />
    </div>

    <div class="line">
      <input class="word" type="text" value="Mouse"/>
      <input class="clue" value="This poor animal is often the victim of feline aggression and human experimentation"/>
    </div>

    <div class="line">
      <input class="word" type="text" value="Antelope"/>
      <input class="clue" value="The victim of every lion documentary clip you've ever seen." />
    </div>

  </div>
</div>
              
            
!

CSS

              
                html{
  height:100%;
}
body{
  height:100%;
  min-width: 400px;
  margin:0;
  
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

.container{
  position: absolute;
  bottom: 0; top: 0; left: 0; right: 0;
  text-align: center;
}
.center{
  margin: 0 auto;
}

.btn{
  margin: 8px 4px 0;  
}
.btn{
  width: 172px;
  height: 28px;
}

.line{  
  height: 2em;
}
.word, .clue{
  display: inline-block;
  height: 1.5em;  
  padding: 0 5px;
}
.word{
  text-align: right;  
  width: 100px;
}
.clue{
  width: 500px;
}


.crossword{
  display: block;  
  background-color: rgb(32,32,32);  
}
.square{  
  margin: 0 1px 1px 0;
  display: inline-block;
  font: 24px Calibri;
  width: 1.25em;
  height: 1.25em;
  line-height: 1.25em;
  vertical-align: middle;
  
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.letter{
  background-color: rgb(255,255,255);
   
  -webkit-touch-callout: text;
  -webkit-user-select: text;
  -khtml-user-select: text;
  -moz-user-select: text;
  -ms-user-select: text;
  user-select: text;
}
.char:focus{
  -webkit-box-shadow: 0 0 0 2px rgba(255,32,32,1);
  -moz-box-shadow: 0 0 0 2px rgba(255,32,32,1);
  box-shadow: inset 0 0 0 2px rgba(255,32,32,1);  
}
.char {
  font-size:24px;
  text-transform: uppercase;
  outline: 0;
  border: 0;
  padding: 0;
  margin: -1px 0 0 -1px;
  width: 1.35em;
  height: 1.35em;
  text-align: center;
  background: none; 
} 

.hide{
  visibility: hidden;
}

.clueReadOnly
{
  border: 0 ;
  outline: 0;
  color:#303030 !important;
  background:none;
}
              
            
!

JS

              
                //---------------------------------//
//   GLOBAL VARIABLES              //
//---------------------------------//

var board, wordArr, wordBank, wordsActive, mode;

var Bounds = {  
  top:0, right:0, bottom:0, left:0,

  Update:function(x,y){
    this.top = Math.min(y,this.top);
    this.right = Math.max(x,this.right);
    this.bottom = Math.max(y,this.bottom);
    this.left = Math.min(x,this.left);
  },
  
  Clean:function(){
    this.top = 999;
    this.right = 0;
    this.bottom = 0;    
    this.left = 999;
  }
};


//---------------------------------//
//   MAIN                          //
//---------------------------------//

function Play(){
  var letterArr = document.getElementsByClassName('letter');
  
  for(var i = 0; i < letterArr.length; i++){
    letterArr[i].innerHTML = "<input class='char' type='text' maxlength='1'></input>";
  }
  
  mode = 0;
  ToggleInputBoxes(false);
}


function Create(){
  if (mode === 0){
    ToggleInputBoxes(true);
    document.getElementById("crossword").innerHTML = BoardToHtml(" ")
    mode = 1;
  }
  else{  
    GetWordsFromInput();

    for(var i = 0, isSuccess=false; i < 10 && !isSuccess; i++){
      CleanVars();
      isSuccess = PopulateBoard();
    }

    document.getElementById("crossword").innerHTML = 
      (isSuccess) ? BoardToHtml(" ") : "Failed to find crossword." ;
  }
}


function ToggleInputBoxes(active){
  var w=document.getElementsByClassName('word'),
      d=document.getElementsByClassName('clue');
  
  for(var i=0;i<w.length; i++){
    if(active===true){
      RemoveClass(w[i], 'hide');
      RemoveClass(d[i], 'clueReadOnly');
      d[i].disabled = '';
    }
    else{
      AddClass(w[i], 'hide');
      AddClass(d[i], 'clueReadOnly');
      d[i].disabled = 'readonly';
    }
  }
}


function GetWordsFromInput(){
  wordArr = [];  
  for(var i=0,val,w=document.getElementsByClassName("word");i<w.length;i++){
    val = w[i].value.toUpperCase();
    if (val !== null && val.length > 1){wordArr.push(val);}
  }
}


function CleanVars(){
  Bounds.Clean();
  wordBank = [];
  wordsActive = [];
  board = [];
  
  for(var i = 0; i < 32; i++){
    board.push([]);
    for(var j = 0; j < 32; j++){
      board[i].push(null);
    }
  }
}


function PopulateBoard(){
  PrepareBoard();
  
  for(var i=0,isOk=true,len=wordBank.length; i<len && isOk; i++){
    isOk = AddWordToBoard();
  }  
  return isOk;
}


function PrepareBoard(){
  wordBank=[];
  
  for(var i = 0, len = wordArr.length; i < len; i++){
    wordBank.push(new WordObj(wordArr[i]));
  }
  
  for(i = 0; i < wordBank.length; i++){
    for(var j = 0, wA=wordBank[i]; j<wA.char.length; j++){
      for(var k = 0, cA=wA.char[j]; k<wordBank.length; k++){
        for(var l = 0,wB=wordBank[k]; k!==i && l<wB.char.length; l++){
          wA.totalMatches += (cA === wB.char[l])?1:0;
        }
      }
    }
  }  
}


// TODO: Clean this guy up
function AddWordToBoard(){
  var i, len, curIndex, curWord, curChar, curMatch, testWord, testChar, 
      minMatchDiff = 9999, curMatchDiff;  

  if(wordsActive.length < 1){
    curIndex = 0;
    for(i = 0, len = wordBank.length; i < len; i++){
      if (wordBank[i].totalMatches < wordBank[curIndex].totalMatches){
        curIndex = i;
      }
    }
    wordBank[curIndex].successfulMatches = [{x:12,y:12,dir:0}];
  }
  else{  
    curIndex = -1;
    
    for(i = 0, len = wordBank.length; i < len; i++){
      curWord = wordBank[i];
      curWord.effectiveMatches = 0;
      curWord.successfulMatches = [];
      for(var j = 0, lenJ = curWord.char.length; j < lenJ; j++){
        curChar = curWord.char[j];
        for (var k = 0, lenK = wordsActive.length; k < lenK; k++){
          testWord = wordsActive[k];
          for (var l = 0, lenL = testWord.char.length; l < lenL; l++){
            testChar = testWord.char[l];            
            if (curChar === testChar){
              curWord.effectiveMatches++;
              
              var curCross = {x:testWord.x,y:testWord.y,dir:0};              
              if(testWord.dir === 0){                
                curCross.dir = 1;
                curCross.x += l;
                curCross.y -= j;
              } 
              else{
                curCross.dir = 0;
                curCross.y += l;
                curCross.x -= j;
              }
              
              var isMatch = true;
              
              for(var m = -1, lenM = curWord.char.length + 1; m < lenM; m++){
                var crossVal = [];
                if (m !== j){
                  if (curCross.dir === 0){
                    var xIndex = curCross.x + m;
                    
                    if (xIndex < 0 || xIndex > board.length){
                      isMatch = false;
                      break;
                    }
                    
                    crossVal.push(board[xIndex][curCross.y]);
                    crossVal.push(board[xIndex][curCross.y + 1]);
                    crossVal.push(board[xIndex][curCross.y - 1]);
                  }
                  else{
                    var yIndex = curCross.y + m;
                    
                    if (yIndex < 0 || yIndex > board[curCross.x].length){
                      isMatch = false;
                      break;
                    }
                    
                    crossVal.push(board[curCross.x][yIndex]);
                    crossVal.push(board[curCross.x + 1][yIndex]);
                    crossVal.push(board[curCross.x - 1][yIndex]);
                  }

                  if(m > -1 && m < lenM-1){
                    if (crossVal[0] !== curWord.char[m]){
                      if (crossVal[0] !== null){
                        isMatch = false;                  
                        break;
                      }
                      else if (crossVal[1] !== null){
                        isMatch = false;
                        break;
                      }
                      else if (crossVal[2] !== null){
                        isMatch = false;                  
                        break;
                      }
                    }
                  }
                  else if (crossVal[0] !== null){
                    isMatch = false;                  
                    break;
                  }
                }
              }
              
              if (isMatch === true){                
                curWord.successfulMatches.push(curCross);
              }
            }
          }
        }
      }
      
      curMatchDiff = curWord.totalMatches - curWord.effectiveMatches;
      
      if (curMatchDiff<minMatchDiff && curWord.successfulMatches.length>0){
        curMatchDiff = minMatchDiff;
        curIndex = i;
      }
      else if (curMatchDiff <= 0){
        return false;
      }
    }
  }
  
  if (curIndex === -1){
    return false;
  }
    
  var spliced = wordBank.splice(curIndex, 1);
  wordsActive.push(spliced[0]);
  
  var pushIndex = wordsActive.length - 1,
      rand = Math.random(),
      matchArr = wordsActive[pushIndex].successfulMatches,
      matchIndex = Math.floor(rand * matchArr.length),  
      matchData = matchArr[matchIndex];
  
  wordsActive[pushIndex].x = matchData.x;
  wordsActive[pushIndex].y = matchData.y;
  wordsActive[pushIndex].dir = matchData.dir;
  
  for(i = 0, len = wordsActive[pushIndex].char.length; i < len; i++){
    var xIndex = matchData.x,
        yIndex = matchData.y;
    
    if (matchData.dir === 0){
      xIndex += i;    
      board[xIndex][yIndex] = wordsActive[pushIndex].char[i];
    }
    else{
      yIndex += i;  
      board[xIndex][yIndex] = wordsActive[pushIndex].char[i];
    }
    
    Bounds.Update(xIndex,yIndex);
  }
    
  return true;
}


function BoardToHtml(blank){
  for(var i=Bounds.top-1, str=""; i<Bounds.bottom+2; i++){
    str+="<div class='row'>";
    for(var j=Bounds.left-1; j<Bounds.right+2; j++){
      str += BoardCharToElement(board[j][i]);
    }
    str += "</div>";
  }
  return str;
}


function BoardCharToElement(c){
  var arr=(c)?['square','letter']:['square'];
  return EleStr('div',[{a:'class',v:arr}],c);
}



//---------------------------------//
//   OBJECT DEFINITIONS            //
//---------------------------------//

function WordObj(stringValue){
  this.string = stringValue;
  this.char = stringValue.split("");
  this.totalMatches = 0;
  this.effectiveMatches = 0;
  this.successfulMatches = [];  
}


//---------------------------------//
//   EVENTS                        //
//---------------------------------//

function RegisterEvents(){
  document.getElementById("crossword").onfocus = function (){ 
    return false; }
  document.getElementById("btnCreate").addEventListener('click',Create,false);
  document.getElementById("btnPlay").addEventListener('click',Play,false);
}
RegisterEvents();


//---------------------------------//
//   HELPER FUNCTIONS              //
//---------------------------------//

function EleStr(e,c,h){
  h = (h)?h:"";
  for(var i=0,s="<"+e+" "; i<c.length; i++){
    s+=c[i].a+ "='"+ArrayToString(c[i].v," ")+"' ";    
  }
  return (s+">"+h+"</"+e+">");
}

function ArrayToString(a,s){
  if(a===null||a.length<1)return "";
  if(s===null)s=",";
  for(var r=a[0],i=1;i<a.length;i++){r+=s+a[i];}
  return r;
}

function AddClass(ele,classStr){
  ele.className = ele.className.replaceAll(' '+classStr,'')+' '+classStr;
}

function RemoveClass(ele,classStr){
  ele.className = ele.className.replaceAll(' '+classStr,'');
}

function ToggleClass(ele,classStr){
  var str = ele.className.replaceAll(' '+classStr,'');
  ele.className = (str.length===ele.className.length)?str+' '+classStr:str;
}

String.prototype.replaceAll = function (replaceThis, withThis) {
   var re = new RegExp(replaceThis,"g"); 
   return this.replace(re, withThis);
};


//---------------------------------//
//   INITIAL LOAD                  //
//---------------------------------//

Create();
Play();
              
            
!
999px

Console