Для классических крестиков-ноликов 3x3, на мой взгляд, проще всего сделать так: хранить выставленные на поле на поле крестики и нолики в одномерном массиве. А для проверки сделать массив для проверки выигрышных комбинаций, где перечислить смещения в основном массиве. И дальше — сделать цикл для проверки.
То есть получаем вот что:
var game_field=[' ',' ',' ',
' ',' ',' ',
' ',' ',' '];
var wins = [[0,1,2],[3,4,5],[6,7,8],[0,4,8],[2,4,6],[0,3,6],[1,4,7],[2,5,8]];
function check_game_over() {
for (i=0; i<wins.length; i++) { // перебираем все выигрышные комбинации
var game_over=true;
if (game_field[wins[i][0]]!=' ') { // если первая из проверяемых клеток не пуста, начинаем проверку
for (j=1; j<wins[i].length; j++) { // начинаем с единицы, так как сравнивать первую выигрышную клетку с собой не имеет смысла
if (game_field[wins[i][0]!=game_field[wins[i][j]]) { // если значение в текущей клетке проверяемой комбинации отличается от первой, комбинация не выигрышная, выходим из вложенного цикла
game_over=false;
break;
}
}
if (game_over) return game_field[wins[i][0]]; // возвращаем выигравшую сторону — крестик или нолик
}
}
return false;
}