Search code examples
javascripthtmltic-tac-toe

"Drawing" different sized Tic-tac-toe board


So I'm making a Tic-tac-toe game using JavaScript and HTML as project for school and teacher asked us to make it possible to "draw" different sized board e.g. 3x3 or 4x4.

And here is what I try to do.

window.addEventListener("load", onLoad, false)

function onLoad() {
  var wins = [7, 56, 448, 73, 146, 292, 273, 84];
  var mainDiv = document.getElementById("mainDiv");
  mainDiv.style.background = "#000000";
  mainDiv.style.width = "306px";
  mainDiv.style.height = "306px";
  mainDiv.style.border = "solid";
  mainDiv.style.borderColor = "#79BDEB";
  mainDiv.style.position = "absolute";
  mainDiv.style.left = "10px";
  mainDiv.style.top = "70px";
  //select.addEventListener("change", onChange, false);
}

function onChange() {
  var select = document.getElementById("mySelect").value;
  var main = document.getElementById("mainDiv");
  if (select == 3) {
    three();
  } else if (select == 4) {
    four();
  } else if (select == 5) {
    five();
  } else {
    six();
  }
  main.innerHTML = "";
  counter = 0;
}

function three() {
  var main = document.getElementById("mainDiv");
  for (var i = 0; i < 3; i++) {
    for (var j = 0; j < 3; j++) {
      var small = document.createElement("div");
      main.appendChild(small);
      small.style.background = "#52498F";
      small.style.width = "100px";
      small.style.height = "100px";
      small.style.border = "solid";
      small.style.borderColor = "#000000";
      small.style.position = "absolute";
      small.style.left = j * 100 + "px";
      small.style.top = i * 100 + "px";
      small.addEventListener("mousedown", onDown, false);
    }
  }
  var state = false;

  function onDown(e) {
    var small = e.target;
    small.style.background = "#f0f0f0";
    small.style.fontSize = "72px";
    small.style.fontFamily = "Arial";
    if (!state) {
      small.innerHTML = "x";
    } else {
      small.innerHTML = "o";
    }
    state = !state;
    small.style.textAlign = "center";
  }
}

function four() {
  var main = document.getElementById("mainDiv");
  for (var i = 0; i < 4; i++) {
    for (var j = 0; j < 4; j++) {
      var small = document.createElement("div");
      main.appendChild(small);
      small.style.background = "#52498F";
      small.style.width = "75px";
      small.style.height = "75px";
      small.style.border = "solid";
      small.style.borderColor = "#000000";
      small.style.position = "absolute";
      small.style.left = j * 75 + "px";
      small.style.top = i * 75 + "px";
      small.addEventListener("mousedown", onDown, false);
    }
  }
  var state = false;

  function onDown(e) {
    var small = e.target;
    small.style.background = "#f0f0f0";
    small.style.fontSize = "60px";
    small.style.fontFamily = "Arial";
    if (!state) {
      small.innerHTML = "x";
    } else {
      small.innerHTML = "o";
    }
    state = !state;
    small.style.textAlign = "center";
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <title>Tic-tac-toe</title>
  <script src="logic.js"></script>
  <style>
    #mySelect {
      font-size: 24px;
    }
    #myColor {
      font-size: 24px;
    }
  </style>
</head>

<body>
  <select id="mySelect" onchange="onChange()">
    <option value="3">3 x 3</option>
    <option value="4">4 x 4</option>
    <option value="5">5 x 5</option>
    <option value="6">6 x 6</option>
  </select>
  <select id="myColor" onchange="color()">
    <option value="11">Blue</option>
    <option value="12">Green</option>
    <option value="13">Red</option>
  </select>
  <div id="mainDiv"></div>
  <script type="text/javascript" src="cordova.js"></script>
</body>

</html>
And my problem is that small div's don't draw in the mainDiv. Strange thing is that on PC of one of my friends it works perfectly. But for me and couple of other friends it doesn't.


Solution

  • And my problem is that small div's don't draw in the mainDiv

    it's cause you're first drawing your elements applying the desired fn loop, but afterwards you're clearing the whole #mainDiv using main.innerHTML = "";

    Also, instead of creating different functions like three(), four(), five()...
    you can simply create a single one oneField(i, j, n) and pass to that function the number of iterations you need to apply like:

    select.addEventListener("change", createMap, false);
    
    function createMap() {
      main.innerHTML = ""; // Clear first, not afterwards!
      var n = this.value;  // 3, 4, 5, ...
      for(var i=0; i<n; i++)  for(var j=0; j<n; j++)  oneField(i, j, n);
      counter = 0;
      turn = 0;
    }
    

    where n can be used to set the field cell width using simple math fieldWidth = 300 / n

    Regarding your HTML and Styles, I would go creating a Table element and TR with TD cells instead of DIV, but I don't know your assignment's details. Also Instead of creating styles all over again for every element, I'd simply create a style rule like:

    #mainDIv > div {
        /* Cell styles here */
    }
    

    In any case here's an example using DIV as you do:

    function el(id){ return document.getElementById(id); }
    
    function css(el, prop, val){
      if (typeof prop==="object") {
        for(var key in prop) el.style[key] = prop[key];
      } else {
        el.style[prop] = val;
      }
    }
    
    var wins    = [7, 56, 448, 73, 146, 292, 273, 84],
        size    = 300,
        turn    = 0, // 0=O, 1=X
        counter = 0,
        select  = el("mySelect"),
        color   = el("myColor"),
        main    = el("mainDiv");
    
    css(main, {
          background : "#000",
          width      : size+"px",
          height     : size+"px",
          border     : "3px solid #79BDEB",
          position   : "absolute",
          left       : "10px",
          top        : "70px"
        });
    
    select.addEventListener("change", createMap, false);
    
    function oneField(i, j, n){
      var field = document.createElement("div"),
          w = size / n;
      css(field, {
          background : "#52498F",
          width      : w-2 +"px", // -2 is to account 1px border
          height     : w-2 +"px",
          border     : "1px solid #000",
          position   : "absolute",
          left       : j*w +"px",
          top        : i*w +"px",
          fontSize   : w-20 +"px",
          lineHeight : w-15 +"px",
          textAlign  : "center" 
      });
      main.appendChild(field);
      field.addEventListener("mousedown", onDown, false);
      //return field; // Return the created square field HTMLElement
    }
    
    function createMap() {
      main.innerHTML = "";
      var n = this.value;
      for(var i=0; i<n; i++)  for(var j=0; j<n; j++)  oneField(i, j, n);
      counter = 0;
      turn = 0;
    }
    
    function onDown(e) {
      var targ = e.target;
      css(targ, {
        background : "#f0f0f0" 
      });
    
      turn ^= 1; // Toggle turn 1,0,1,0...
      targ.innerHTML = turn ? "x" : "o" ;
    }
    * {
      margin: 0;
      padding: 0;
    }
    body {
      font: 16px/1 Helvetica, Arial, sans-serif;
      color: #444;
    }
    #mySelect,
    #myColor {
      font-size: 24px;
    }
    <select id="mySelect">
      <option value="3">3 x 3</option>
      <option value="4">4 x 4</option>
      <option value="5">5 x 5</option>
      <option value="6">6 x 6</option>
    </select>
    
    <div id="mainDiv"></div>