jQuery Connect四 - 帮助调试功能

时间:2018-04-30 14:26:22

标签: javascript jquery

我的jQuery作业有问题(我是学生和JS初学者)。

基本上,我的任务是使用MV(C)(我们不使用控制器)模式使用jQuery创建一个Connect 4游戏。

比赛场地是一个2D阵列,看起来像这样。

- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , - , - , - , - , - 

并且玩家按下列进行游戏(f.ex.Player 1按3)

- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , x , - , - , - , - 

并且播放器2按下4

- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , - , - , - , - , - 
- , - , x , o , - , - , - 

等等。

当游戏结束时,获胜的四个字母应该变为大写。

我被困住了,并且真的不知道如何继续下去所以我创建了一个包含所有代码的GitHub存储库。

https://github.com/VeronicaLeeds/connectfour

基本上它初始化了比赛场地,你可以按数字,但是play()方法不会起作用。

如果有人能告诉我它为什么不将数组的值从 - 更改为x / o,那会很棒吗?

这是代码:

checkAvailableRow(column) {
            for (var i = 5 ; i >= 0 ; i--) {
                console.log(currentPlayer);
                if (playFieldArray[column][i] === "-") {
                    return i;
                    if(currentPlayer == "Player 1"){
                        playFieldArray[column][i] = "x";
                    } else {
                        playFieldArray[column][i] = "o";
                    }

                }
            }
            return -1;
        }

为什么Model.js中的checkIfWon()函数不起作用。

永远感激任何帮助。

2 个答案:

答案 0 :(得分:0)

return i;

返回会导致逻辑进程返回其所处的函数。因此,它之后的任何逻辑都不会发生。评论此声明并查看是否有任何变化(应该)。

或者将其移动到更改数组值的if / else之后。

答案 1 :(得分:0)

以下是在提供网格和x值时如何获得y轴的可用索引的示例:

//function to get available index for y when given grid and x
//  it will return false if no y is available
const getY = (grid,index)=>{
  const getIndex = (arr,index) => {
    if(arr[index]==="-"){
      return index;
    }
    if(index<0){
      return false;
    }
    return getIndex(arr,index-1);
  }
  return getIndex(grid[index],grid[index].length-1);
}

//Run some tests:
const rotate = grid =>//just to make the grid look normal in console.log
  grid[0].map((i,y)=>grid.map((i,x)=>[y,x]))
  .map((row)=>row.map(([y,x])=>grid[x][y]));
const format = grid => rotate(grid).map(row=>row.join(" ")).join("\n");

//function to mutate grid setting items for testing
const setItem = (x,grid,value) => y => grid[x][y]=value;
//7 by 6 grid containing -
const grid = Array.from(new Array(7),()=>Array.from(new Array(6),()=>"-"));
//add some values to grid
[0,1,2,3,4,5].forEach(x=>[0,1,2,3,4,5].slice(x).forEach(setItem(x,grid,"O")));
console.log("grid is:");
console.log(format(grid));
//see the values for y when asking for 
console.log("Testing....");
[0,1,2,3,4,5,6].forEach(
  x=>console.log(`y is ${getY(grid,x)} when x is:${x}`)
);

以下是检查玩家是否在给定网格和位置的情况下获胜的功能。

const isWin = (grid,position) => {
  const [x,y] = position;
  const player = grid[x][y];
  if(player==="-"){//current location in grid is empty, return false
    return false;
  }
  const countConnectedAllDirections = (directions,position,player) => {
    const connectCount = (direction,position,player,count=1)=>{
      const [x,y]=[position[0]+count*direction[0],position[1]+count*direction[1]];
      if((grid[x] && grid[x][y])!==player){
        return count;
      }
      return connectCount(direction,position,player,count+1);
    };
    return directions.map(
      ([back,forward])=>[connectCount(back,position,player),forward]
    ).map(
      ([countBack,forward])=>[countBack,connectCount(forward,position,player)]
    ).map(
      ([countBack,countForward])=>countBack+countForward-1
    ).reduce(
      (highest,item)=>(item>highest)?item:highest,0
    );
  }
  const directions = [[0,-1],[-1,-1],[-1,0],[-1,1]].map(([x,y])=>[[x,y],[x*-1,y*-1]]);
  return countConnectedAllDirections(directions,position,player)>=4;
};
//Run some tests:
const rotate = grid =>//just to make the grid look normal in console.log
  grid[0].map((i,y)=>grid.map((i,x)=>[y,x]))
  .map((row)=>row.map(([y,x])=>grid[x][y]));
const format = grid => rotate(grid).map(row=>row.join(" ")).join("\n");
const test = (message,pass) =>
  (pass)
    ? console.log(`Passed: ${message}`)
    : console.error(`Failed: ${message}`)
//function to mutate grid setting items for testing
const setItem = (x,y,value) => grid[x][y]=value;
//7 by 6 grid containing -
const createGrid = () => Array.from(new Array(7),()=>Array.from(new Array(6),()=>"-"));
var grid = createGrid();
test("Should return false when position is empty",isWin(grid,[0,5])===false);
const posReducer = (all,pos)=>all&&isWin(grid,pos);
[[0,5],[0,4],[0,3]].forEach(([x,y])=>setItem(x,y,"X"));
console.log(format(grid));
test(
  "Should return false when position is not empty but not connect 4",
  [[0,5],[0,4],[0,3]].reduce((all,pos)=>all||isWin(grid,pos),false)===false 
);
[[0,5],[0,4],[0,3],[0,2]].forEach(([x,y])=>setItem(x,y,"X"));
console.log(format(grid));
test(
  "Should return true when position is not empty and connect 4 vertical",
  [[0,5],[0,4],[0,3],[0,2]].reduce(posReducer,true)
);
grid = createGrid();//reset grid
[[1,5],[2,5],[3,5],[4,5]].forEach(([x,y])=>setItem(x,y,"X"));
console.log(format(grid));
test(
  "Should return true when position is not empty and connect 4 horizontal",
  [[1,5],[2,5],[3,5],[4,5]].reduce(posReducer,true)
);
grid = createGrid();//reset grid
[[1,5],[2,4],[3,3],[4,2]].forEach(([x,y])=>setItem(x,y,"X"));
console.log(format(grid));
test(
  "Should return true when position is not empty and connect 4 diagonal bottom left to top right",
  [[1,5],[2,4],[3,3],[4,2]].reduce(posReducer,true)
);
grid = createGrid();//reset grid
[[1,2],[2,3],[3,4],[4,5]].forEach(([x,y])=>setItem(x,y,"X"));
console.log(format(grid));
test(
  "Should return true when position is not empty and connect 4 diagonal top left to bottom right",
  [[1,2],[2,3],[3,4],[4,5]].reduce(posReducer,true)
);

以下是完整的游戏:

//view part
const [init,paint] = (()=>{
  const getStyle = gridValue => 
    (gridValue==="-")
      ? ""
      : `style="background-color:${(gridValue==="RED")?"red":"green"}"`;
  const createTD = ([x,y,gridValue]) => 
    `<td ${getStyle(gridValue)} data-role="turn" data-position="${x},${y}"></td>`;
  const createTR = gridRow => 
    `<tr>${gridRow.reduce((result,value)=>result+createTD(value),"")}</tr>`;
  const createTable = grid =>
      `<table>${
        grid.reduce((all,row)=>all+createTR(row),"")
      }</table>`
  ;
  const createMessage = message => `<div><h1>${message}</h1></div>`;
  const createResetButton = () => `<button data-role="reset">Reset</button>`;
  const createUndoRedo = () => `
    <div>
    <button data-role="undo_redo" data-direction="-1">Undo</button>
    <button data-role="undo_redo" data-direction="1">Redo</button>
    </div>
  `;
  const paint = state =>
      state.container.innerHTML = 
        createTable(state.grid) +
        createMessage(state.message) +
        createResetButton(state) +
        createUndoRedo();
  const init = state => state.container.addEventListener(
    "click",
    e=>{
      const role = e.target.getAttribute("data-role");
      if(role==="turn"){
        const xy = e.target.getAttribute("data-position");
        handleEvent(role,xy.split(",").map(Number));
      }
      if(role==="reset"){
        handleEvent(role,{});
      }
      if(role==="undo_redo"){
        const direction = e.target.getAttribute("data-direction");
        handleEvent(role,Number(direction));
      }
    }
  );
  return [init,paint];
})();


const handleEvent = (()=>{
  const createState = ([x,y])=>({
    grid:Array.from(new Array(x),()=>Array.from(new Array(y),()=>"-")),
    container:document.querySelector("#content"),
    currentPlayer:"RED",
    winner:false,
    message:`It's RED's turn`
  });
  var state = createState([7,6]);

  const isWin = (grid,position) => {
    const [x,y] = position;
    const player = grid[x][y];
    if(player==="-"){//current location in grid is empty, return false
      return false;
    }
    const countConnectedAllDirections = (directions,position,player) => {
      const connectCount = (direction,position,player,count=1)=>{
        const [x,y]=[position[0]+count*direction[0],position[1]+count*direction[1]];
        if((grid[x] && grid[x][y])!==player){
          return count;
        }
        return connectCount(direction,position,player,count+1);
      };
      return directions.map(
        ([back,forward])=>[connectCount(back,position,player),forward]
      ).map(
        ([countBack,forward])=>[countBack,connectCount(forward,position,player)]
      ).map(
        ([countBack,countForward])=>countBack+countForward-1
      ).reduce(
        (highest,item)=>(item>highest)?item:highest,0
      );
    }
    const directions = [[0,-1],[-1,-1],[-1,0],[-1,1]].map(([x,y])=>[[x,y],[x*-1,y*-1]]);
    return countConnectedAllDirections(directions,position,player)>=4;
  };
  const getAvailableIndex = (grid,x)=>{
    const getIndex = (arr,y) => {
      if(arr[y]==="-"){
        return y;
      }
      if(y<0){
        return false;
      }
      return getIndex(arr,y-1);
    }
    return getIndex(grid[x],grid[x].length-1);
  }
  const play = (player,grid,[posX,posY])=>{
    return grid.map((arr,x)=>arr.map(
      (val,y)=>(x===posX && y===posY) ? player : val
    ));
  }
  const rotateGrid = grid =>
    grid[0].map((i,y)=>grid.map((i,x)=>[y,x]))
    .map((row)=>row.map(([y,x])=>[x,y,grid[x][y]]));
  const paintRotate = state => paint({...state,grid:rotateGrid(state.grid)});
  const canMove = grid => grid.reduce(
    (result,ignore,index)=>result||(getAvailableIndex(grid,index)!==false),false
  )
  const handleEvent = ((states,statesIndex) => (eventType,data) =>{
    const newState={...states[statesIndex]};
    if(eventType==="turn"){
      if(newState.winner){
        return;
      }
      if(!canMove(newState.grid)){
        newState.message=`It's a draw, press reset to play again.`;
        paintRotate(newState);
        return;
      }
      const availableY = getAvailableIndex(newState.grid,data[0]);
      if(availableY===false){
        newState.message=`Cannot play this move, still ${newState.currentPlayer}'s turn.`
        if(states[statesIndex].message!==newState.message){
          statesIndex=states.length;
          states.push(newState);
          paintRotate(newState);
        }
        return;
      }
      statesIndex=states.length;
      const newGrid = play(newState.currentPlayer,newState.grid,[data[0],availableY]);
      newState.grid=newGrid;
      newState.winner=isWin(newState.grid,[data[0],availableY]);
      if(newState.winner){
        newState.message=`Winner is:${newState.currentPlayer}`;
        states.push(newState)
        paintRotate(newState);
        return;      
      }
      if(!canMove(newState.grid)){
        newState.message=`It's a draw, press reset to play again.`;
        states.push(newState);
        paintRotate(newState);
        return;
      }
      newState.currentPlayer=(newState.currentPlayer==="RED")?"GREEN":"RED";
      newState.message=`It's ${newState.currentPlayer}'s turn`;
      states.push(newState);
      paintRotate(newState);
    }
    if(eventType==="reset"){
      state = createState([newState.grid.length,newState.grid[0].length]);
      statesIndex=states.length;
      states.push(state);
      paintRotate(state);
    }
    if(eventType==="undo_redo"){
      const newIndex = statesIndex+data;
      if(newIndex<0){
        paintRotate({...states[statesIndex],message:"Cannot undo. "+states[statesIndex].message});
        return;
      }
      if(newIndex>=states.length){
        paintRotate({...states[statesIndex],message:"Cannot redo. "+states[statesIndex].message});
        return;
      }
      statesIndex=newIndex;
      paintRotate(states[statesIndex]);
    }
  })([state],0);
  init(state);
  paintRotate(state);
  return handleEvent;
})();
td {
  width:30px;
  height:30px;
  border:1px solid gray;
  cursor:pointer;
}
<div id="content"></div>