题目来源于面试公司,先看看题目吧面试
假设咱们如今有一个 3 x 3 的井字棋游戏,咱们用一个二维数组表明棋盘,’x’ 表明玩家 X 下的棋子,’o’ 表明玩家 O 下的棋子,’e’ 表明该格没有棋子。例如:一个空白的棋盘如下面的二维数组表示:
[[‘e’, ‘e’, ‘e’], [‘e’, ‘e’, ‘e’], [‘e’, ‘e’, ‘e’] ]
若是玩家 X 在第一行第一列下了一步棋,玩家 O 在第二行第二列下了一步棋,则表示以下:
[[‘x’, ‘e’, ‘e’], [‘e’, ‘o’, ‘e’], [‘e’, ‘e’, ‘e’]]
如今须要一个 function,接受一个已有任意棋子的棋盘(和上面二维数组同样的格式),和玩家的标志(’x’ 或 ‘o'),返回该玩家下一步有几种可能的获胜方式(获胜方式以数组表示,[0, 0] 表明在第一行第一列下一步棋便可获胜,[2, 2] 表明在第三行第三列下一步棋便可获胜)。例如:
someFunction( ‘x’, [[‘o’, ‘e’, ‘e’], [‘o’, ‘x’, ‘o’], [‘x’, ‘x’, ‘e’]]) // return [ [2, 2], [0, 1], [0, 2] ] someFunction( ‘x’, [[‘x’, ‘o’, ‘o’], [‘x’, ‘x’, ‘e’], [‘e’, ‘o’, ‘e’]]) // return [[2, 2], [1, 2], [2, 0]] someFunction( ‘x’, [[‘x’, ‘x’, ‘o’], [‘e’, ‘e’, ‘e’], [‘e’, ‘e’, ‘e’]]) // return [ ] someFunction( ‘o’, [[‘o’, ‘o’, ‘o’], [‘e’, ‘e’, ‘e’], [‘e’, ‘e’, ‘e’]]) // return [ ]
最后是加分项:数组
下面是本身的代码实现.性能
var getSuccess; +function(){ //假设3个相连便可获胜. const linkLen = 3; //实际上, 咱们能够理解为, 围绕某个没有棋子的点,在 X 和 十 字这4个方向上的比较 //所以这里提供获取该4个方向上获取棋盘点的简易计算公式. const _getTraverlConfig = function(distance){ return [{ cStartRow : -1 * linkLen + 1, cStartLine : -1 * linkLen + 1, rowAdd : 1, lineAdd : 1, }, { cStartRow : -1 * linkLen + 1, cStartLine : linkLen - 1, rowAdd : 1, lineAdd : -1, }, { cStartRow : -1 * linkLen + 1, cStartLine : 0, rowAdd : 1, lineAdd : 0, }, { cStartRow : 0, cStartLine : -1 * linkLen + 1, rowAdd : 0, lineAdd : 1, }]; } //提供一个target字符串重复n次本身的方法 const _strRepeat = function (target, n){ var s = target, total = ''; while( n > 0 ) { if(n % 2 == 1) total += s; if(n == 1) break; s += s; n = n >>1 ; } return total; } //最终对外暴露的方法, 第一个参数是下棋的人, 第二个是棋盘的点数组. getSuccess = function( piece, chessboard ){ var availablePosition = [], distance = chessboard.length, traversalConfig, maxLen, compareStr, chessStr; //根据几个点连成线获取4个方向上的计算公式; traversalConfig = _getTraverlConfig(linkLen); //计算方向上的点数量. maxLen = 2 * (linkLen - 1) + 1; //若是传入的piece为x,那么这里的值就为xxx compareStr = _strRepeat(piece, linkLen); //这一步很重要, 将棋盘转为一个字符串,为的就是更快. chessStr = chessboard.reduce( (x,y) => x + y.join('') , '') //检查每个字符串, 若是是空的话就判断可否获胜. for( let i = 0, len = chessStr.length; i < len; i++) if( 'e' == chessStr.charAt(i) ) _checkAvailable(i); function _checkAvailable( sqnm ){ //计算点在棋盘上的行和列. let curRow = Math.floor(sqnm / distance), curLine = sqnm % distance; //以传入的参数填在该空点上,获得一个新的棋盘字符串. let tempChessStr = chessStr.substring(0, sqnm) + piece + chessStr.substring(sqnm + 1, chessStr.length); //4个方向上的检查 for( let i = 0, len = traversalConfig.length; i < len; i++) { let { cStartRow, cStartLine, rowAdd, lineAdd } = traversalConfig[i]; let tempStr = ''; let j = 0; let row = curRow + cStartRow; let line = curLine + cStartLine; while( j < maxLen ) { //超出边界视为空字符串. if(row < 0 || row > distance || line > distance || line < 0){ tempStr += ''; } else { //方向上棋盘的实际棋子的集合字符串. tempStr += tempChessStr.charAt(row * distance + line); } row += rowAdd; line += lineAdd; j++; } //若是在该字符串中含有须要比较的重复字符串便可认为该点能够获胜. if( -1 != tempStr.indexOf(compareStr) ) { availablePosition.push([curRow, curLine]); return; } } } console.log(availablePosition); } }();
写的很差, 请多指教.单元测试