text: // const __PIECE_FN_SVG = [];
  // import React, { Component } from 'react'
  
  
  function bB(props) {
      return (
        `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
          <g
            fill="none"
            fillRule="evenodd"
            stroke="#000"
            strokeWidth="1.5"
            strokeLinecap="round"
            strokeLinejoin="round">
            <g fill="#000" strokeLinecap="butt">
              <path d="M9 36c3.39-.97 10.11.43 13.5-2 3.39 2.43 10.11 1.03 13.5 2 0 0 1.65.54 3 2-.68.97-1.65.99-3 .5-3.39-.97-10.11.46-13.5-1-3.39 1.46-10.11.03-13.5 1-1.354.49-2.323.47-3-.5 1.354-1.94 3-2 3-2z" />
              <path d="M15 32c2.5 2.5 12.5 2.5 15 0 .5-1.5 0-2 0-2 0-2.5-2.5-4-2.5-4 5.5-1.5 6-11.5-5-15.5-11 4-10.5 14-5 15.5 0 0-2.5 1.5-2.5 4 0 0-.5.5 0 2z" />
              <path d="M25 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 1 1 5 0z" />
            </g>
            <path d="M17.5 26h10M15 30h15m-7.5-14.5v5M20 18h5" stroke="#fff" strokeLinejoin="miter" />
          </g>
        </svg>`
      )
    }
    
  function bK(props) {
      return (
        `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
          <g
            fill="none"
            fillRule="evenodd"
            stroke="#000"
            strokeWidth="1.5"
            strokeLinecap="round"
            strokeLinejoin="round">
            <path d="M22.5 11.63V6" strokeLinejoin="miter" />
            <path
              d="M22.5 25s4.5-7.5 3-10.5c0 0-1-2.5-3-2.5s-3 2.5-3 2.5c-1.5 3 3 10.5 3 10.5"
              fill="#000"
              strokeLinecap="butt"
              strokeLinejoin="miter"
            />
            <path
              d="M11.5 37c5.5 3.5 15.5 3.5 21 0v-7s9-4.5 6-10.5c-4-6.5-13.5-3.5-16 4V27v-3.5c-3.5-7.5-13-10.5-16-4-3 6 5 10 5 10V37z"
              fill="#000"
            />
            <path d="M20 8h5" strokeLinejoin="miter" />
            <path
              d="M32 29.5s8.5-4 6.03-9.65C34.15 14 25 18 22.5 24.5l.01 2.1-.01-2.1C20 18 9.906 14 6.997 19.85c-2.497 5.65 4.853 9 4.853 9"
              stroke="#fff"
            />
            <path
              d="M11.5 30c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0"
              stroke="#fff"
            />
          </g>
        </svg>`
      )
    }
  
  
  function bN(props) {
  return (
      `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
      <g>
          <path
          d="M36 36c-3.385-.972-10.115.43-13.5-2-3.385 2.43-10.115 1.028-13.5 2 0 0-1.646.542-3 2 .677.972 1.646.986 3 .5 3.385-.972 10.115.458 13.5-1 3.385 1.458 10.115.028 13.5 1 1.354.486 2.323.472 3-.5-1.354-1.945-3-2-3-2z"
          fillRule="evenodd"
          stroke="#000"
          strokeWidth="1.5"
          strokeLinejoin="round"
          />
          <path
          d="M30 32c-2.5 2.5-12.5 2.5-15 0-.5-1.5 0-2 0-2h15s.5.5 0 2z"
          fillRule="evenodd"
          stroke="#000"
          strokeWidth="1.5"
          strokeLinejoin="round"
          />
          <path d="M30 30H15" fill="none" stroke="#000" strokeWidth="1.5" />
          <g strokeLinecap="round">
          <path
              d="M20.344 7.627c8.037.765 12.63 6.123 12.247 22.197H14.987c0-6.89 7.654-4.975 6.124-16.074"
              fillRule="evenodd"
              stroke="#000"
              strokeWidth="1.14813"
          />
          <path
              d="M21.875 13.75c.294 2.228-4.25 5.64-6.123 6.89-2.297 1.53-2.158 3.323-3.827 3.06-.798-.722 1.08-2.325 0-2.296-.766 0 .143.943-.766 1.53-.766 0-3.065.766-3.063-3.06 0-1.53 4.593-9.186 4.593-9.186s1.443-1.456 1.53-2.68c-.555-.76-.382-1.53-.382-2.295.765-.765 2.296 1.914 2.296 1.914h1.53s.6-1.525 1.915-2.297c.764 0 .764 2.297.764 2.297"
              fillRule="evenodd"
              stroke="#000"
              strokeWidth="1.14813"
              strokeLinejoin="round"
          />
          <path
              d="M10.776 19.49a.383.383 0 1 1-.765 0 .383.383 0 1 1 .766 0zM14.935 12.028a.383 1.148 30 1 1-.663-.383.383 1.148 30 1 1 .663.383z"
              stroke="#fff"
              strokeWidth="1.14813"
              strokeLinejoin="round"
          />
          <path
              d="M31.825 29.824c.766-15.31-4.21-21.05-9.185-21.815"
              fillRule="evenodd"
              stroke="#fff"
              strokeWidth=".76542"
          />
          </g>
          <path
          d="M15 30h15"
          stroke="#fff"
          strokeWidth="1.5"
          strokeLinecap="round"
          strokeLinejoin="round"
          />
      </g>
      </svg>`
  )
  }
  
  
  function bP(props) {
  return (
      `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%" >
      <path
          d="M22 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2.38-1.95 1.12-3.28 3.21-3.28 5.62 0 2.03.94 3.84 2.41 5.03-3 1.06-7.41 5.55-7.41 13.47h23c0-7.92-4.41-12.41-7.41-13.47 1.47-1.19 2.41-3 2.41-5.03 0-2.41-1.33-4.5-3.28-5.62.49-.67.78-1.49.78-2.38 0-2.21-1.79-4-4-4z"
          stroke="#000"
          strokeWidth="1.5"
          strokeLinecap="round"
      />
      </svg>`
  )
  }
  
  
  function bQ(props) {
  return (
      // `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
      // <g
      //     fill={props.black ? 0 : 'None'} 
      //     fillRule="evenodd"
      //     stroke="#000"
      //     strokeWidth="1.5"
      //     strokeLinecap="round"
      //     strokeLinejoin="round">
      //     <g fill="#000" stroke="none">
      //     <circle cx={6} cy={12} r={2.75} />
      //     <circle cx={14} cy={9} r={2.75} />
      //     <circle cx={22.5} cy={8} r={2.75} />
      //     <circle cx={31} cy={9} r={2.75} />
      //     <circle cx={39} cy={12} r={2.75} />
      //     </g>
      //     <path
      //     d="M9 26c8.5-1.5 21-1.5 27 0l2.5-12.5L31 25l-.3-14.1-5.2 13.6-3-14.5-3 14.5-5.2-13.6L14 25 6.5 13.5 9 26z"
      //     strokeLinecap="butt"
      //     />
      //     <path
      //     d="M9 26c0 2 1.5 2 2.5 4 1 1.5 1 1 .5 3.5-1.5 1-1.5 2.5-1.5 2.5-1.5 1.5.5 2.5.5 2.5 6.5 1 16.5 1 23 0 0 0 1.5-1 0-2.5 0 0 .5-1.5-1-2.5-.5-2.5-.5-2 .5-3.5 1-2 2.5-2 2.5-4-8.5-1.5-18.5-1.5-27 0z"
      //     strokeLinecap="butt"
      //     />
      //     <path d="M11 38.5a35 35 1 0 0 23 0" fill="none" strokeLinecap="butt" />
      //     <path
      //     d="M11 29a35 35 1 0 1 23 0M12.5 31.5h20M11.5 34.5a35 35 1 0 0 22 0M10.5 37.5a35 35 1 0 0 24 0"
      //     fill="none"
      //     stroke="#fff"
      //     />
      // </g>
      // </svg>`
  
      `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">    
        <g
            fill="#000"
            fillRule="evenodd"
            stroke="#000"
            strokeWidth="1.5"
            strokeLinecap="round"
            strokeLinejoin="round">
            <path d="M8 12a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM24.5 7.5a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM41 12a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM16 8.5a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM33 9a2 2 0 1 1-4 0 2 2 0 1 1 4 0z"  />
            <path
            d="M9 26c8.5-1.5 21-1.5 27 0l2-12-7 11V11l-5.5 13.5-3-15-3 15-5.5-14V25L7 14l2 12z"
            strokeLinecap="butt" stroke="#fff" strokeWidth = '0.7'
            />
            
            <path
            d="M9 26c0 2 1.5 2 2.5 4 1 1.5 1 1 .5 3.5-1.5 1-1.5 2.5-1.5 2.5-1.5 1.5.5 2.5.5 2.5 6.5 1 16.5 1 23 0 0 0 1.5-1 0-2.5 0 0 .5-1.5-1-2.5-.5-2.5-.5-2 .5-3.5 1-2 2.5-2 2.5-4-8.5-1.5-18.5-1.5-27 0z"
            strokeLinecap="butt" stroke="#fff" strokeWidth = '0.9'
            />
            <path d="M11.5 30c3.5-1 18.5-1 22 0M12 33.5c6-1 15-1 21 0" fill="#fff" stroke="#fff" strokeWidth = '0.9'/>
        </g>
      </svg>`
  
  )
  }
  
  function bR(props) {
  return (
      `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
      <g
          fill={0} 
          fillRule="evenodd"
          stroke="#000"
          strokeWidth="1.5"
          strokeLinecap="round"
          strokeLinejoin="round">
          <path
          d="M9 39h27v-3H9v3zM12.5 32l1.5-2.5h17l1.5 2.5h-20zM12 36v-4h21v4H12z"
          strokeLinecap="butt"
          />
          <path d="M14 29.5v-13h17v13H14z" strokeLinecap="butt" strokeLinejoin="miter" />
          <path
          d="M14 16.5L11 14h23l-3 2.5H14zM11 14V9h4v2h5V9h5v2h5V9h4v5H11z"
          strokeLinecap="butt"
          />
          <path
          d="M12 35.5h21M13 31.5h19M14 29.5h17M14 16.5h17M11 14h23"
          fill="none"
          stroke="#fff"
          strokeWidth={1}
          strokeLinejoin="miter"
          />
      </g>
      </svg>`
  )
  }
  
  
  function wB(props) {
  return (
      `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
      <g
          fill="none"
          fillRule="evenodd"
          stroke="#000"
          strokeWidth="1.5"
          strokeLinecap="round"
          strokeLinejoin="round">
          <g fill="#fff" strokeLinecap="butt">
          <path d="M9 36c3.39-.97 10.11.43 13.5-2 3.39 2.43 10.11 1.03 13.5 2 0 0 1.65.54 3 2-.68.97-1.65.99-3 .5-3.39-.97-10.11.46-13.5-1-3.39 1.46-10.11.03-13.5 1-1.354.49-2.323.47-3-.5 1.354-1.94 3-2 3-2z" />
          <path d="M15 32c2.5 2.5 12.5 2.5 15 0 .5-1.5 0-2 0-2 0-2.5-2.5-4-2.5-4 5.5-1.5 6-11.5-5-15.5-11 4-10.5 14-5 15.5 0 0-2.5 1.5-2.5 4 0 0-.5.5 0 2z" />
          <path d="M25 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 1 1 5 0z" />
          </g>
          <path d="M17.5 26h10M15 30h15m-7.5-14.5v5M20 18h5" strokeLinejoin="miter" />
      </g>
      </svg>`
  )
  }
  
  
  function wK(props) {
    return (
        `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
        <g
            fill="none"
            fillRule="evenodd"
            stroke="#000"
            strokeWidth="1.5"
            strokeLinecap="round"
            strokeLinejoin="round">
            <path d="M22.5 11.63V6M20 8h5" strokeLinejoin="miter" />
            <path
            d="M22.5 25s4.5-7.5 3-10.5c0 0-1-2.5-3-2.5s-3 2.5-3 2.5c-1.5 3 3 10.5 3 10.5"
            fill="#fff"
            strokeLinecap="butt"
            strokeLinejoin="miter"
            />
            <path
            d="M11.5 37c5.5 3.5 15.5 3.5 21 0v-7s9-4.5 6-10.5c-4-6.5-13.5-3.5-16 4V27v-3.5c-3.5-7.5-13-10.5-16-4-3 6 5 10 5 10V37z"
            fill="#fff"
            />
            <path d="M11.5 30c5.5-3 15.5-3 21 0M11.5 33.5c5.5-3 15.5-3 21 0M11.5 37c5.5-3 15.5-3 21 0" />
        </g>
        </svg>`
    )
  }
  
  
  function wN(props) {
  return (
      `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
      <g
          fill="none"
          fillRule="evenodd"
          stroke="#000"
          strokeWidth="1.5"
          strokeLinecap="round"
          strokeLinejoin="round">
          <path d="M22 10c10.5 1 16.5 8 16 29H15c0-9 10-6.5 8-21" fill="#fff" />
          <path
          d="M24 18c.38 2.91-5.55 7.37-8 9-3 2-2.82 4.34-5 4-1.042-.94 1.41-3.04 0-3-1 0 .19 1.23-1 2-1 0-4.003 1-4-4 0-2 6-12 6-12s1.89-1.9 2-3.5c-.73-.994-.5-2-.5-3 1-1 3 2.5 3 2.5h2s.78-1.992 2.5-3c1 0 1 3 1 3"
          fill="#fff"
          />
          <path d="M9.5 25.5a.5.5 0 1 1-1 0 .5.5 0 1 1 1 0z" fill="#000" />
          <path
          d="M14.933 15.75a.5 1.5 30 1 1-.866-.5.5 1.5 30 1 1 .866.5z"
          fill="#000"
          strokeWidth="1.49997"
          />
      </g>
      </svg>`
  )
  }
  
  
  function wP(props) {
  return (
      `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
      <path
          d="M22 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2.38-1.95 1.12-3.28 3.21-3.28 5.62 0 2.03.94 3.84 2.41 5.03-3 1.06-7.41 5.55-7.41 13.47h23c0-7.92-4.41-12.41-7.41-13.47 1.47-1.19 2.41-3 2.41-5.03 0-2.41-1.33-4.5-3.28-5.62.49-.67.78-1.49.78-2.38 0-2.21-1.79-4-4-4z"
          fill="#fff"
          stroke="#000"
          strokeWidth="1.5"
          strokeLinecap="round"
          {...props}
      />
      </svg>`
  )
  }
  
  function wQ(props) {
  return (
      `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
      
      
      <g
          fill="#fff"
          fillRule="evenodd"
          // stroke="#000"
          strokeWidth="1.5"
          strokeLinecap="round"
          strokeLinejoin="round">
          <path d="M8 12a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM24.5 7.5a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM41 12a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM16 8.5a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM33 9a2 2 0 1 1-4 0 2 2 0 1 1 4 0z" />
          <path
          d="M9 26c8.5-1.5 21-1.5 27 0l2-12-7 11V11l-5.5 13.5-3-15-3 15-5.5-14V25L7 14l2 12z"
          strokeLinecap="butt"
          stroke="#00000" 
          />
          <path
          d="M9 26c0 2 1.5 2 2.5 4 1 1.5 1 1 .5 3.5-1.5 1-1.5 2.5-1.5 2.5-1.5 1.5.5 2.5.5 2.5 6.5 1 16.5 1 23 0 0 0 1.5-1 0-2.5 0 0 .5-1.5-1-2.5-.5-2.5-.5-2 .5-3.5 1-2 2.5-2 2.5-4-8.5-1.5-18.5-1.5-27 0z"
          strokeLinecap="butt"
          />
          <path d="M11.5 30c3.5-1 18.5-1 22 0M12 33.5c6-1 15-1 21 0" fill="none" />
      </g>
      </svg>`
  
      
  )
  }
  
  
  function wR(props) {
    return (
        `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
        <g
            fill="#fff"
            fillRule="evenodd"
            stroke="#000"
            strokeWidth="1.5"
            strokeLinecap="round"
            strokeLinejoin="round">
            <path
            d="M9 39h27v-3H9v3zM12 36v-4h21v4H12zM11 14V9h4v2h5V9h5v2h5V9h4v5"
            strokeLinecap="butt"
            />
            <path d="M34 14l-3 3H14l-3-3" />
            <path d="M31 17v12.5H14V17" strokeLinecap="butt" strokeLinejoin="miter" />
            <path d="M31 29.5l1.5 2.5h-20l1.5-2.5" />
            <path d="M11 14h23" fill="none" strokeLinejoin="miter" />
        </g>
        </svg>`
  )
  }
  
  function no_piece(props){
    return (`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" width=${props.size} height="100%">
      <g>
      </g>
    </svg>`)
  }
  
  function piece_svg(i, size){
    // console.debug("i : ", i, ",  size : ", size)
    return __PIECE_FN_SVG[i]({'size' : size})
  }
  
  // __PIECE_FN_SVG[0] = wK, __PIECE_FN_SVG[1] = wQ,  __PIECE_FN_SVG[2] = wR,  __PIECE_FN_SVG[3] = wB,  __PIECE_FN_SVG[4] = wN,  __PIECE_FN_SVG[5] = wP;
  
  // __PIECE_FN_SVG[8] = bK, __PIECE_FN_SVG[9] = bQ,  __PIECE_FN_SVG[10] = bR,  __PIECE_FN_SVG[11] = bB,  __PIECE_FN_SVG[12] = bN,  __PIECE_FN_SVG[13] = bP;
  
  
  // { __PIECE_FN_SVG, wK, wQ, wR, wB, wN, wP, bK, bQ, bR, bB, bN, bP}
  const __PIECE_FN_SVG = [
                                  wK, wQ, wR, wB, wN, wP, no_piece, no_piece,
                                  bK, bQ, bR, bB, bN, bP, no_piece, no_piece
                                  ]
  const SVG = {
      piece_svg: piece_svg
    }
  
  const constant = {
      bw_cname : {
          0 : 'white-square',
          1 : 'black-square',
          black : 'black-square',
          white : 'white-square',
          'black-square' : 'black-square',
          'white-square' : 'white-square',
      },
  
      FILE : ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
  };
  
  const redox = './images/redo_icon.svg'
  
  const undox = './images/undo_icon.svg'
  
  const blank = './images/blank.svg'
  
  var config = {
  		/**
  		 * Constants
  		 */
          WHITE :     '#f8ecec', // hex colo string
          BLACK :     '#ffa500', // hex colo string
          HIGHLIGHT : '#646400', // hex colo string
          CONTROLLER : {
                  redo : redox,
                  undo : undox,
                  blank : blank
          },
          SQ_SIZE: 10, // value in pixels
          BOARD : null,
  
  
  		/**
  		 * Functions
  		 * most of them are seters
  		 */
  
  		/**
  		 * It set square size in pixels by reading viewport height and width
  		 * and height and width of div enclosing board.
  		 * For mobile devices board spans over complete width by default, else till only div width
  		 * @param {Number | dictonary} px 
  		 */
  		set_sq_size : function(px = null){
  			if(typeof px == Number){
  				console.log("Number got : ", typeof px)
  				config.SQ_SIZE = px
  			}
  			else if(px.constructor == Object){
  				if(px.id && typeof px.id == 'string'){
  					var h = get.divheight(px.id),
  					w = get.divwidth(px.id)
  					H = get.bodyheight()
  					W = get.bodywidth()
  					l =  h > w ? parseInt(W / 8) : parseInt(h / 8)
  					config.SQ_SIZE = l
  				}
  			}
  		},
  
  		/**
  		 * set black and white color of board
  		 * takes colors dictionart of format : 
  		 * {
  		 * 		black : "..." // hex color string with #
  		 *      white : "..." // hex color string with #
  		 * }
  		 * @param {dictionary} colors 
  		 */
  		set_black_white : function(colors){
  			if(colors.constructor == Object){
  				if(colors.black && colors.white &&
  					typeof colors.black == 'string' && typeof colors.black == 'string' &&
  					match.iscolor(colors.black) && match.iscolor(colors.white)){
  						config.BLACK = colors.black
  						config.WHITE = colors.white
  				}
  			}
  		}
  };
  
  
  class converter{
      static vh2px(value) {
          var w = window,
            d = document,
            e = d.documentElement,
            g = d.getElementsByTagName('body')[0],
            x = w.innerWidth || e.clientWidth || g.clientWidth,
            y = w.innerHeight|| e.clientHeight|| g.clientHeight;
        
          var result = (y*value)/100;
          return result;
        }
        static vw2px(value) {
          var w = window,
            d = document,
            e = d.documentElement,
            g = d.getElementsByTagName('body')[0],
            x = w.innerWidth || e.clientWidth || g.clientWidth,
            y = w.innerHeight|| e.clientHeight|| g.clientHeight;
        
          var result = (x*value)/100;
          return result;
        }
  
        static percent2px(value, rootdivid = 'chess-board') {
          var g = document.getElementById(rootdivid);
          var x = g.clientWidth,
            y = g.clientHeight; 
          const result = {
              x : (x*value)/100,
              y : (y*value)/100
          };
          return result;
        }
  }
  
  class get{
  	static bodyheight(){
  		var w = window,
            d = document,
            e = d.documentElement,
            g = d.getElementsByTagName('body')[0];
            return  g.clientHeight; // || w.innerHeight || e.clientHeight ||
  	}
  
  	static bodywidth(){
  		var w = window,
            d = document,
            e = d.documentElement,
            g = d.getElementsByTagName('body')[0];
            return g.clientWidth // || w.innerWidth || e.clientWidth ||
  	}
  
  	static divheight(id){
  		var div = document.getElementById(id)
  		if(div){
  			return div.offsetHeight
  		}
  	}
  
  	static divwidth(id){
  		var div = document.getElementById(id)
  		if(div){
  			return div.offsetWidth
  		}
  	}
  }
  
  class match{
  	static iscolor(){
  		return /^#[0-9A-F]{6}$/i.test('#AABBCC')
  	}
  }
  
  
  
  class query{
  	static baseclass(cls){
  		if(cls instanceof Function){
  			let basecls = cls;
  			while (basecls){
  			  const newbasecls = Object.getPrototypeOf(basecls);
  			  if(newbasecls && newbasecls !== Object && newbasecls.name) basecls = newbasecls;
  			  else break;
  			}
  			return basecls;
  		}
  	}
  
  	static allinstances(cls){
  		var basecls = query.baseclass(cls)
  		console.log(basecls, basecls.instances)
  	}
  }
  objects = {
      add : function(instance){
          var basecls = query.baseclass(instance.constructor)
          if(basecls.name in objects) objects[basecls.name].push(instance)
          else objects[basecls.name] = [instance]
      }
  }
  class State{
      constructor(board){
          this.board = board ? board : null; 
          this.sq_n = null;
          this.valid_moves = [];
          this.clicked = false;
          this.movenow = false;
          this.update = false;
          this.cntrl = {type : 'nan'};
          
      }
      get(){
          this.clicked = !this.clicked;
          return this;
      }
      move(){
          if(this.contains(this.sq_n)){ // x ==? f,   y ==? r
              this.movenow = true
          }else this.movenow = false
          return this.movenow;
      }
      
      contains(n_sq_n){
          // console.log("valid_moves ", this.valid_moves.map(x => this.x88_sq_id({r : x.y, f : x.x})), "n_sq_n", this.x88_sq_id(n_sq_n))
          return this.valid_moves.map(x => this.x88_sq_id({r : x.y, f : x.x})).includes(this.x88_sq_id(n_sq_n))
      }
  
      set_cntrl(type){
          this.cntrl.type = type;
      }
  
      set_board(board){
          this.board = board;
          return this;
      }
  
      set_sq_n(sq_n){
          this.clicked = true;
          this.sq_n = sq_n;
      }
      set_valid_moves(valid_moves){
          this.clicked = true;
          this.valid_moves = valid_moves;
      }
      set(sq_n, valid_moves){
          this.clicked = true;
          this.valid_moves = valid_moves;
          this.sq_n = sq_n
      }
      x88_sq_id(sq_n){
          if(sq_n) return (sq_n.r << 4) | sq_n.f
          if(this.sq_n == null) return null;
          return (this.sq_n.r << 4) | this.sq_n.f;
      }
  }
  
  const games = []
  class Click{
      static clicked_square(r, f, game=0){
          console.log("square clicked : id ", r, f)
          games[game].config.BOARD.ui_board[r][f].clicked_square()
          games[game].config.BOARD.clicked_board()
          return
      }
  
      static clicked_board(){
          console.log("board clicked")
          return
      }
  }
  
  const version = "0.1.0";
  
  /**
   *  Vertical  Representation used x88
   *  wR wP -- -- -- -- bP bR
   *  wN wP -- -- -- -- bP bN
   *  wB wP -- -- -- -- bP bB
   *  wK wP -- -- -- -- bP bK
   *  wQ wP -- -- -- -- bP bQ
   *  wB wP -- -- -- -- bP bB
   *  wN wP -- -- -- -- bP bN
   *  wR wP -- -- -- -- bP bR
   *  ....
   *  ...
   *  .
   *  8
   *  .
   *  .
   *  ..
   *  ...
   * 
   *  Board class translates it to horizontal one, by replacing : x <--> y
   * 
   * @ignore_above
   * 
   *  Y
   *  ^
   *  |
   *  |
   *  |
   *  |__________________> X
   * 
   *  x --> coloums ==> files
   *  y --> rows    ==> ranks
   *  
   * 
   * 
   * 
   */
  
  
  /**
  * Length : 64
  * Contains INT value of which only 10 used for now
  * First 6 from LSB for representation of square, so th E can place any where on board
  * Second 4  [6, 10) for piece representation.
  * Instruction Format
  * |sign_bit|  [ EMPTY_INVALID_BITS]  | influence_int | |   file    | | peices_info[0-16] |
  *    31            30  ... 17           17 ... 7          7 ... 4          4 ... 0 
  * @file
  * 3 bits to identify the file on board
  *  
  * @EMPTY_INVALID_BITS 
  * 14 bits not assign anything [17, 31);
  * 
  * @influence_int
  * 10 bit number forming sign int [-511 , 0 , 511] 1023 nums
  * negative for black influence and vice versa
  * 
  * @piecesinfo
  * Piece def 
  * 0000 0  white_king
  * 0001 1  white_queen
  * 0010 2  white_rook
  * 0011 3  white_bishop
  * 0100 4  white_knight
  * 0101 5  white_pawn
  * 0110 6  _no_piece
  * 0111 7  _invalid
  * 1000 8  black_king
  * 1001 9  black_queen
  * 1010 10 black_rook
  * 1011 11 black_bishop
  * 1100 12 black_knight
  * 1101 13 black_pawn
  * 1110 14 __no_piece
  * 1111 15 __invalid 
  *
  * @direction_info
  *    6      4      2
  *     \  5__|__3  /
  *      \    |   /
  *    7   \  |  /  1
  * 8__|____ \|/____|__ 0 
  *    |     /|\    |
  *    9    / |  \  15
  *       /11_|_13 \
  *     /     |      \
  *   10     12       14
  * Total 16 direction considered
  *
  *
  *
  * @player_info
  * pl_type  =   0 ..... 1 .....  3   .......   4 
  * string     white   black    Empty        Invalid
  */
  
  const __PIECES_STD = [];
  __PIECES_STD["wK"] = 0; __PIECES_STD["wQ"] = 1; __PIECES_STD["wR"] = 2; __PIECES_STD["wB"] = 3; __PIECES_STD["wN"] = 4; __PIECES_STD["wP"] = 5; __PIECES_STD["X"] = 6;
  __PIECES_STD["bK"] = 8; __PIECES_STD["bQ"] = 9; __PIECES_STD["bR"] = 10; __PIECES_STD["bB"] = 11; __PIECES_STD["bN"] = 12; __PIECES_STD["bP"] = 13;
  
  const __PIECES_ID = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
  
  const BOARD_MASK = 0x8
  
  const PIECE_MASK = 0xF
  
  const PIECE_INFO_MASK = 0x7F
  
  const PIECE_INFO_BITS = 7
  
  const PIECE_BITS = 4
  
  const x88_MASK = 0x7F
  
  const x88_MOVE_BITS = 14
  
  const x88_MOVE_MASK = 0x3FFF
  
  const x88_BITS = 7
  
  const DEAD = 0x8 // Square number 8 represents DEAD piece
  
  const DIR_OFF_INV = 0
  
  const EMPTY_SQ_TYPE = 2
  
  const EMPTY_SQ = 6
  
  const INVALID_SQ = 7
  
  /**
  * store number value for piece, max it can go in any one direction
  */
  const __RANGE = {
  KING : 1,
  QUEEN : 8,
  ROOK : 8,
  BISHOP : 8,
  HORSE : 1,
  PAWN : 1, 
  DEFAULT : 8,
  };
  
  const __BORANK = [ [0b000, 0b001], //WHITE
                      [0b111, 0b110] ] //BLACK
  
  const __RANGE_ARR = [1, 8, 8, 8, 1, 1, 8, 0, 1, 8, 8, 8, 1, 1, 8, 0];
  
  const __DIRECTION = {
      KING : [0, 2, 4, 6 ,8 ,10 ,12, 14],
      QUEEN : [0, 2, 4, 6 ,8 ,10 ,12, 14],
      ROOK : [0, 4, 8, 12],
      BISHOP : [2, 6, 10, 14],
      HORSE : [1, 3, 5, 7, 9, 11, 13, 15],
      PAWN : [2, 4, 6],
      DEFAULT : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
  };
  
  
  
  const __DIR_LENGTH = {
      KING : 8,
      QUEEN : 8,
      ROOK : 4,
      BISHOP : 4,
      HORSE : 8,
      PAWN : 3,
      DEFAULT : 16,
  }
  
  const __HORSE_MOVES_OFFSET = [0x12, 0x21, 0x1F, 0x0E, -0x12, -0x21, -0x1F, -0x0E]
  
  const __DIR_OFFFSET_M = {
      KING : [0x01, 0,  0x11, 0, 0x10, 0, 0x0F, 0, -0x01, 0, -0x11, 0,  -0x10, 0, -0x0F, 0],
      QUEEN : [0x01, 0, 0x11, 0, 0x10, 0, 0x0F, 0, -0x01, 0, -0x11, 0, -0x10, 0, -0x0F, 0],
      ROOK : [0x01, 0,  0, 0, 0x10, 0, 0, 0, -0x01, 0, 0, 0, -0x10, 0, 0, 0],
      BISHOP : [0, 0, 0x11, 0, 0, 0,  0x0F, 0, 0, 0,  -0x11, 0, 0, 0, -0x0F, 0],
      HORSE : [0, 0x12, 0, 0x21, 0, 0x1F, 0, 0x0E, 0, -0x12, 0, -0x21, 0, -0x1F, 0, -0x0E],
      PAWN : [0, 0, 0x11, 0, 0x10, 0, 0x0F, 0, 0, 0, 0, 0, 0, 0, 0, ],
      DEFAULT : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
  }
  
  
  const __DIR_OFFFSET = {
      KING : [0x01, 0x11, 0x10, 0x0F, -0x01, -0x11, -0x10, -0x0F],
      QUEEN : [0x01, 0x11, 0x10, 0x0F, -0x01, -0x11, -0x10, -0x0F],
      ROOK : [0x01, 0x10, -0x01, -0x10],
      BISHOP : [0x11, 0x0F, -0x11, -0x0F],
      HORSE : [0x12, 0x21, 0x1F, 0x0E, -0x12, -0x21, -0x1F, -0x0E],
      PAWN : [0, 0x11, 0x10, 0x0F],
      DEFAULT : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
  }
  
  const __DIR_OFFFSET_ARR = [__DIR_OFFFSET.KING, __DIR_OFFFSET.QUEEN, __DIR_OFFFSET.ROOK, __DIR_OFFFSET.BISHOP, __DIR_OFFFSET.HORSE, __DIR_OFFFSET.PAWN, __DIR_OFFFSET.DEFAULT, [], 
                             __DIR_OFFFSET.KING, __DIR_OFFFSET.QUEEN, __DIR_OFFFSET.ROOK, __DIR_OFFFSET.BISHOP, __DIR_OFFFSET.HORSE, __DIR_OFFFSET.PAWN, __DIR_OFFFSET.DEFAULT, []]
  
  const __P_RANK = [0x1, 0x6]
  
  const __DIRECTION_ARR = [__DIRECTION.KING, __DIRECTION.QUEEN, __DIRECTION.ROOK, __DIRECTION.BISHOP, __DIRECTION.HORSE, __DIRECTION.PAWN, __DIRECTION.DEFAULT, [],
                          __DIRECTION.KING, __DIRECTION.QUEEN, __DIRECTION.ROOK, __DIRECTION.BISHOP, __DIRECTION.HORSE, __DIRECTION.PAWN, __DIRECTION.DEFAULT, []];
  
  // const __PIECE_VALUE = [255, 9, 5, 3, 3, 1, 0, 0, 767, 521, 517, 515, 515, 513, 0, 0];
  const __PIECE_VALUE = [1048756, 127, 64, 47, 47, 23, 0, 0, -1048756, -127, -64, -47, -47, -23, 0, 0];
  // const __CAPIECE_VALUE = [1, 2, 5, 3, 3, 1, 0, 0, -255, -9, -5, -3, -3, -1, 0, 0];
  
  
  const PIECE_VALUE_MASK = 0x1ff
  
  const __PIECE_SQ = null
  
  const __PIECE_INFL = [1, 3, 5, 7, 7, 9, 0, 0, 513, 515, 517, 519, 519, 521, 0, 0];
  
  const __PIECE = ["wK", "wQ", "wR", "wB", "wN", "wP", "X", "RE", "bK", "bQ", "bR", "bB", "bN", "bP", "X", "RE"];
  
  const __CLASSIC = [['wR', 'wN', 'wB', 'wQ', 'wK', 'wB', 'wN', 'wR'],
              ['wP', 'wP', 'wP', 'wP', 'wP', 'wP', 'wP', 'wP'],
              ['X',  'X',  'X',  'X',  'X',  'X',  'X',  'X'],
              ['X' , 'X' , 'X' , 'X' , 'X' , 'X' , 'X' , 'X'],
              ['X' , 'X' , 'X' , 'X' , 'X' , 'X' , 'X' , 'X'] ,
              ['X',  'X',  'X',  'X',  'X',  'X',  'X',  'X'],
              ['bP', 'bP', 'bP', 'bP', 'bP', 'bP', 'bP', 'bP'],
              ['bR', 'bN', 'bB', 'bQ', 'bK', 'bB', 'bN', 'bR']
              ];
  
  const __x88 = [/* Piece Info */ 2, 4, 3, 1, 0, 3, 4, 2, /* Sq Info */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // |  | |__| | ""|"" |_"_" 
               /* Piece Info */ 5, 5, 5, 5, 5, 5, 5, 5, /* Sq Info */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,   // |/\| |  | |   |   |__ 
  
               /* Piece Info */ 6, 6, 6, 6, 6, 6, 6, 6, /* Sq Info */ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
               /* Piece Info */ 6, 6, 6, 6, 6, 6, 6, 6, /* Sq Info */ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
               /* Piece Info */ 6, 6, 6, 6, 6, 6, 6, 6, /* Sq Info */ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
               /* Piece Info */ 6, 6, 6, 6, 6, 6, 6, 6, /* Sq Info */ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
  
               /* Piece Info */ 13, 13, 13, 13, 13, 13, 13, 13, /* Sq Info */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // |__\ |    /\  |"" |/
               /* Piece Info */ 10, 12, 11,  9,  8, 11, 12, 10, /* Sq Info */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // |__/ |__ /  \ |__ |\  
               ]
  
  const __STANDARD =  [["A", "B", "C", "D", "E", "F", "G", "H"],
                          ["1", "2", "3", "4", "5", "6", "7", "8"]
                       ];
  const __BTYPE_MOD = []
  __BTYPE_MOD['x88'] = 16; __BTYPE_MOD['NORMAL'] = 8; 
  
  const __STYLE = []
  __STYLE["CLASSIC"] = __CLASSIC
  
  
  const FUNCTION_START = "__________________________________________________\nProcess Start\n__________________________________________________";
  const FUNCTION_END = "__________________________________________________\nProcess End\n__________________________________________________";
  
  
  
  class Piece{
      constructor(piece){
          if(typeof(piece) == 'string'){
              if(!__PIECE.includes(piece)) return
              this.piece_id = __PIECES_STD[piece]
              this.name = piece
          }else if(typeof(piece) == 'number'){
              if(!__PIECES_ID.includes(piece)) return
              this.piece_id = piece
              this.name = __PIECE[piece]
          }
      }
  
      update_piece_id(piece){
          if(typeof(piece) == 'number'){
              piece &= 0xF // Piece is only stores in LSB 4 digit 
              if(!__PIECES_ID.includes(piece)) return
              // console.log("UUUUUUUUUUUUUU : "  + piece)
              this.piece_id = piece
              this.name = __PIECE[piece]
          }
      }
  }
  
  class Square{
  
      /**
       * 
       * @param {number} i row 
       * @param {number} j column
       * @param {number} num returns index value of square in 0x88 format
       */
      static x88sqno(i, j){
          return ((i << 4) + j) & 0x7F
      }
  
      static x88_v40sqno(sq_n){
          var c = {x : sq_n % 16, y :Math.floor(sq_n / 16) }
          if(c.y > 7) throw ErrorEvent("Invalid Parameters")
          return c
      }
  
      /**
       * 
       * @param {number} i 
       * @param {number} j 
       * @returns string representation of square
       */
      static sq_name(i, j = null, type = 'NORMAL'){
          if(j == null){
              var MOD = __BTYPE_MOD[type]
              j = i % MOD;
              i = Math.floor(i / MOD);
          }
          return __STANDARD[0][j] + __STANDARD[1][i]
      }
      constructor(i, j, piece, attack_flag = 0){
          this.sq = {x : j, y : i}
          this.name = this.sq_name(i, j)
          this.piece = piece
          this.attack_flag = attack_flag
      }
  
      /**
       * 
       * @param {number} i 
       * @param {number} j 
       * @returns string representation of square
       */
      sq_name(i, j = null, type = 'NORMAL'){
          if(j == null){
              var MOD = __BTYPE_MOD[type]
              i = i % MOD;
              j = Math.floor(j / MOD);
          }
          return __STANDARD[0][j] + __STANDARD[1][i]
      }
  
      set_piece_id(piece_id){
          
      }
  
      /**
       * returns the square color, White --> 0;   Black --> 1
       * @param {string} type 
       */
      static sq_color(i, j, type = 'NORMAL'){
          return ~((i & 1) ^ (j & 1))
      }
  
      sq_color(type = 'NORMAL'){
          return ~((this.sq.x & 1) ^ (this.sq.y & 1)) & 1
      }
  
  
  
  }
  
  class Board{
      constructor(style = 'CLASSIC'){
          this.board = array2D(8, 8)
          this.style = style
          this.init()
          this.v_moves = []
          this.engine = new Engine()
          this.computer = 0 // Black
      }
  
      init(){
          for(var i = 0; i < 8; i++){
              for(var j = 0; j < 8; j++){
                  this.board[i][j] = new Square(i, j, new Piece(__STYLE[this.style][i][j]))
              }   
          }
      }
  
      get_piece(j, i){
          return this.board[i][j].piece_id;
      }
  
      get_square(j, i){
          return this.board[i][j];
      }
  
      clear_flag(array = null){
          if(array){
              this.v_moves.forEach(c =>{
                  this.board[c.x][c.y].attack_flag = 0
              });
          }
      }
  
      valid_moves(j, i){ // i : x  ; j : y
          this.clear_flag(this.v_moves)
          var moves = this.engine.valid_moves(Square.x88sqno(i, j), null, this.engine.turn, true)
          this.v_moves = this.to_visual_array(moves)
          this.v_moves.forEach(c =>{
              this.board[c.x][c.y].attack_flag = 1
          });
          return this.v_moves;
      }
  
  
      move_black(){
          var black_engine = new Engine(this.engine.EB, 1);
          var sq = black_engine.next_move(null, null, 2);
          console.log("sq : ", sq)
          return sq;
      }
  
      move(n_j, n_i, turn = 0){
          // console.log("turn now : ", this.engine.turn);
          // console.log("val_moves : ", this.val_moves)
          var moved = this.engine.move(Square.x88sqno(n_i, n_j), null, this.val_moves)
          // console.log("white moved : ", this.engine.turn);
          this.update()
          return  moved;
  
          // if(moved) {
          //     var mv = this.move_black();
          //     console.log("Engine Board : ", this.engine.EB)
          //     var moved =  this.engine.move(mv.sq_n, mv.n_sq_n, null, true)
          //     console.log("moved : ", moved);
          //     console.log("black moved : ", this.engine.turn);
          //     // this.engine.turn = this.engine.turn;//this.engine.invert(this.engine.turn, 1); // Updating outside the engine 
          //     this.update();
          // }
  
      }
  
      next_move(n_j, n_i){
          var mv = this.engine.next_move(Square.x88sqno(n_i, n_j), null, 1, this.engine.turn);
          // console.log("next move is : ", mv);
          this.engine.sq_n = mv.sq_n;
          // this.engine.valid_moves(mv.sq_n, null, this.engine.turn, true, false)
          this.engine.move(mv.n_sq_n, null, null, true);
          // move
          return mv
      }
      update(){
          for(var i = 0; i < 128; i++){
              var c = Square.x88_v40sqno(i);
              if(c.x < 8){
                  // console.log("/c : " + c.x + " , " + c.y)
                  // console.log(this.engine.EB[i])
                  this.board[c.y][c.x].piece.update_piece_id(this.engine.EB[i]) //Vertical Representation ; so this.board[c.y][c.x]
              }
              
          }
          // console.log("EB : ", this.engine.EB.map(a=> a&15))
      }
  
      cntrl(action){
          // console.log("ACTION  : ", action)
          if(action == 'undo'){
              this.engine.undo()
          }else if(action == 'redo'){
              this.engine.redo()
          }else if(action == 'undoone'){
              this.engine.undo_one()
          }else {
              //Do nothing
          }this.update()
          // console.log("cntrl : EB ", this.engine.EB)
      }
  
  
      /**
       * 
       * @param {Array} board1D 
       */
      to_visual_array(board1D){
          var squares = [];
          for(var i = 0; i < board1D.length; i++){
              squares.push(Square.x88_v40sqno(board1D[i]));
          }return squares;
      }
  
      /**
       * To x88 Chess Board Representation
       */
      to_engine_board(){
          var enboard = array2D(8, 16 , 0)
          for(var i = 0; i < 8; i++){
              for(var j = 0; j < 8; j++){
                  enboard[Square.x88sqno(i, j)] = j << 4 | this.board[i][j].piece.piece_id
              }
          }
          return enboard
      }
  }
  
  
  class Engine{
      constructor(EB, turn = 0){
          if(EB != null) this.EB = [...EB]     //  Electronic Board x88 format
          else this.init()
          
          
          this.p_sq_n = null     //  This is for undo  and redo      
          this.n_p_sq_n = null   //  operation one move only
          
          this.sq_n = null
  
          this.val_moves = []
  
          this.hist_move = []
  
          this.future_move = []
  
          this.computer = 1
  
          this.turn = turn
      }
  
      init(){
          this.EB = Array(128).fill(0)
          for(var i = 0; i < 128; i++){
              var file = i & 0xF;
              if(file < 8) this.EB[i] = file << 4 | __x88[i] // Setting File info along with piece_id on main board 
              else this.EB[i] = __x88[i]
          }
          this.turn = 0 // White turn
      }
  
      init_pieces(){
          for(var i = 0; i < 128; i++){
              var file = i & 0xF;
              if(this.piece_area(i)){
                  this.EB[i] = file << 4 | __x88[i]
              }
          }
          this.turn = 0 // White turn
      }
  
      init_sq(){
          for(var i = 0; i < 128; i++){
              if(!this.piece_area(i)){
                  this.EB[i] = __x88[i]
              }
          }
          this.turn = 0 // White turn
      }
  
      set(board){
          this.EB = board.to_engine_board();
      }
  
      /**
       * returns rank of piece, relative black_piece_rank = | 7 - white_piece_rank |
       * @param {number} sq_n encoded in Int32
       */
      rank(sq_n){
          if(!isFinite(sq_n)) return null
          if(!this.piece_area(sq_n)) return null
          else return sq_n >> 4;
      }
  
      /**
       * 
       * @param {number} num 
       * @param {number} bits 
       */
      invert(num, bits = 0){
          if(bits){
              var MASK = 1 << bits - 1
              return  ~num & MASK
          }else return ~num & 7
      }
  
  
      /**
       * returns if piece info is present in that part of board
       * @param {number} sq_n
       */
      piece_area(sq_n){
          return (sq_n & BOARD_MASK) == 0
      }
  
      on_board(sq_n){
          return sq_n >= 0 && sq_n < 128
      }
  
  
      /**
       * return x co-ordinate of square
       * @param {number} sq 
       */
      _x(sq_n){
          if(!isFinite(sq_n)) return -1;
          if(this.piece_area(sq_n)) return sq_n & 7;
          return -1;
      }
  
      /**
       * returns y co-ordinate of square
       * @param {number} sq 
       */
      _y(sq_n){
          if(!isFinite(sq_n)) return -1;
          if(this.piece_area(sq_n)) return sq_n >>> 4;
          return -1;
      }
  
      /**
       * 
       * @param {number} sq_n 
       * @param {number} piece_id 
       */
      set_piece(sq_n, piece_id){
          var pie_ = (piece_id & 0xf);
          sq_n &= 0x7F; 
          this.EB[sq_n] |= pie_; //^ (this.set_square(sq_n) & 0x3c0);
          
          return this.EB[sq_n]; 
      }
  
      /**
       * returns boolean value if piece is present on square, true if yes, else false
       * @param {number} sq_n square number on board  (0 - 128) & BOARD_MASK == BOARD_MASK
       * @param {number} player player type , black(1) or white(0) or none(3) 
       * @returns {boolean} value if piece is present on square
       */
      haves_piece(sq_n, player = 3){
          if(!this.piece_area(sq_n)) return false
          var piece = this.EB[sq_n] & 0xF
          if(player == 1) return (piece > 7 && piece < 14);
          else if(player == 0) return (piece > -1 && piece < 6);  
          player = 1     
          if (player == 1 || player == 0) return (piece > -1 && piece < 6) || (piece > 7 && piece < 14);
          else return false
      }
  
      // move_encode(sq_n, n_sq_n){
      //     return ((((sq_n & x88_MASK) << x88_BITS) | this.piece(sq_n, true)) << x88_MOVE_BITS) | (((n_sq_n & x88_MASK) << x88_BITS) | this.piece(n_sq_n, true)) 
      // }
  
      move_encode(sq_n, n_sq_n){
          return ( ((((sq_n & x88_MASK) << PIECE_INFO_BITS) | this.EB[sq_n] & PIECE_INFO_MASK) << x88_MOVE_BITS) | (((n_sq_n & x88_MASK) << PIECE_INFO_BITS) | this.EB[n_sq_n] & PIECE_INFO_MASK)) 
      }
  
      move_decode(c_sq_n){
          return [[(c_sq_n >> (x88_MOVE_BITS + PIECE_INFO_BITS)) & x88_MASK, (c_sq_n >> x88_MOVE_BITS) & PIECE_INFO_MASK], [((c_sq_n >> PIECE_INFO_BITS) & x88_MASK), c_sq_n & PIECE_INFO_MASK]]
      }
  
      /**
       * return piece value / id on board
       * @param {number} sq_n square no on board
       * @param {boolean} abs absolute piece value if true 
       */
      piece(sq_n, abs = false){
          if(abs) return this.EB[sq_n] & 0xF;
          return this.EB[sq_n] & 0x7;
      }
  
      pl_type(sq_n){
          if(!this.on_board(sq_n)) return 3 // out of board
          if(this.haves_piece(sq_n, 1)) return 1 // 
          if(this.haves_piece(sq_n, 0)) return 0 //
          if(this.piece_area(sq_n)) return 2 // on board
          return 3
      }
  
  
      /**
       * moves the piece on square sq_n to new sqaure of n_sq_n, and set
       * current sq_n to empty square(6)
       * if you are in x state
       * x = undo(move(x))
       * @param {int} sq_n 
       * @param {int} n_sq_n 
       */
      move_nen(sq_n, n_sq_n, valid_moves = null){
          if(!n_sq_n){    
              var t_sq_n = sq_n
              sq_n = n_sq_n ? n_sq_n : this.sq_n
              n_sq_n = t_sq_n
          }console.log("sq_n", sq_n, " n_sq_n : ", n_sq_n, !this.sq_n || sq_n == n_sq_n)
          if(!this.sq_n || sq_n == n_sq_n) return
          console.log("val _ moves  : ", this.val_moves)
          if(this.val_moves.length != [].length){
              valid_moves = this.val_moves
              console.log("valid_moves", valid_moves , sq_n, !valid_moves.includes(n_sq_n))
              if(!valid_moves.includes(n_sq_n)) return
          }
          this.val_moves = []
          this.p_sq_n = [sq_n, this.EB[sq_n]]       // [sq_no, piece_info]  piece_info --> (file .. piece_id )
          this.n_p_sq_n = [n_sq_n, this.EB[n_sq_n]] // [sq_no, piece_info]  piece_info --> (file .. piece_id )  
          
          this.hist_move.push(this.move_encode(sq_n, n_sq_n))
          console.log("hist kmoves : ", this.hist_move)
          var index = (__BORANK[this.pl_type(sq_n)][this.piece(sq_n) < 5 ? 0: 1] << 4) + (this.EB[sq_n] >> 4 & 0x7)  ;
          this.EB[index] = sq_n;
  
          if(this.pl_type(n_sq_n) == 0 || this.pl_type(n_sq_n) == 1){
              index = (__BORANK[this.pl_type(n_sq_n)][this.piece(n_sq_n) < 5 ? 0: 1] << 4) + (this.EB[n_sq_n] >> 4 & 0x7)  ;
              this.EB[index] = n_sq_n;
          }
  
          this.EB[n_sq_n] = this.EB[this.sq_n]
          this.EB[sq_n] = EMPTY_SQ
  
          this.sq_n = n_sq_n      
  
      }
  
  
      /**
       * moves the piece on square sq_n to new sqaure of n_sq_n, and set
       * current sq_n to empty square(6)
       * if you are in x state
       * x = undo(move(x))
       * @param {int} sq_n 
       * @param {int} n_sq_n 
       */
      move(sq_n, n_sq_n, valid_moves = null, su = false){
          if(!n_sq_n){    
              var t_sq_n = sq_n
              sq_n = this.sq_n
              n_sq_n = t_sq_n
          }
          if(!valid_moves) valid_moves = this.val_moves
          if(!sq_n|| sq_n == n_sq_n) return false;
  
          if(!this.piece_area(sq_n) || !this.piece_area(n_sq_n)) return false;
          if(this.pl_type(n_sq_n) == this.pl_type(sq_n)) return false;
          if(this.pl_type(sq_n) == this.invert(this.turn, 1)) return false;
          
          if(!sq_n) return false;
  
          if(!su){
              if(!valid_moves.includes(n_sq_n)) return false;
          }
          
  
          
          this.p_sq_n = [sq_n, this.EB[sq_n]]       // [sq_no, piece_info]  piece_info --> (file .. piece_id )
          this.n_p_sq_n = [n_sq_n, this.EB[n_sq_n]] // [sq_no, piece_info]  piece_info --> (file .. piece_id )  
          
          this.hist_move.push(this.move_encode(sq_n, n_sq_n))
          if([0, 1].includes(this.pl_type(sq_n))){    
              var index = (__BORANK[this.pl_type(sq_n)][this.piece(sq_n) < 5 ? 0: 1] << 4) + (this.EB[sq_n] >> 4 & 0x7) + 8;
              this.EB[index] = n_sq_n;
          }
          // console.log("MOVED SUCCESS FULL TILL VALID  CHECKING .. ", sq_n, n_sq_n)
          // console.log("1. Piece : ", this.piece(sq_n), ", square : ", sq_n, ",  index : ", index, ' n_sq_n : ', n_sq_n)
          if(this.pl_type(n_sq_n) == 0 || this.pl_type(n_sq_n) == 1){
              index = (__BORANK[this.pl_type(n_sq_n)][this.piece(n_sq_n) < 5 ? 0: 1] << 4) + (this.EB[n_sq_n] >> 4 & 0x7) + 8;
              // console.log("2. Piece : ", this.piece(n_sq_n), ", square : ", n_sq_n, ",  index : ", index)
              this.EB[index] = sq_n;
          }
          // console.log("sq_n : ", sq_n, ", n_sq_n : ", n_sq_n) 
          this.EB[n_sq_n] = this.EB[sq_n]
          this.EB[sq_n] = EMPTY_SQ
  
          this.sq_n = null   
          this.future_move = []
          this.turn = this.invert(this.turn, 1);
  
          return true
      }
  
  
      /**
       * undo reverses back one move, 
       * two times undo results you in same position as earlier
       * x = undo(undo(x))
       */
      undo_one(){
  
          if(this.now_undo){
              this.redo()
          }
          if(this.now_redo){
              this.undo()
          }
  
      }
  
      redo(){
          if(this.future_move.length == 0) return false;
  
          var last_move = this.future_move.pop()
  
          last_move = this.move_decode(last_move)
  
          var p = last_move[0]
          var n = last_move[1]
  
          this.hist_move.push(this.move_encode(p[0], n[0]))
          var p_sq_n = [this.p_sq_n, this.EB[this.p_sq_n[0]]]       // [sq_no, piece_info]  piece_info --> (file .. piece_id )
          var n_p_sq_n = [this.n_p_sq_n, this.EB[this.n_p_sq_n[0]]] // [sq_no, piece_info]  piece_info --> (file .. piece_id )  
          if([0, 1].includes(this.pl_type(p[0]))){
              var index = (__BORANK[this.pl_type(p[0])][this.piece(p[0]) < 5 ? 0: 1] << 4) + (this.EB[p[0]] >> 4 & 0x7) + 8 ;
              this.EB[index] = p[0];
          }
          if([0, 1].includes(this.pl_type(n[0]))){
              var index = (__BORANK[this.pl_type(n[0])][this.piece(n[0]) < 5 ? 0: 1] << 4) + (this.EB[n[0]] >> 4 & 0x7) + 8 ;
              this.EB[index] = n[0];
          }
          
          this.EB[p[0]] = p[1]// (p[0] & 3) | (p[1] & 0xf)
          this.EB[n[0]] = n[1]// (n[0] & 3) | (n[1] & 0xf)
          this.now_redo = true
          this.turn = this.invert(this.turn, 1);
  
          return true;
  
      }
      undo(){        
          if(this.hist_move.length == 0) return false;
          // console.log('hist move before : ', this.hist_move)
          var last_move = this.hist_move.pop()
          // console.log('hist move after : ', this.hist_move)
          last_move = this.move_decode(last_move)
          
          var p = last_move[0]
          var n = last_move[1]
          this.future_move.push(this.move_encode(p[0], n[0]))
          var p_sq_n = [this.p_sq_n, this.EB[this.p_sq_n[0]]]       // [sq_no, piece_info]  piece_info --> (file .. piece_id )
          var n_p_sq_n = [this.n_p_sq_n, this.EB[this.n_p_sq_n[0]]] // [sq_no, piece_info]  piece_info --> (file .. piece_id )  
          if([0, 1].includes(this.pl_type(p[0]))){
              var index = (__BORANK[this.pl_type(p[0])][this.piece(p[0]) < 5 ? 0: 1] << 4) + (this.EB[p[0]] >> 4 & 0x7) + 8 ;
              this.EB[index] = n[0];
              // console.log("1. MODIFIED PIECE SQUARE STRORE OF THE BOEARD ====> index : ", index, "  square : ", this.EB[index]);
          }
          if([0, 1].includes(this.pl_type(n[0]))){
              var index = (__BORANK[this.pl_type(n[0])][this.piece(n[0]) < 5 ? 0: 1] << 4) + (this.EB[n[0]] >> 4 & 0x7) + 8 ;
              this.EB[index] = p[0];
              // console.log("BORANK  : ", this.pl_type(n[0]), this.piece(n[0]) < 5 ? 0: 1 )
              // console.log("2. MODIFIED PIECE SQUARE STRORE OF THE BOEARD ====> index : ", index, "  square : ", this.EB[index]);
          }
          
          this.EB[p[0]] = p[1]// (p[0] & 3) | (p[1] & 0xf)
          this.EB[n[0]] = n[1]// (n[0] & 3) | (n[1] & 0xf)
          
          this.now_undo = true
          this.turn = this.invert(this.turn, 1);
  
          return true
      }
  
      /**
       * It evaluates the board and get the integer indicating who is dominating on board
       * +ve score refer white will be wining
       * -ve score refer black will be wining 
       * simple evaluation function deciding wining by influence number of squares 
       * regardless of piece which is attacking
       * @returns {int} integer representation the eval score of board
       */
      eval(){
          var score = 0
          var piece_prt = 0
          for(var i = 0; i < 2; i++){
              var turn = i & 1
              if(i != turn) continue
              var offset_multiplier = turn == 1 ? -1 : 1 // offset multiplier +ve for white and -ve for black 
              // console.log(i, ". offset multiplier : ", offset_multiplier)
              for(var j = 0; j < 2; j++){
                  var rank = __BORANK[i][j] // rank
                  for(var k = 0; k < 8; k++){
                      var piece_sq = this.EB[rank << 4 | k | 8] & 0x7F // get the square where current piece is store
                      if(!this.piece_area(piece_sq)) continue
                      // piece_prt += __PIECE_VALUE[this.piece(piece_sq, true)]
                      var al = this.valid_moves(piece_sq, null, turn, true)
                      score += al.length
                  }
              }
          }
          // print("score : ", score + piece_prt, " sss : ", score, "  ppp : ", piece_prt)
          return score + piece_prt;
      }
  
      /**
       * 
       * @param {int} sq_n  current square
       * @param {int} p_sq_n previous square
       * @param {int} depth depth of chess chess min-max tree
       */
      next_move(sq_n = 0, p_sq_n = 0, depth = 5, turn = this.turn){
          // print("TOP depth : ", depth, "  sq_n : ", sq_n, "   n_sq_n : ", p_sq_n)
          if(depth == 0){
              var eva = this.eval()
              // print("DEPTH 0 : ", depth, "  sq_n : ", sq_n, "   n_sq_n : ", p_sq_n, eva)
              return {score : eva, sq_n : sq_n & x88_MASK, n_sq_n : p_sq_n & x88_MASK}
          }
          // var all_moves = this.get_all_moves(turn)
          var n_sq_n = null
          // var turn = 0; 
          // console.log("Suggesting move for player : ", turn, __BORANK[turn][0] , __BORANK[turn][1] )
          // console.log("all_moves : ", all_moves)
          var index = 0
          var sc = null, mx = {score : 1000000, sq_n : 0, n_sq_n : 0};
          var sc_arr = []
          var sel_arr = []
          for(var i = 0; i < 2; i++){
              var rank = __BORANK[turn][i] // get the rank where pieces are store
              for(var j = 8; j < 16; j++){
                  n_sq_n = this.EB[(rank << 4 )+ j] & x88_MASK // get the square of piece currently present
                  // console.log("index : ", (rank << 4) + j)
                  if(!this.piece_area(n_sq_n)) continue // Checks if the square got is within piece area of x88 board
                  
                  var temp_moves = this.valid_moves(n_sq_n, null, turn, true) // ,  Dir offset gives all direction for a piece on square wrt current player king
                  // console.log("turn : ", turn, "n_sq_n : ", n_sq_n, " index : ", (rank << 4 )+ j, (rank << 4 ), rank, "TEMP MOVES  : ", temp_moves)
                  // mx = {score : 1000000, sq_n : sq_n, n_sq_n : temp_moves[k]}; 
                  // console.log("n_sq_n original : ", n_sq_n, "temp moves  : ", temp_moves)
                  for(var k = 0; k < temp_moves.length; k++){
                      var moved = this.move(n_sq_n, temp_moves[k], temp_moves);
                      // console.log(k, ". Square sq_n : ", Square.sq_name(n_sq_n, null, 'x88'), ",  n_sq_n : ", Square.sq_name(temp_moves[k], null, 'x88'), " moved : ", moved)
                      // turn = this.invert(turn, 1);
                      // console.log("depth : ", depth, " sq_n : ", n_sq_n, "   n_sq_n : ", temp_moves[k])
                      sc = this.next_move(n_sq_n, temp_moves[k], depth - 1, turn)
                      // console.log(k, ". <= k , be n_sq_n : ", this.EB[(rank << 4 )+ j] & x88_MASK)
                      var undoed = this.undo()
                      // console.log(k, "turn : ", this.turn, turn,  "  moved : ", moved, ". undoed : ", undoed)
                      // console.log(k, ". <= k , af n_sq_n : ", this.EB[(rank << 4 )+ j] & x88_MASK)
                      
                      // console.log(k, ". Piece : ", this.piece(sc.sq_n), "  SQUARE |  sq_n : ", Square.sq_name(sc.sq_n, null, 'x88'), sc.sq_n, ",  n_sq_n : ", Square.sq_name(sc.n_sq_n, null, 'x88'), sc.n_sq_n, " score :", sc.score);
                      sel_arr.push([sc, index])
                      // console.log("score sc", sc, "score mx : ", mx, sc.score > mx.score, sc.score == mx.score)
                      // if(turn == 0) sc.score  *= -1
                      if(sc.score > mx.score && turn == 0) {
                          // console.log("1. ")
                          mx = sc;
                          index = i;
                          sc_arr = [[mx, index]]
                      }else if(sc.score == mx.score){
                          // console.log("2. ")
                          sc_arr.push([sc, index])
                      }else if(sc.score < mx.score && turn == 1) {
                          // console.log("3. ")
                          mx = sc//{score : sc.score, sq_n: sc.sq_n, n_sq_n : sc.n_sq_n};
                          index = i;
                          sc_arr = [[mx, index]]
                      }
                  }
              }
          }
          mx = sc_arr[Math.floor(Math.random() * sc_arr.length)][0]
          // console.log(". index : ", index, "Square to return : ", {score : sc, sq_n : all_moves[index] >> x88_BITS, n_sq_n : all_moves[index] & x88_MASK})
          return {score : mx.score, sq_n : mx.sq_n, n_sq_n : mx.n_sq_n}
      }
  
      get_all_moves(turn){
          var moves = []
          for(var i = 0; i < 2; i++){
              var rank = __BORANK[turn][i] // get the rank where pieces are store
              for(var j = 8; j < 16; j++){
                  var n_sq_n = this.EB[(rank << 4 )+ j] // get the square of piece currently present
                  // console.log("index : ", (rank << 4) + j)
                  if(!this.piece_area(n_sq_n)) continue // Checks if the square got is within piece area of x88 board
                  
                  var temp_moves = this.valid_moves(n_sq_n, null, turn, true, true) // ,  Dir offset gives all direction for a piece on square wrt current player king
                  // console.log(i, j ,"temp_moves ", temp_moves, Square.sq_name(n_sq_n, null, 'x88'), n_sq_n)
                  Array.prototype.push.apply(moves, temp_moves)
              }
          }
          return moves.sort((a, b) => this.piece(this.EB[a & x88_MASK]) < this.piece(this.EB[b & x88_MASK]))
      }
      /**
       * return moves dict like object
       * {moves : ... , score : ...}
       * moves are encoded by first 7 bits from lsb for attacked square and next 7 bits for which square is attacking
       * individual 7 bits are big-endian coded
       * 
       * e.g.  if 7th sqaure is attacking 5th sqaure 
       * then enoded in hex is :==  0x0705
       * @param {int} sq_n 
       * @param {Array} directions 
       * @param {int} turn 
       */
      valid_moves(sq_n, directions = null, turn = this.turn, move = false, en = false){
          if(!this.piece_area(sq_n)) return [];
          // if(attacked) this.c_sq_n = sq_n
          var moves = [];
          var piece = this.piece(sq_n);
          if(this.pl_type(sq_n) != turn) return [];
          // console.log("direction  == ", directions)
          // console.log("sq_n : ", sq_n)
          if(piece == 0){ //KING
              if(!directions) moves = this.king_moves(sq_n);
              else moves = this.king_moves(sq_n, directions)
          }
          else if(piece == 1){ //QUEEN
              if(!directions) moves = this.queen_moves(sq_n);
              else moves = this.queen_moves(sq_n, directions);
          }
          else if(piece == 2){ //ROOK
              if(!directions) moves = this.rook_moves(sq_n);
              else moves = this.rook_moves(sq_n, directions);
          }
          else if(piece == 3){ //BISHOP
              if(!directions) moves = this.bishop_moves(sq_n);
              else moves = this.bishop_moves(sq_n, directions);
          }
          else if(piece == 4){ //HORSE
              if(!directions) moves = this.horse_moves(sq_n);
              else moves = this.horse_moves(sq_n, directions);
          }
          else if(piece == 5){ //PAWN
              if(!directions) moves = this.pawn_moves(sq_n);
              else moves = this.pawn_moves(sq_n, directions);
          }else{
              //raise error
              console.log("ERR MOVE")
          }
  
          this.sq_n = sq_n
  
          if(move){ 
              this.val_moves = moves['moves'].map(a => a & x88_MASK)
              if(en) return moves['moves']
              else  return this.val_moves
          }
          // this.val_moves = []
  
          return moves // {moves: moves['moves'], 'score' :moves['score']};
      }
  
      king_moves(sq_n, directions = __DIR_OFFFSET.KING, turn = this.turn){
          if(!this.piece_area(sq_n)) return []
          var moves = []
          var score = []
          var c_piece_val = __PIECE_VALUE[this.piece(sq_n, true)]
          var pl_type = this.pl_type(sq_n)
          var a_sq_n = 0, b_sq_n = 0, can;
          directions.forEach(o => {
              a_sq_n = sq_n
              for(var i = 0; i < __RANGE.KING; i++){
                  a_sq_n = a_sq_n + o
                  can = this.go_to_square_if_can(a_sq_n, pl_type, moves)
                  if(!can && this.pl_type(a_sq_n) == this.invert(pl_type, 1)) {
                      // console.log(i, ". square : ", Square.sq_name(a_sq_n, null, 'x88'), a_sq_n & x88_MASK," k pl_type == sq_pl_type : ", this.pl_type(a_sq_n) == this.invert(pl_type, 1), this.pl_type(a_sq_n) , this.invert(pl_type, 1),pl_type)
                      var f_piece_val = __PIECE_VALUE[this.piece(a_sq_n, true)]
                      // console.log("f piece :", f_piece_val)
                      score.push((f_piece_val * -1))
                      break
                  }if(!can) break
              }
          });
          return {'moves' : moves.map(a => (sq_n << x88_BITS ) | (a & x88_MASK)), 'score' : score}
      }
       
  
      queen_moves(sq_n, directions = __DIR_OFFFSET.QUEEN){
          if(!this.piece_area(sq_n)) return []
          var moves = []
          var score = []
          var c_piece_val = __PIECE_VALUE[this.piece(sq_n, true)]
          var pl_type = this.pl_type(sq_n)
          var a_sq_n = 0, b_sq_n = 0, can;
          directions.forEach(o => {
              a_sq_n = sq_n
              for(var i = 0; i < __RANGE.QUEEN; i++){
                  a_sq_n = a_sq_n + o
                  can = this.go_to_square_if_can(a_sq_n, pl_type, moves)
                  if(!can && this.pl_type(a_sq_n) == this.invert(pl_type, 1)) {
                      // console.log(i, ". square : ", Square.sq_name(a_sq_n, null, 'x88'), a_sq_n & x88_MASK, " q pl_type == sq_pl_type : ", this.pl_type(a_sq_n) == this.invert(pl_type, 1), this.pl_type(a_sq_n) , this.invert(pl_type, 1), pl_type)
                      var f_piece_val = __PIECE_VALUE[this.piece(a_sq_n, true)]
                      // console.log("f piece :", f_piece_val)
                      score.push((f_piece_val * -1))
                      break
                  }if(!can) break
              }
          });
          return {'moves' : moves.map(a => (sq_n << x88_BITS ) | (a & x88_MASK)), 'score' : score}
      }
  
      rook_moves(sq_n, directions = __DIR_OFFFSET.ROOK, turn = this.turn){
          if(!this.piece_area(sq_n)) return []
          var moves = []
          var score = []
          var c_piece_val = __PIECE_VALUE[this.piece(sq_n, true)]
          var pl_type = this.pl_type(sq_n);
          var a_sq_n = 0, b_sq_n = 0, can;
          // console.log("directions === > ", directions)
          directions.forEach(o => {
              a_sq_n = sq_n
              for(var i = 0; i < __RANGE.ROOK; i++){
                  a_sq_n = a_sq_n + o
                  can = this.go_to_square_if_can(a_sq_n, pl_type, moves)
                  if(!can && this.pl_type(a_sq_n) == this.invert(pl_type, 1)) {
                      // console.log(i, ". square : ", Square.sq_name(a_sq_n, null, 'x88'), a_sq_n & x88_MASK," r pl_type == sq_pl_type : ", this.pl_type(a_sq_n) == this.invert(pl_type, 1), this.pl_type(a_sq_n) , this.invert(pl_type, 1), pl_type)
                      var f_piece_val = __PIECE_VALUE[this.piece(a_sq_n, true)]
                      // console.log("f piece :", f_piece_val)
                      score.push((f_piece_val * -1))
                      break
                  }if(!can) break
              }
          });
          return {'moves' : moves.map(a => (sq_n << x88_BITS ) | (a & x88_MASK)), 'score' : score}
      }
  
      bishop_moves(sq_n , directions = __DIR_OFFFSET.BISHOP, turn = this.turn){
          if(!this.piece_area(sq_n)) return []
          var moves = []
          var score = []
          var c_piece_val = __PIECE_VALUE[this.piece(sq_n, true)]
          var pl_type = this.pl_type(sq_n)
          var a_sq_n = 0, b_sq_n = 0, can;
          directions.forEach(o => {
              a_sq_n = sq_n
              for(var i = 0; i < __RANGE.BISHOP; i++){
                  a_sq_n = a_sq_n + o
                  can = this.go_to_square_if_can(a_sq_n, pl_type, moves)
                  if(!can && this.pl_type(a_sq_n) == this.invert(pl_type, 1)) {
                      // console.log(i, ". square : ", Square.sq_name(a_sq_n, null, 'x88'), a_sq_n & x88_MASK," b pl_type == sq_pl_type : ", this.pl_type(a_sq_n) == this.invert(pl_type, 1), this.pl_type(a_sq_n) , this.invert(pl_type, 1), pl_type)
                      var f_piece_val = __PIECE_VALUE[this.piece(a_sq_n, true)]
                      // console.log("f piece :", f_piece_val)
                      score.push((f_piece_val * -1))
                      break
                  }if(!can) break
              }
          });
          return {'moves' : moves.map(a => (sq_n << x88_BITS ) | (a & x88_MASK)), 'score' : score}
      }
      /**
       * returns array of all possible horse moves on x88ru board
       * @param {number} sq_n encoded x88ru format 
       * @returns {Array} moves array containing all possible moves
       */
      horse_moves(sq_n, directions = __DIR_OFFFSET.HORSE, turn = this.turn){
          if(!this.piece_area(sq_n)) return []
          var moves = []
          var score = []
          var c_piece_val = __PIECE_VALUE[this.piece(sq_n, true)]
          var can, n_sq_n;
          var pl_type = this.pl_type(sq_n), n_sq_n = 0
          for(var i = 0; i < directions.length; i++){
              n_sq_n = sq_n + directions[i] // new square if horse moved in (2 * i + 1) direction
              can = this.go_to_square_if_can(n_sq_n, pl_type, moves)
              if(!can && this.pl_type(n_sq_n) == this.invert(pl_type, 1)) {
                  // console.log(i, ". square : ", Square.sq_name(a_sq_n, null, 'x88'), n_sq_n & x88_MASK," h pl_type == sq_pl_type : ", this.pl_type(a_sq_n) == this.invert(pl_type, 1), this.pl_type(a_sq_n) , this.invert(pl_type, 1), pl_type)
                  var f_piece_val = __PIECE_VALUE[this.piece(n_sq_n, true)]
                  // console.log("f piece :", f_piece_val)
                  score.push((f_piece_val * -1))
                  continue
              }if(!can) continue
          }
          return {'moves' : moves.map(a => (sq_n << x88_BITS ) | (a & x88_MASK)), 'score' : score}
      } 
  
      /**
       * 
       * @param {number} sq_n 
       */
      pawn_moves(sq_n, directions = __DIR_OFFFSET.PAWN, turn = this.turn){
          if(!this.piece_area(sq_n)) return []
          
          var pl_type = this.pl_type(sq_n);
          
          var can, n_sq_n, to_add;
  
          var moves = [];
          var score = [0, 0]
          var c_piece_val = __PIECE_VALUE[this.piece(sq_n, true)]
          var f_piece_val = 0
          var L = directions.length
          
          if(directions != __DIR_OFFFSET.PAWN){
              for(var i = 0; i < 3 - L; i++){
                  directions.push(24) // Invalid adder , any addition or subtraction of 8, 24, 48, etc from on board will result off board
              }   
              directions.sort((a, b) => a > b ? a : b)
              L = 3             
          }
  
          var offsetm = this.piece(sq_n, true) == 5 ? 1 : -1
          
          var RANGE = this.rank(sq_n) == __P_RANK[pl_type] ? 2 : 1; // for first move
  
          n_sq_n = sq_n + offsetm * directions[L - 3]
          to_add = this.pl_type(n_sq_n) == EMPTY_SQ_TYPE ? false : true
          can = this.go_to_square_if_can(n_sq_n, pl_type, moves, to_add )    
          if(!can && this.pl_type(n_sq_n) == this.invert(pl_type, 1)) {
              // console.log(i, ". square : ", Square.sq_name(a_sq_n, null, 'x88'), a_sq_n & x88_MASK," b pl_type == sq_pl_type : ", this.pl_type(a_sq_n) == this.invert(pl_type, 1), this.pl_type(a_sq_n) , this.invert(pl_type, 1), pl_type)
              var f_piece_val = __PIECE_VALUE[this.piece(n_sq_n, true)]
              // console.log("f piece :", f_piece_val)
              score.push((f_piece_val * -1))
          }
          
          n_sq_n = sq_n + offsetm * directions[L - 2]
          to_add = this.pl_type(n_sq_n) == EMPTY_SQ_TYPE ? true : false
          can = this.go_to_square_if_can(n_sq_n, pl_type, moves, to_add )   
          
          if (RANGE == 2 && can) {
              n_sq_n = sq_n + 32 * offsetm
              to_add = this.pl_type(n_sq_n) == EMPTY_SQ_TYPE ? true : false
              can = this.go_to_square_if_can(n_sq_n, pl_type, moves, to_add )   
          }
          
          n_sq_n = sq_n + offsetm * directions[L - 1]
          to_add = this.pl_type(n_sq_n) == EMPTY_SQ_TYPE ? false : true
          can = this.go_to_square_if_can(n_sq_n, pl_type, moves, to_add )  
          if(!can && this.pl_type(n_sq_n) == this.invert(pl_type, 1)) {
              // console.log(i, ". square : ", Square.sq_name(a_sq_n, null, 'x88'), a_sq_n & x88_MASK," b pl_type == sq_pl_type : ", this.pl_type(a_sq_n) == this.invert(pl_type, 1), this.pl_type(a_sq_n) , this.invert(pl_type, 1), pl_type)
              var f_piece_val = __PIECE_VALUE[this.piece(n_sq_n, true)]
              // console.log("f piece :", f_piece_val)
              score.push((f_piece_val * -1))
          }
          
          return {'moves' : moves.map(a => (sq_n << x88_BITS ) | (a & x88_MASK)), 'score' : score}
      }
  
      
  
      /**
       * next/new square is confirmed and add in moves array
       * It only checks if player can place on the square irrespective of if king is in danger
       * It checks if the square is empty, or player is present, and type of player and act accordingly
       * @param {number} n_sq_n next/new square to confirm or add in moves array 
       * @param {number} pl_type  it stores player type black(1) or white(0) or None(3)
       * @param {Array} moves array storing the moves, n_sq_n will be added if can
       */
      go_to_square_if_can(n_sq_n, pl_type, moves = [], add = true){
          if(!add) return false;
          var n_ply_type = this.pl_type(n_sq_n)
          // console.log("pl_type : ", n_ply_type, pl_type)
          // console.log("N_PLY TYPE : " + n_ply_type)
          if(n_ply_type == 3) return false // out of board
          if(n_ply_type == 2){ // empty square
              moves.push(n_sq_n);
              return true
          }
          if(n_ply_type != pl_type){ // opposite team player standing
              moves.push(n_sq_n);
              return false
          }return false
      }
  
      /**
       * Will find all possible moves of oppenent in next turn, and return if sq_n is attacked by opponent
       * @param {number} sq_n 
       */
      if_attacked(sq_n){
          var opp_pl_type = this.invert(this.turn, 1), n_sq_n;
          var moves = [], attackers = [], movesabs = []
          this.turn = this.invert(this.turn, 1) //Inverting the turn, without changing move count
          for(var j = 0; j < 2; j++){
              var rank = __BORANK[opp_pl_type][j]; // Getting the rank where opp_pl_type players pieces position are stored in half part of x88 board
              for(var i = 8; i < 16; i++){
                  n_sq_n = this.EB[rank * 16 + i]
                  if(!this.piece_area(n_sq_n)) continue // Checks if the square got is within piece area of x88 board
                   
                  var direction = this._direction(n_sq_n, sq_n) >> 1 // Get the direction of n_sq_n --> sq_n, see @direction_info (8 direction)
                  if (direction == -1 ) continue
                  moves = this.valid_moves(n_sq_n, false, [__DIR_OFFFSET_ARR[this.piece(n_sq_n, true)][direction]]) // ,  Dir offset gives all direction for a piece on square wrt current player king
                  
                  if(this.piece(n_sq_n) == 1){
                      
                  }
                  if(moves.includes(sq_n)) {
                      // console.log("Found Attacker : " + __PIECE[this.piece(n_sq_n, true)] + "  " + this.piece(n_sq_n, true) + "  on square " + Square.sq_name(n_sq_n, null, 'x88') + "  " + n_sq_n)
                      attackers.push(n_sq_n);
                      Array.prototype.push.apply(movesabs, moves);
                      movesabs.push(n_sq_n)
                  } 
              }
              
          }
          this.turn = this.invert(this.turn, 1) //Inverting back the turn, without changing move count
          return {attackers : attackers, moves : movesabs };
      }
  
      /**
       * 
       * @param {Array} moves array
       * @param {number} direction  [1 - 16)
       */
      go_in_direction( moves , direction){
  
      }
  
       /**
       * return sq2 direction from sq1
       * @param {number} sq1 
       * @param {number} sq2 
       */
      _direction(sq1, sq2){
          if(!this.piece_area(sq1) || !this.piece_area(sq2)) return -1 // Both sq1 and sq2 should be in board area
          
          var diff = sq2 - sq1;
     
          if(this._y(diff) == 0 && this._x(diff) > 0) return 0;
          else if(diff == 0x12) return 1;
          else if(diff % 17 == 0 && diff > 0) return 2;
          else if(diff == 0x21) return 3;
          else if(diff % 8 == 0 && diff > 0) return 4;
          else if(diff == 0x1F) return 5;
          else if(diff % 15 == 0 && diff > 0) return 6;
          else if(diff == 0x0F) return 7;
          else if(this._y(diff) == 0 && this._x(diff) < 0 ) return 8;
          else if(diff == -0x12) return 9;
          else if(diff * -1 % 17 == 0 ) return 10;
          else if(diff == -0x21) return 11;
          else if(diff * -1 % 8 == 0) return 12;
          else if(diff == -0x1F) return 13;
          else if(diff * -1 % 15 == 0) return 14;
          else if(diff == -0x0E) return 15;
          else return -1;
      }
  
  
  }
  
  
  
  
  /**
   * 
   * @param {number} n : rows
   * @param {number} m : columns
   * @param {number} default_val : default value
   */
  function array2D(n, m, default_val = null){
      let array = new Array(n); 
  	for(let i = 0; i < n; i++) {
          array[i] = new Array(m); 
          for(let j = 0; j < m; j++){
              array[i][j] = default_val;
          }
  	}
   
  	return array; 
  }
  
  /**
   * 
   * @param {number} i 
   * @param {number} j 
   * @returns string representation of square
   */
  function square_name(i, j = null, type = 'NORMAL'){
      if(j == null){
          var MOD = __BTYPE_MOD[type]
          i = i % MOD;
          j = Math.floor(j / MOD);
      }
      return __STANDARD[0][i] + __STANDARD[1][j]
  }
  
  function sq_color(i, j = null, type = 'NORMAL'){
      return 0
  }
  
  /**
   * 
   * @param {Array} array1 
   * @param {Array} array2 
   */
  function intersect(array1, array2){
      return array1.filter(x =>{
          return array2.includes(x)
      });
  }
  
  /**
   * finds array1 - array2
   * @param {Array} array1 
   * @param {Array} array2 
   */
  function minus(array1, array2){
      return array1.filter(x =>{
          return !array2.includes(x);
      }); 
  }
  
  
  
  
  // export const CS = {Board, Piece, Engine, Square}
  
  // export const CT = {
  //                     __PIECES_STD, __PIECES_ID, BOARD_MASK ,PIECE_MASK , PIECE_INFO_MASK, PIECE_INFO_BITS ,
  //                     PIECE_BITS,x88_MASK ,x88_MOVE_BITS, x88_MOVE_MASK , x88_BITS ,DEAD,DIR_OFF_INV,EMPTY_SQ_TYPE, EMPTY_SQ ,
  //                     INVALID_SQ,__RANGE, __BORANK , __RANGE_ARR, __DIRECTION , __DIR_LENGTH, __HORSE_MOVES_OFFSET ,__DIR_OFFFSET_M,
  //                     __DIR_OFFFSET, __DIR_OFFFSET_ARR , __P_RANK,__DIRECTION_ARR,__PIECE_VALUE, PIECE_VALUE_MASK, __PIECE_SQ, __PIECE_INFL,
  //                     __PIECE ,__CLASSIC ,__STANDARD, __BTYPE_MOD, __STYLE, FUNCTION_START, FUNCTION_END
  
  //                 }
  
  // export const FN = {
  //     sq_color, intersect, minus, square_name
  // }
  const E = {
                      Board, Piece, Engine, Square,
  
                      __PIECES_STD, __PIECES_ID, BOARD_MASK ,PIECE_MASK , PIECE_INFO_MASK, PIECE_INFO_BITS ,
                      PIECE_BITS,x88_MASK ,x88_MOVE_BITS, x88_MOVE_MASK , x88_BITS ,DEAD,DIR_OFF_INV,EMPTY_SQ_TYPE, EMPTY_SQ ,
                      INVALID_SQ,__RANGE, __BORANK , __RANGE_ARR, __DIRECTION , __DIR_LENGTH, __HORSE_MOVES_OFFSET ,__DIR_OFFFSET_M,
                      __DIR_OFFFSET, __DIR_OFFFSET_ARR , __P_RANK,__DIRECTION_ARR,__PIECE_VALUE, PIECE_VALUE_MASK, __PIECE_SQ, __PIECE_INFL,
                      __PIECE ,__CLASSIC ,__STANDARD, __BTYPE_MOD, __STYLE, FUNCTION_START, FUNCTION_END,
  
  
                      sq_color, intersect, minus, square_name
                  }
  
  class Component{
      constructor(props){
          this.props = props;
          this.statex = props.statex;
      }
      setState(){
          this.statex.update = true
          var event = new Event('update');
          var body = document.getElementsByTagName('body')[0]
          body.addEventListener('update', Game.update_all(this))
          body.dispatchEvent(event)
  
      }
  }
  
  class UiSquare extends Component{
      constructor(props){
          super(props)
          this.sq_id = props.sq_id;
          this.piece_id = this.set_piece_id(this.sq_id);
          this.attacked = false
          this.state = {sq_id : this.sq_id, statex : this.statex},
          this.divid = props.divid
          this.check_if_cntrl_clicked = this.check_if_cntrl_clicked.bind(this);
          objects.add(this)
      }
      componentDidMount() {
          console.debug(`Basic Square Mounted with HTML`)
          // this.draw_square()
          this.draw_name()
          if(this.attacked){
              this.highlight_square()
          }
      }
  
      componentDidUpdate(){
          this.clear()
          this.draw_name()
          if(this.attacked){
              this.highlight_square()
          }
      }
  
      shouldComponentUpdate(){ 
          this.check_if_cntrl_clicked()
          this.set_piece_id(this.sq_id)
          this.attacked = this.statex.contains(this.sq_id)
          return true
      }
      
  
      check_if_cntrl_clicked(){
          if(this.statex.cntrl.type != 'nan'){
              this.statex.board.eboard.cntrl(this.statex.cntrl.type);
              this.statex.set_cntrl('nan');
              this.setState() // initiates react re-render mechanism
          }
      }
  
      clicked_square(){
          this.statex.set_sq_n(this.sq_id) 
          if(this.statex.move()){
              return;
          }
      } 
  
      clear(){
          const canvas = document.getElementById(`${this.sq_name()}`)
          const ctx = canvas.getContext("2d")
          ctx.clearRect(0, 0, canvas.width, canvas.height)
      }
      draw_square(){
          let k = this.sq_id;
          var color;
          if((k.f ^ k.r) & 1) color = config.WHITE
          else color = config.BLACK
      
          const canvas = document.getElementById(`${this.sq_name()}`)
          console.info(`canvas : ${canvas}`)
          const ctx = canvas.getContext("2d")
  
          ctx.fillStyle = color;
          ctx.fillRect(0, 0, canvas.width, canvas.height)
  
      }
      highlight_square(){
          const canvas = document.getElementById(`${this.sq_name()}`)
          const ctx = canvas.getContext("2d")
          var x = canvas.width / 2, y = canvas.height / 2;
          ctx.arc(x, y, 0.3 * x, 0, 2 * Math.PI)
          ctx.fillStyle = config.HIGHLIGHT
          ctx.fill()
      }
  
      draw_name(){
          const canvas = document.getElementById(`${this.sq_name()}`)
          const ctx = canvas.getContext("2d")
          ctx.fillStyle = "#000"
          ctx.font = "12px Courier"
  
          ctx.fillText(this.sq_name(), converter.vh2px(0.5), this.props.height - converter.vh2px(0.8))
          ctx.fillText(this.sq_name('x88'), this.props.width - converter.vh2px(4), this.props.height - converter.vh2px(0.8))
      }
  
      sq_color(){
          let k = this.props.sq_id;
          return constant.bw_cname[~(k.f ^ k.r) & 1]
      }
  
      set_piece_id(k){
          // console.debug(`statex.board : ${this.statex.board.eboard.board}`, this.statex.board)
          this.piece_id = this.statex.board.eboard.board[k.r][k.f].piece.piece_id//E.__PIECES_STD[w]
          return this.piece_id
      }
  
      sq_name(type = '8x8'){
          let k = this.props.sq_id;
          if(type == '8x8') return constant.FILE[k.f] + k.r.toString()
          else if(type == 'x88') return (k.r << 4) | k.f 
      }
  
      rerender(){
          document.getElementById(`${this.sq_name()}-svg`).innerHTML = `${SVG.piece_svg(this.piece_id, 50)}`
      }
      render(){
          return  `<div id = '${this.sq_name()}-square' class = ${this.sq_color()} onClick = 'Click.clicked_square(${this.sq_id.r}, ${this.sq_id.f})' style = 'width: ${config.SQ_SIZE}px; height:${config.SQ_SIZE}px; margin:-4px;'>
                      <div id = '${this.sq_name()}-svg' class= "posi" style="position:absolute;width:${config.SQ_SIZE}px;height:${config.SQ_SIZE}px;"> ${SVG.piece_svg(this.piece_id, 50)}</div>
                      <canvas ref = "canvas" id = ${this.sq_name()} className= 'posi' width = ${this.props.width} height =${this.props.height} style="position:absolute"/>
                  </div>`
          
      }
  }class UiBoard extends Component{
      constructor(props){
          super(props);
          this.divid = props.id
          this.eboard = new E.Board(); //ab
          this.state = {engine : this.eboard, statex : this.statex}
          this.statex = new State(this)
          this.clicked_board = this.clicked_board.bind(this);
          this.check_if_cntrl_clicked = this.check_if_cntrl_clicked.bind(this);
          objects.add(this)
          config.set_sq_size({id : this.divid})
          this.ui_board = this.init_ui_board()
      }
  
      init_ui_board(){
          let ui_board = []
          console.debug(`divid : ${this.divid}`)
          for(var i = 0; i < 8; i++){
              ui_board.push([])
              for(var j = 0; j < 8; j++){
                  ui_board[i].push(new UiSquare(
                      {
                          sq_id : {
                              r : j,
                              f : i
                          },
                          statex : this.statex,
                          width : config.SQ_SIZE, // in pixels
                          height : config.SQ_SIZE, // in pixels
                          color : null,
                          divid : this.divid
                      }
                  ))
              }
          }
          return ui_board;
      }
      componentDidMount(){
          for(var i = 0; i < this.ui_board.length; i++){
              for(var j = 0; j < this.ui_board.length; j++){
                  this.ui_board[i][j].componentDidMount()
              }
          }
      }
      componentDidUpdate(){
      }
  
      shouldComponentUpdate(){
          // this.check_if_cntrl_clicked();
          return true;
      }
  
      check_if_cntrl_clicked(){
          if(this.statex.cntrl.type != 'nan'){
              this.eboard.cntrl(this.statex.cntrl.type);
              this.statex.set_cntrl('nan');
              this.setState() // initiates react re-render mechanism
          }
      }
  
      clicked_board(){
          var mv = this.eboard.move(this.statex.sq_n.r, this.statex.sq_n.f)
          
          var valid_moves = this.eboard.valid_moves(this.statex.sq_n.r, this.statex.sq_n.f) // (f, r) == > (x, y)  x --> coloums ==> files  ,,   y --> rows    ==> ranks
          
          this.statex.set_valid_moves(valid_moves)
          this.statex = this.statex.get() // initiates rect re-render mechanism
          
          this.setState()
      }
  
      draw_row(j){
          let row = []
          for(var i = 0; i < 8; i++){
              row.push(
                  // <Square sq_id  = {{r : j, f : i}} statex = {this.statex} width = '80' height = '80' color = 'null'/>
                  `<div style = "display:inline-block;">
                      ${this.ui_board[i][j].render()}
                  </div>` 
                  )
          }return row.join("")
      }
      draw_board(){
          let board = []
          for(var i = 7; i >= 0; i--){
              board.push(
                  `<div>
                      ${this.draw_row(i)}
                  </div>`
              )
          }return board.join("")
      }
      uistring(){
          var div_board  = this.draw_board()
          var string = '';
          for(var i = 0; i < div_board.length; i++){
              for(var j = 0; j < div_board[i].length; j++){
                  string += div_board[i][j]
              }
          }return string
      }
      render(){
          console.debug()
          return `<div >
                      ${this.uistring()} 
                  </div>`
      }
  }
  
  
  // export const Component;
  // export const Click;
  // export const Square;
  // export const Board;
  class Game {
      
      constructor(props){
          this.mount_board(props.id)
  
          games.push(this)
      }
      static update_all(instance){
          for(var i in games){
              games[i].update(instance)
          }
      }
  
      /**
       * The mount function instantiate neccessary components require to play game
       */
      mount_board(id){
          this.board = new UiBoard(props = {id : id})        // This is construtor init phase
  
          this.config = JSON.parse(JSON.stringify(config));   // | This can termed as 
          this.config.BOARD = this.board                      // | getDerivedStateFromProps phase
          
          $("#test").html(this.board.render())                     // This is render phase
          
          this.board.componentDidMount()                           // This is Did Mount phase
      }
  
      /**
       * The update function needs to be call when the State is changed. 
       * Every Component in game has this.statex varible which is object of class State
       */
      update(instance){
          for(var i in instance.ui_board){
              for(var j in instance.ui_board[i]){
                  if(instance.ui_board[i][j].shouldComponentUpdate()){
                      instance.ui_board[i][j].rerender()
                      instance.ui_board[i][j].componentDidUpdate()
                      
                  }
              }
          }
      }
  
      move(){
          var c = this.board_index(i, j)
          i = c.x; j = c.y
          this.board.move(i, j)
          this.hold_flag = !this.hold_flag;
          this.board.valid_moves(i, j)
      }
      valid_moves(){
          var c = this.board_index(i, j)
          i = c.x; j = c.y
          this.hold_flag = !this.hold_flag;
          this.board.valid_moves(i, j)
      }
  }
  