国語 漢字パズル 部首の組み合わせ

国語 漢字パズル 部首の組み合わせ | ひまあそび-ミニゲーム hi0a.com

view source

JavaScript

document.title = '国語 漢字パズル 部首の組み合わせ';

/*
「部首」とは、漢字を作る主な要素、つまり首(かしら)となる部分のことです。

常用漢字とは、内閣が定めた「常用漢字表」に掲載されている漢字のことです。これは、一般の社会生活で現代の国語を書き表す際の漢字使用の目安として示されています。

形声文字とは、意味を表す部分と音を表す部分を組み合わせてできた漢字のことです。

会意文字とは、2つ以上の漢字を意味的に組み合わせて、新しい意味を表した漢字のことです。
*/

let aryOrg2 = [];
let clearCount = 0;


function setGame(){
  let $div = $('<div>',{id:'combo'});
  let $c = $('<h1>').text('正しい漢字の部首の組み合わせは?線でつなげて!');
  let $p = $('<p>').text('小中学で習う常用漢字の範囲');
  let $after = $('<div>',{id:'after'});
  let $btns = $('<div>',{id:'btns'});
  let $links = $('<div>',{id:'links'});
  let $canvas = $('<canvas>');
  let $ul1 = $('<ul>',{id:'a1'});
  let $ul2 = $('<ul>',{id:'a2'});

  $('#demo').append($div);
  $div.append($ul1).append($ul2).append($canvas);
  $div.after($after);
  $after.append($btns).append($c).append($p).append($links);

  let max = 5;
  let ctx = $canvas[0].getContext('2d');
  ctx.lineWidth = 4;

  let ary = [];
  let isSelect1 = false;
  let isSelect2 = false;
  let p1 = {x:0,y:0};
  let p2 = {x:0,y:0};
  let ele1;
  let ele2;
  let text1 = '';
  let text2 = '';
  let c = 0;
  let colors = ['#ff0000','#00ff00','#0000ff','#aaaa00','#00aaaa'];

  function changePanel(a,b){
    let c = $('<li>');
    a.before(c);
    a.removeClass('select');
    b.after(a);
    c.after(b);
    c.remove();
  }

  function shufflePanel(){
    for(let i=0;i<7;i++){
      let r = Math.floor(Math.random()*max);
      let r2 = Math.floor(Math.random()*max);
      let r3 = Math.floor(Math.random()*max);
      let r4 = Math.floor(Math.random()*max);
      changePanel($('.a1').eq(r),$('.a1').eq(r2));
      changePanel($('.a2').eq(r3),$('.a2').eq(r4));
    }
  }

  function setStage(){
    $ul1.empty();
    $ul2.empty();
    $links.empty();
    c = 0;
    ctx.clearRect(0,0,999,999);
    //ary = _.shuffle(aryOrg2).slice(0, max);

    let seenRadicals = new Set();
    let uniqueAry = [];

    let shuffled = _.shuffle(aryOrg2);
    for (let i = 0; i < shuffled.length && uniqueAry.length < max; i++) {
      let entry = shuffled[i];
      if (!seenRadicals.has(entry[0])) {
        seenRadicals.add(entry[0]);
        uniqueAry.push(entry);
      }
    }

    ary = uniqueAry;


    console.log(ary);

    ary.forEach(function(v){
      let radical = v[0];
      let component = v[1];
      let kanji = v[2];

      let $li1 = $('<li>');
      let $a1 = $('<a>').text(radical).addClass('a1');
      $li1.append($a1);
      $ul1.append($li1);

      let $li2 = $('<li>');
      let $a2 = $('<a>').text(component).addClass('a2');
      $li2.append($a2);
      $ul2.append($li2);

      $a1.on('click', function(){ checkResult(this); });
      $a2.on('click', function(){ checkResult(this); });
    });

    $canvas[0].width = $div.width();
    $canvas[0].height = $div.height();
    shufflePanel();
  }

  function checkResult(ele){
    if($(ele).hasClass('select')) return;

    if($(ele).hasClass('a1') && !isSelect1){
      $(ele).addClass('select');
      isSelect1 = true;
      ele1 = $(ele);
      text1 = $(ele).text();
    }

    if($(ele).hasClass('a2') && !isSelect2){
      $(ele).addClass('select');
      isSelect2 = true;
      ele2 = $(ele);
      text2 = $(ele).text();
    }

    let clientRect = ele.getBoundingClientRect();
    let canvasRect = $canvas[0].getBoundingClientRect();

    let x = clientRect.left + clientRect.width / 2 - canvasRect.left;
    let y = clientRect.top + clientRect.height / 2 - canvasRect.top;

    if($(ele).hasClass('a1')){
      p1 = {x: x, y: y};
    }
    if($(ele).hasClass('a2')){
      p2 = {x: x, y: y};
    }

    ctx.beginPath();
    ctx.arc(x, y, 4, 0, 2 * Math.PI);
    ctx.fill();


    ctx.beginPath();
    ctx.arc(x, y, 4, 0, 2 * Math.PI);
    ctx.fill();

    if(isSelect1 && isSelect2){
      let isMatch = ary.some(function(v){
        return (text1 === v[0] && text2 === v[1]);
      });

      isSelect1 = false;
      isSelect2 = false;

      if(!isMatch){
        let altKanji = checkAlternativeMatch(text1, text2);
        if (altKanji) {
          ary.push([text1, text2, altKanji]);
          $(ele1).addClass('nearly');
          $(ele2).addClass('nearly');
        } else {
          $(ele1).addClass('ng');
          $(ele2).addClass('ng');
          $('.a1,.a2').addClass('select');
          if(clearCount>2) clearCount--;
          setNext();
          return;
        }
      }

      $(ele1).addClass('ok');
      $(ele2).addClass('ok');
      ctx.strokeStyle = colors[c];
      ctx.beginPath();
      ctx.moveTo(p1.x, p1.y);
      ctx.lineTo(p2.x, p2.y);
      ctx.stroke();
      c++;

      if(c >= max){
        clearCount++;
        setNext();
      }
    }
  }

  function setLinks(){
    let h2 = $('<h2>').text('意味を調べる');
    $links.append(h2);
    ary.forEach(function(v){
      let url = '//www.google.com/search?q=' + v[2];
      let a = $('<a>',{target:'_blank',href:url}).text(v[2]);
      $links.append(a);
    });
  }

  function setNext(){
    getHint(clearCount);
    let $btn = $('<button>').text('次の問題へ');
    $btn.on('click', function(){
      setStage();
      $c.text(clearCount);
      $(this).remove();
    });
    $('li a').on('dblclick', function(){
      let t = $(this).text();
      let url = '//www.google.com/search?q=漢字 つくり ' + t;
      window.open(url);
    });
    $btns.append($btn);
    setLinks();
  }

  //例外漢字チェック
  function checkAlternativeMatch(radical, component) {
    let match = aryOrg2.find(entry => entry[0] === radical && entry[1] === component);
    return match ? match[2] : null;
  }


  setStage();
}



$.getJSON('./kanji.json', function(data){
  Object.keys(data).forEach(function(radical){
    let items = data[radical];
    for(let i = 0; i < items.kanji.length; i++){
      aryOrg2.push([radical, items.components[i], items.kanji[i]]);
    }
  });

  setGame();
});

CSS

#demo{
  display:grid;
  justify-items: center;
  align-items: center; 
}

footer,
#code,
pre{
  display:none;
}

h1{
  font-weight:bold;
}

#combo{
  display:flex;
  justify-content: space-between;
  margin:0 auto;
  width:320px;
  max-width:100%;
  position:relative;
  left:0;
  top:0;
}
#combo ul{
  position:relative;
  left:0;
  top:0;
  z-index:3;
}

#combo canvas{
  position:absolute;
  left:0;
  top:0;
  width:100%;
  height:100%;
}

#combo a{
  display:block;
  padding:12px;
  margin:4px 0;
  line-height:40px;
  border:2px solid #000;
  font-size:32px;
  font-weight:bold;
  min-width:80px;
  text-align:center;
  box-sizing: border-box;
}

#combo a:hover{
  background-color:#ccc;
  cursor:pointer;
}
#combo a.select{
  background-color:#aaa;
}
#combo a.ng{
  background-color:#faa;
}
#combo a.ok{
  background-color:#afa;
}
#combo a.nearly{
  background-color:#ffa;
}
#after{
  text-align:center;
}
#links{
  height:40px;
  padding:4px;
}
#links a{
  padding:8px;
  font-size:48px;
}

#btns{
  height:80px;
}
button{
  display:block;
  margin:8px auto;
  padding:24px;
}

HTML

ページのソースを表示 : Ctrl+U , DevTools : F12

view-source:https://hi0a.com/game/game-text-kanji/

ABOUT

hi0a.com 「ひまあそび」は無料で遊べるミニゲームや便利ツールを公開しています。

プログラミング言語の動作デモやWEBデザイン、ソースコード、フロントエンド等の開発者のための技術を公開しています。

必要な機能の関数をコピペ利用したり勉強に活用できます。

プログラムの動作サンプル結果は画面上部に出力表示されています。

環境:最新のブラウザ GoogleChrome / Windows / Android / iPhone 等の端末で動作確認しています。

画像素材や音素材は半分自作でフリー素材配布サイトも利用しています。LINK参照。

仕様変更、API廃止等、実験途中で動かないページもあります。