[React.js] BullsAndCows


BullsAndCows(デジタル野球)


👶 init ver.


import React from "react";
import { useState, useRef } from "react";

function getNumbers() {
  const candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  const answerArr = [];
  for (let i = 0; i < 4; i++) {
    const chosen = candidate.splice(Math.floor(Math.random() * (9 - i)), 1)[0];

    answerArr.push(chosen);
  }
  return answerArr; // = answer = [2,5,6,1]
}

const BullsAndCows = () => {
  const [answer, setAnswer] = useState(getNumbers());
  const [value, setValue] = useState("");
  const [result, setResult] = useState("");
  const [tries, setTries] = useState([]); // push쓰면 원본 바뀌므로 ...로 추가해주기

  let inputRef = useRef(null);

  const onSubmitForm = e => {
    e.preventDefault();

    if (value == answer.join("")) {
      setResult("홈런! 정답입니다.");
      setTries([...tries, { try: value, result: "홈런!" }]);
      setValue("");
    } else {
      let strike = 0;
      let ball = 0;
      const valueArr = value.split(""); // [1,3,5,7]
      console.log(answer, valueArr);

      for (let i = 0; i < 4; i++) {
        for (let j = 0; j < 4; j++) {
          if (valueArr[i] == answer[j]) {
            if (i == j) {
              strike++;
            } else {
              ball++;
            }
          }
        }
      }
      setResult(`${strike}스트라이크 ${ball}`);
    }

    setTries([...tries, result]);

    setValue("");
    inputRef.current.focus();
  };

  const onChangeInput = e => {
    setValue(e.target.value);
  };

  return (
    <>
      <div>
        <form onSubmit={onSubmitForm}>
          <input
            type="number"
            maxLength={4}
            value={value}
            onChange={onChangeInput}
            ref={inputRef}
          />
          <button>입력</button>
        </form>
      </div>
      <div>{result}</div>
      {/* <ul>
        LOG:{" "}
        {tries.map(el => (
          <li>{el}</li>
        ))}
      </ul> */}
    </>
  );
};

export default BullsAndCows;

🚀追加する

triesスクリーンで実現(記録ログを残してください)
  • コメントレガシー(liマッピング/配列形式)
  • countstateを10回追加
  • do-whileまたはwhile-if(){break}を使用した方が良いです.
  • count++位置に注意.
  • 📝 「試行」画面に表示

    import React from "react";
    import { useState, useRef } from "react";
    
    function getNumbers() {
      const candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
      const answerArr = [];
      for (let i = 0; i < 4; i++) {
        const chosen = candidate.splice(Math.floor(Math.random() * (9 - i)), 1)[0];
    
        answerArr.push(chosen);
      }
      return answerArr; // = answer = [2,5,6,1]
    }
    
    const BullsAndCows = () => {
      const [answer, setAnswer] = useState(getNumbers());
      const [value, setValue] = useState("");
      const [result, setResult] = useState("");
      const [tries, setTries] = useState([]); // push쓰면 원본 바뀌므로 ...로 추가해주기
    
      let inputRef = useRef(null);
    
      const onSubmitForm = e => {
        e.preventDefault();
    
        if (value == answer.join("")) {
          setResult("홈런! 정답입니다.");
          setTries([...tries, { try: value, result: "홈런!" }]);
          setValue("");
        } else {
          let strike = 0;
          let ball = 0;
          const valueArr = value.split("").map(v => parseInt(v)); // [1,3,5,7]
          console.log(answer, valueArr);
    
          for (let i = 0; i < 4; i++) {
            for (let j = 0; j < 4; j++) {
              if (valueArr[i] === answer[j]) {
                if (i === j) {
                  strike++;
                } else {
                  ball++;
                }
              }
            }
          }
          setResult(`${strike}스트라이크 ${ball}`);
          setTries([
            ...tries,
            { try: value, result: `${strike}스트라이크 ${ball}` },
          ]);
          console.log(tries);
          setValue("");
          inputRef.current.focus();
        }
      };
    
      const onChangeInput = e => {
        setValue(e.target.value);
      };
    
      return (
        <>
          <div>
            <h1>🎲숫자야구🏏</h1>
            <form onSubmit={onSubmitForm}>
              <input
                type="number"
                maxLength={4}
                value={value}
                placeholder="숫자를 맞혀보세요"
                onChange={onChangeInput}
                ref={inputRef}
              />
              <button>입력</button>
            </form>
          </div>
          <div>{result}</div>
          <ul>
            🔎 로그
            {tries.map(el => (
              <li key={el.try}>
                {el.try} : {el.result}
              </li>
            ))}
          </ul>
        </>
      );
    };
    
    export default BullsAndCows;
    
    🎨 result

    📃 Details
    // else문 내부 - setResult 후
    setTries([
            ...tries,
            { try: value, result: `${strike}스트라이크 ${ball}` },
          ]);
    // return 부분
    <ul>
        🔎 로그
        {tries.map(el => (
          <li key={el.try}>
            {el.try} : {el.result}
          </li>
        ))}
    </ul>
    🔨 に質問
     { try: value, result: `${strike}스트라이크 ${ball}` } 
      // 🔻 이렇게 하니까 에러남
     { try: value, result: result },
  • このresult値はsubmitで変更されているので、
    次のコミット時にresult値がすぐに反映されます.strikeball変数でやらざるを得ない.
    またはresultをconstcurrentResult=resultにコピーします
  • 📝 count limit+画面表示


    回数を10回以内に制限、
    現在の残りの回数を画面に表示しましょう.
    🙋‍♂️(Limit)10話を超えると?
    1.結果に「ゲーム終了」を印刷し、
    答えを教えてあげましょう.
    2.triesを空の配列[]に初期化します.
    3.答え(正しい数字)を再選択します.
    import React from "react";
    import { useState, useRef } from "react";
    
    function getNumbers() {
      const candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
      const answerArr = [];
      for (let i = 0; i < 4; i++) {
        const chosen = candidate.splice(Math.floor(Math.random() * (9 - i)), 1)[0];
    
        answerArr.push(chosen);
      }
      return answerArr; // = answer = [2,5,6,1]
    }
    
    const BullsAndCows = () => {
      const [answer, setAnswer] = useState(getNumbers());
      const [value, setValue] = useState("");
      const [result, setResult] = useState("");
      const [tries, setTries] = useState([]); // push쓰면 원본 바뀌므로 ...로 추가해주기
    
      let inputRef = useRef(null);
    
      const onSubmitForm = e => {
        e.preventDefault();
    
        if (tries.length >= 9) {
          setResult(`게임오버! 정답은 ${answer.join("")} 였습니다.`);
          setValue("");
          setTries([]);
          setAnswer(getNumbers());
        } else {
          if (value == answer.join("")) {
            setResult("홈런! 정답입니다.");
            setTries([...tries, { try: value, result: "홈런!" }]);
            setValue("");
          } else {
            let strike = 0;
            let ball = 0;
            const valueArr = value.split("").map(v => parseInt(v)); // [1,3,5,7]
            console.log(answer, valueArr);
    
            for (let i = 0; i < 4; i++) {
              for (let j = 0; j < 4; j++) {
                if (valueArr[i] === answer[j]) {
                  if (i === j) {
                    strike++;
                  } else {
                    ball++;
                  }
                }
              }
            }
            setResult(`${strike}스트라이크 ${ball}`);
            setTries([
              ...tries,
              { try: value, result: `${strike}스트라이크 ${ball}` },
            ]);
            console.log(tries);
            setValue("");
            inputRef.current.focus();
          }
        }
      };
    
      const onChangeInput = e => {
        setValue(e.target.value);
      };
    
      return (
        <>
          <div>
            <h1>🎲숫자야구🏏</h1>
            <p>남은 횟수: {10 - tries.length}</p>
            <form onSubmit={onSubmitForm}>
              <input
                required
                type="number"
                maxLength={4}
                value={value}
                placeholder="숫자를 맞혀보세요"
                onChange={onChangeInput}
                ref={inputRef}
              />
              <button>입력</button>
            </form>
          </div>
          <div>{result}</div>
          <ul>
            🔎 로그
            {tries.map(el => (
              <li key={el.try}>
                {el.try} : {el.result}
              </li>
            ))}
          </ul>
        </>
      );
    };
    
    export default BullsAndCows;
    
    🎨 result

    📃 Details
    // if-else 구조 
    if (tries.length >= 9) { // tries.length가 9면 > 이전 로그가 9개니까 지금이 10회째 시도임!
          setResult(`게임오버! 정답은 ${answer.join("")} 였습니다.`);
          setValue("");
          setTries([]);
          setAnswer(getNumbers());
        } else {
          if (value == answer.join("")) {
            // 정답이면 
          } else {
            // 오답이면 - strike, ball 
          }
        }
    // 남은 횟수 표시 (10-tries.length)
    <p>남은 횟수: {10 - tries.length}</p>

    📝 Logic+if-else構造変更


    🙋‍♂️ strike、ball判断ロジック変更
    方法1-これで修正!
    // 반복 변수 하나로 OK. 
    for (let i = 0; i < 4; i++) {
              if (valueArr[i] === answer[i]) {
                strike++;
              } else if (answer.includes(valueArr[i])) { // 포함하는지
                ball++;
              }
    メソッド2-既存のメソッド
    // 반복 변수(i,j) 두개 필요
     for (let i = 0; i < 4; i++) {
              for (let j = 0; j < 4; j++) {
                if (valueArr[i] === answer[j]) {
                  if (i === j) {
                    strike++;
                  } else {
                    ball++;
                  }
                }
              }
    🙋‍♂️ if-else構造の変更
  • 私が作成したコード
  • 私が先にチェックした回数は10回未満で、
    これは10回目でもゲーム終了となります.
    if (tries.length >= 9) { // tries.length가 9면 > 이전 로그가 9개니까 지금이 10회째 시도임!
       setResult(`게임오버! 정답은 ${answer.join("")} 였습니다.`);
       setValue("");
       setTries([]);
       setAnswer(getNumbers());
     } else {
       if (value == answer.join("")) {
         // 정답이면 
       } else {
         // 오답이면 - strike, ball 
     ```
  • 修正コード
  • 答えが正しいかチェックする
    if (value === answer.join("")) {
        // 정답이면
      } else { // 오답이면
        if (tries.length >= 9) {
           // 횟수 초과시 - gameover
        } else {
          for (let i = 0; i < 4; i++) {
            // strike, ball 
  • 📃 ぶんしそし


    🔻 BullsAndCows.jsx
  • triesの各要素がtryInfoのアイテムに送信される.
  • // tries.map 부분
    <ul>
            🔎 로그
            {tries.map((v, index) => (
              <Try key={`${index}차시도`} tryInfo={v} />
            ))}
    </ul>
    🔻 Try.jsx
  • props受入使用
  • import React from "react";
    
    const Try = ({ tryInfo, index }) => {
      return (
        <li key={`${index}차 시도:`}>
          {tryInfo.try} : {tryInfo.result}
        </li>
      );
    };
    
    export default Try;
    
    リファレンス
    元々index鍵として使えなかったのですが、
    この場合に使っても構いません.