演習
1.「弱い」「普通」「強い」の3つのボタンを、「先攻」「後攻」と「スタート」の間に作成してください。
2. 以下の処理を行う関数を、3つの強さボタンのクリックイベントハンドラとして定義してください。
- ・弱い → 0、普通 → 1、強い → 2 となる定数と、強さを格納する変数を定義する。
- ・強さを選択した際に、その強さを表す定数を、変数に代入する。
- ・先攻後攻ボタン同様に、選択後に選択状態を保持する。
3. 先攻後攻ボタン同様に、リセットボタン押下時に、3つの強さボタンで選択状態となっているボタンを解除してください。
4. 以下の修正を行ない、3種類の強さをもつCOM対戦の三目並べを完成させてください。完成イメージをこちらに掲載します。
4-1. COM自動入力ロジックで使用する定数を定義
1 2 3 4 5 6 7 8 9 10 |
$(function() { // 定数定義 ︙ const CENTER_CELL = 4 const CORNER_CELLS = [0, 2, 6, 8] const MAX_RATE = 100 const MIN_RATE = 0 const RATE_THRESHOLD = 60 ︙ }) |
4-2. COMによる自動入力関数(do_input_by_com())の修正
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
$(function() { ︙ /** * COMによる自動入力実行 */ function do_input_by_com() { // 現在の入力情報を取得 let results = $("td").get() // COMのマーク let com_result_symbol = now_attack ? BATSU : MARU let empty_cell_ids = [] // 未入力セル情報 let own_cell_ids = [] // COM入力セル情報 let man_cell_ids = [] // プレイヤー入力セル情報 // ゲーム盤情報確認(該当するものについて、idを数値型に変換して格納) for (let cnt = 0; cnt < results.length; cnt++) { // 未入力の場合 if (! $(results[cnt]).html()) { empty_cell_ids.push(Number($(results[cnt]).attr("id"))) // COMが取ったセルの場合 } else if ($(results[cnt]).html() == com_result_symbol) { own_cell_ids.push(Number($(results[cnt]).attr("id"))) // プレイヤーが取ったセルの場合 } else { man_cell_ids.push(Number($(results[cnt]).attr("id"))) } } // 未入力セルがある場合 if (empty_cell_ids.length) { logic(empty_cell_ids, own_cell_ids, man_cell_ids, com_result_symbol) } return com_result_symbol } ︙ }) |
4-3. ロジック(logic())の追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
// 【前提】 // 弱い:常にランダムに選択 // 強い:常に正攻法 // 普通:60%の確率で正攻法を、40%の確率でランダムに選択(6:4=強い:弱い) $(function() { ︙ /** * ロジック */ function logic(empty_cell_ids, own_cell_ids, man_cell_ids, com_result_symbol) { let target_cell_id // 弱い場合、ランダムに1つ選択 if (com_skill == WEAK) { target_cell_id = get_id_by_random(empty_cell_ids) } // 普通 or 強い else { let rate; // 強い場合は常に正攻法ロジック if (com_skill == HARD) { rate = MIN_RATE } // 普通の場合は、一定の確率で正攻法ロジックを選択させる else if (com_skill == NORMAL) { rate = Math.floor(Math.random() * MAX_RATE) } // 確率を超えている場合、正攻法ロジック if (rate < RATE_THRESHOLD) { // 中央が空いている場合、真っ先に取得 if (empty_cell_ids.indexOf(CENTER_CELL) > -1) { target_cell_id = CENTER_CELL } // 真ん中が埋まっている場合、それ以外の場所を取る else { // COM、プレイヤーのリーチの有無を確認 let { complete_cells: com_complete_cells, is_center: com_is_center } = check_reach(own_cell_ids) let { complete_cells: man_complete_cells } = check_reach(man_cell_ids) // 空いている角のセル番号を取得 let empty_corner = empty_cell_ids.filter(function(empty_cell_id) { return CORNER_CELLS.indexOf(empty_cell_id) > -1 }) let com_has_reach = com_complete_cells.length // COMにリーチがあるか let man_has_reach = man_complete_cells.length // プレイヤーにリーチがあるか let is_empty_corner = empty_corner.length // 角に空きがあるか // 1. COMにリーチがある場合 // COMのリーチをそろえるように選択 if (com_has_reach) { target_cell_id = com_complete_cells[0] } // 2. COMにリーチがなく、プレイヤーにリーチがある場合 // プレイヤーのリーチを阻止するよう選択 else if (! com_has_reach && man_has_reach) { target_cell_id = man_complete_cells[0] } // 3. COM・プレイヤーともにリーチがなく、中央をCOMが取得している場合 // 空いているセルからランダムに選択 else if (! (com_has_reach || man_has_reach) && com_is_center) { target_cell_id = get_id_by_random(empty_cell_ids) } // 4. COM・プレイヤーともにリーチがなく、中央をプレイヤーが取得している中で、角が空いている場合 // 空いている角からランダムに選択 else if (! (com_has_reach || man_has_reach || com_is_center) && is_empty_corner) { target_cell_id = get_id_by_random(empty_corner) } // 5. COM・プレイヤーともにリーチがなく、中央をプレイヤーが取得している中で、角が空いていない場合 // 残りからランダムに選択 else if (! (com_has_reach || man_has_reach || com_is_center || is_empty_corner)) { target_cell_id = get_id_by_random(empty_cell_ids) } // 6. その他の場合 // 残りからランダムに選択 else { target_cell_id = get_id_by_random(empty_cell_ids) } } // ランダムに1つ取得 } else { target_cell_id = get_id_by_random(empty_cell_ids) } } // 結果を入れる $("#" + target_cell_id).html(com_result_symbol) } ︙ function get_id_by_random(cell_ids) { return cell_ids[Math.floor(Math.random() * cell_ids.length)] } ︙ }) |
4-4. リーチ判定関数(check_reach())の追加(logic() からコールされる)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
$(function() { ︙ function check_reach(cell_ids) { // リーチパターン1: 真ん中を含む // 真ん中のセルが自分のものであるか let is_center = cell_ids.indexOf(CENTER_CELL) > -1 let reach_lines = [] // 真ん中が自分のセルの場合、真ん中とその他で2連続があるか確認 if (is_center) { // 真ん中以外に自分のセルがあるか let exclude_center_cell_ids = cell_ids.filter(function(x) { return x != CENTER_CELL }) // ある場合 if (exclude_center_cell_ids.length) { reach_lines = exclude_center_cell_ids.map(function(x) { return [x, CENTER_CELL] }) } } // リーチパターン2: 外周の4ラインだけでリーチとなる(真ん中を含まない) let target_pattern = [ // 外周4ラインで2連続 [0, 1], [1, 2], [0, 3], [3, 6], [2, 5], [5, 8], [6, 7], [7, 8], // 外周4ラインの角同士 [0, 2], [0, 6], [0, 8], [2, 6], [2, 8], [6, 8] ] // 真ん中以外のセルで2つ連続したセルがあるか let exist_pattern = target_pattern.filter(function(pattern) { // COMが取得したセル同士であるか return cell_ids.indexOf(pattern[0]) > -1 && cell_ids.indexOf(pattern[1]) > -1 }) // 2連続のラインがある場合 if (exist_pattern.length) { // 真ん中を含む結果とマージ reach_lines = reach_lines.concat(exist_pattern) } // プレイヤーがリーチで、もう1つのセルに自分のセルがない列を取得 let complete_cells = reach_lines.reduce(function(accumelator, reach_line) { // リーチがかかっている列の、そろったパターンを抽出 let target_pattern = complete_patterns.filter(function(complete_pattern) { return complete_pattern.indexOf(reach_line[0]) > -1 && complete_pattern.indexOf(reach_line[1]) > -1 })[0] // リーチがかかっている、残りの1セルの番号を取得 let remaining_cell_id = target_pattern.filter(function(x) { return reach_line.indexOf(x) == -1 })[0] // 既に阻止しているか確認 if (! $("#" + remaining_cell_id).html()) { accumelator.push(remaining_cell_id) } return accumelator }, []) return { complete_cells, is_center } } ︙ }) |
あなたも、Avintonでこのような最先端技術を習得し活用してみませんか?
社員の成長を導きながら、AIやビッグデータなどの最先端技術をプロジェクトに活用していくことが私たちのビジョンです。Avintonの充実した技術研修でスキルアップを図り、あなたのキャリア目標を一緒に達成しませんか?