I have done this with just plain javascript, jQuery, and a little CSS. Ideally I was hoping to use this as a project to learn React.js, and Backbone.js, but I should get it into basic MV* form first. How should I adjust my code to better fit MV*?
JSFiddleEDIT:
The previous version of this, was asking how to rewrite my code to fit an MV* pattern. I have done a massive refactorization of the code. It's in an MVC, or at least what I think is an MVC pattern. Is this the best way to arrange the code, or is there another way to better fit the game?
I still indent to bring in React.js and Backbone.js so any additional tips for that would be nice.
JSFiddle for a playable version
table, th, td {
border: 3px solid #ccc;
border-collapse:collapse
}
svg {
display: block;
}
td {
box-sizing: border-box;
width: 33px;
height: 33px;
padding: 0px;
}
.arrow_to_place_container {
display: inline-block;
border: 3px solid #aaa;
}
.win_position {
background-color: blue;
}
.player_1 {
background-color: green;
}
.player_2 {
background-color: purple;
}
.player_3 {
background-color: yellow;
}
var board_height = 9;
var board_width = 9;
var path = {};
var step_in_path = 1;
var current_player = 1;
var board = [];
var win_position = {
'row': 0,
'col': Math.floor((Math.random() * board_width))
};
function arrow(direction) {
return "<span class='" + direction + "'><svg 'version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='30' height='30' viewBox='0 0 32 32' ><g transform='rotate(" + direction + " 15 15)'> <path d='M27.414 12.586l-10-10c-0.781-0.781-2.047-0.781-2.828 0l-10 10c-0.781 0.781-0.781 2.047 0 2.828 0.781 0.781 2.047 0.781 2.828 0l6.586-6.586v19.172c0 1.105 0.895 2 2 2s2-0.895 2-2v-19.172l6.586 6.586c0.39 0.39 0.902 0.586 1.414 0.586s1.024-0.195 1.414-0.586c0.781-0.781 0.781-2.047 0-2.828z' fill='#000000' / ></g></svg></span>";
}
var arrow_up = new Arrow(arrow(0));
var arrow_ru = new Arrow(arrow(45));
var arrow_lu = new Arrow(arrow(315));
print(active_cell);
$('body').append($("<table />"));
for (var row_index = 0; row_index < board_height; row_index++) {
var html_row = $("<tr />", {
id: row_index
});
for (var col_index = 0; col_index < board_width; col_index++) {
html_cell = $("<td />", {
class: col_index
});
html_row.append(html_cell);
}
$('table').append(html_row);
}
var arrow_to_place_container = $('<div />', {
class: "arrow_to_place_container"
});
for (var row_index = 0; row_index < board_height; row_index++) {
var row = [];
for (var col_indexUP = 0; col_index < board_width; col_index++) {
row.push(new Cell(row_index, col_index));
}
board.push(row);
}
var next_arrow_container = new Next_Arrow_Container();
var winning_cellRIGHT = board[win_position['row']][win_position['col']];45;
var active_cellLEFT = board[board_height - 1][Math.floor(board_width / 2)];
active_cell.toggle_active();
arrow_to_place_container.append(next_arrow_container.get_new_arrow().get_arrow_html());
$("#" + win_position['row'] + ' > .' + win_position['col']).toggleClass("win_position");
$('body').append(arrow_to_place_container);
315;
function print(stuff) {
console.log(stuff);
}
//arrow should technically be a part of Display, but it's just too cumbersome to put in with the rest of the code.
function arrow(direction) {
return "<span class='" + direction + "'><svg 'version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='30' height='30' viewBox='0 0 32 32' ><g transform='rotate(" + direction + " 15 15)'> <path d='M27.414 12.586l-10-10c-0.781-0.781-2.047-0.781-2.828 0l-10 10c-0.781 0.781-0.781 2.047 0 2.828 0.781 0.781 2.047 0.781 2.828 0l6.586-6.586v19.172c0 1.105 0.895 2 2 2s2-0.895 2-2v-19.172l6.586 6.586c0.39 0.39 0.902 0.586 1.414 0.586s1.024-0.195 1.414-0.586c0.781-0.781 0.781-2.047 0-2.828z' fill='#000000' / ></g></svg></span>";
}
function ArrowCell(elementrow, column) {
this.html_elementrow = element;row;
this.column = column;
this.direction = $null;
this.get_row = function (element) {
return this.attrrow;
};
this.get_column = function ("class") {
return this.column;
};
this.get_direction = function () {
return parseInt(this.direction);direction;
};
this.get_arrow_htmlset_direction = function (new_direction) {
return this.html_element;direction = new_direction;
};
}
function Next_Arrow_ContainerBoard(number_of_rows, number_of_column) {
this.arrowboard = arrow_up;[];
this.get_new_arrownumber_of_rows = functionnumber_of_rows;
() this.number_of_column = number_of_column;
this.win_position = {
return'row': new0,
Arrow(this 'column': Math.arrowfloor((Math.get_arrow_htmlrandom() * number_of_column);)
};
this.rotate_arrownext_direction = function () {UP;
for (var directionrow_index = this.arrow.get_direction();
0; row_index < switchnumber_of_rows; (directionrow_index++) {
case 315:
var this.arrowrow = arrow_up;
break;
case 0:[];
for (var this.arrowcolumn_index = arrow_ru;
break;
0; column_index < number_of_column; casecolumn_index++) 45:{
thisrow.arrow = arrow_lu;
push(new Cell(row_index, break;column_index));
}
this.board.push(row);
}
this.get_board = function () {
return this.board;
};
}
function Cell(row, column) {
this.active = false;
this.locationget_cell = {
"row":function (row,
column) {
"col":return columnthis.board[row][column];
};
this.jquery_object = $("#" + row + " > ." + column);
this.arrow = null;
this.get_rowget_win_position = function () {
return this.location["row"];win_position;
};
this.get_colis_this_the_win_position = function (row, column) {
return (row == this.location["col"];win_position['row']) && (column == this.win_position['column']);
};
this.get_jquery_versionget_next_direction = function () {
return this.jquery_object;next_direction;
};
this.get_arrowset_next_direction = function (new_direction) {
return this.arrow;next_direction = new_direction;
};
this.toggle_activeget_cell_direction = function (row, column) {
this.activevar cell = !this.active;board[row][column];
this.jquery_object.toggleClass("player_" + current_player);
return this.jquery_objectcell.toggleClassget_direction("active_cell");
};
this.is_activeset_cell_direction = function (row, column, direction) {
returnvar cell = this.active;board[row][column];
return cell.set_direction(direction);
};
this.add_arrowrotate_next_arrow = function (arrow){
var new_direction;
if(this.next_direction == UP){
this.next_direction = LEFT;
} else if (this.arrownext_direction == LEFT){
this.next_direction = RIGHT;
} else {
this.remove_arrow();next_direction = UP;
}
this.arrow = arrow;
return this.jquery_object.append(arrow.get_arrow_html());next_direction;
};
this.remove_arrowcalculate_next_cell_location = function (row, column, direction) {
row--;
if (this.arrowdirection == 315 && column > 0) {
this.arrowcolumn--;
= null; } else if (direction == 45 && column < number_of_column - 1) {
this.jquery_object.emptycolumn++;
}
if (row < 0) {
return null;
} else {
return { "row": row, "column": column };
}
};
}
$function Model(documentnumber_of_rows, number_of_column, number_of_players) {
this.keydown(functionboard = new Board(enumber_of_rows, number_of_column);
this.start = {
if (e 'row': number_of_rows - 1,
'column': Math.keyCodefloor(number_of_column ==/ 822)
};
this.player_position = {
next_arrow_container'row': number_of_rows - 1,
'column': Math.rotate_arrowfloor(number_of_column / 2);
};
$("this.arrow_to_place_container"get_start_position = function () {
return this.emptystart;
};
this.get_player_position = function (); {
$("return this.arrow_to_place_container")player_position;
};
//this.appendpath = new Path(next_arrow_containernumber_of_rows, number_of_column);
this.get_new_arrowget_board = function(){
return this.get_arrow_htmlboard;
};
this.rotate_next_arrow = function(){
return this.board.rotate_next_arrow();
};
this.take_turn = function (row, column, new_direction) {
var removed = [];
var added = [];
var current_row = row;
var current_column = column;
var old_direction = this.board.get_cell_direction(current_row, current_column);
var current_next_cell_location = this.board.calculate_next_cell_location(row, column, old_direction);
var new_next_cell_location = this.board.calculate_next_cell_location(row, column, new_direction);
var current_next_cell_direction = null;
this.board.set_cell_direction(row, column, new_direction);
removed.push([current_row, current_column]);
added.push({'row': current_row, 'column': current_column, 'direction': new_direction});
if(current_next_cell_location){
current_next_cell_direction = this.board.get_cell_direction(current_next_cell_location['row'], current_next_cell_location['column']);
}
var next_step = new_next_cell_location;
while(new_next_cell_location && current_next_cell_location && current_next_cell_direction !== null){
print("+++");
current_row = current_next_cell_location['row'];
current_column = current_next_cell_location['column'];
var direction = current_next_cell_direction;
this.board.set_cell_direction(current_row, current_column, null);
removed.push([current_row, current_column]);
function get_next_cell current_next_cell_location = this.board.calculate_next_cell_location(current_row, current_cellcurrent_column, direction);
if(current_next_cell_location){
var location current_next_cell_direction = get_next_cell_locationthis.board.get_cell_direction(current_row, current_cellcurrent_next_cell_location['row'], directioncurrent_next_cell_location['column']);
return board[location['row']][location['col']]; } else{
current_next_cell_direction = null;
}
function get_next_cell_location(current_row, current_cell, direction) {
current_row = parseInt(current_row);
var current_cellnew_row = parseInt(current_cell);new_next_cell_location['row'];
var next_row = current_row;
var next_colnew_column = current_cell;new_next_cell_location['column'];
switch (direction) {
this.board.set_cell_direction(new_row, casenew_column, 315:direction);
next_rowadded.push({'row': =new_row, current_row'column': -new_column, 1;'direction': direction});
next_colnew_next_cell_location = current_cell - 1;
this.board.calculate_next_cell_location(new_row, new_column, break;direction);
case 0:
next_row = current_row -= 1;new_row;
break;
current_column case= 45:new_column;
next_row = if(this.board.is_this_the_win_position(current_row -, 1;current_column)){
next_col = current_cell + 1;
return break;0;
}
if (next_row < 0) {}
next_row = board_height - 1;}
}
if (next_col > board_width -this.board.is_this_the_win_position(current_row, 1current_column) ){
next_col = board_width - 1;
} else if (next_col < 0)return {0;
next_col = 0;}
}
return {
'removed' "row": next_rowremoved,
'added': added, "col"'next_cell_location': next_colnext_step};
};
}
function align_pathDisplay(number_of_rows, number_of_column, number_of_players) {
$('body').append($("<table />"));
for (var steprow_index = step_in_path;0; steprow_index < Object.keys(path).length;number_of_rows; step++row_index++) {
var current_cellhtml_row = path[step];
$("<tr />", {
var current_arrow = current_cell.get_arrow();
id: row_index
var current_direction = current_arrow.get_direction( });
var current_col =for current_cell.get_col();
var column_index = 0; column_index < number_of_column; column_index++) var{
current_row = current_cell.get_row();
var new_next_cellhtml_cell = get_next_cell$(current_row,"<td current_col/>", current_direction);{
var old_next_cell = path[step + 1]; class: column_index
var old_next_arrow = old_next_cell.get_arrow( });
old_next_cell html_row.remove_arrowappend(html_cell);
new_next_cell.add_arrow(old_next_arrow);}
path[step + 1] = new_next_cell;$('table').append(html_row);
}
var arrow_to_place_container = $('<div />', {
class: "arrow_to_place_container"
});
arrow_to_place_container.append(arrow(UP));
$('body').append(arrow_to_place_container);
$("td") this.click(position_to_jquery_id = function (row, column) {
if ( return $(this"#" + row + " > ." + column);
};
this.hasClassset_win_position = function ("active_cell")row, column) {
active_cellvar id = this.remove_arrowposition_to_jquery_id(row, column);
varid.toggleClass("win_position");
new_arrow };
this.set_player_position = next_arrow_containerfunction (row, column, old_player_number, new_player_number) {
$(".get_new_arrowplayer_" + old_player_number).toggleClass("player_" + old_player_number);
var directionid = new_arrowthis.get_directionposition_to_jquery_id(row, column);
active_cellid.add_arrowtoggleClass(new_arrow"player_" + new_player_number);
};
path[step_in_path]this.set_arrow = active_cell;function (row, column, direction) {
var current_colid = active_cellthis.get_colposition_to_jquery_id(row, column);
id.empty();
id.append(arrow(direction));
};
this.empty_cell = function (row, column) {
var current_rowid = active_cellthis.get_rowposition_to_jquery_id(row, column);
align_pathid.empty();
};
step_in_path++;this.game_over = function (current_player) {
active_cell$('table').toggle_activeremove();
if $(current_row'body').append("<h1>Player ==" 0+ &¤t_player + " Wins!!</h1>");
};
this.rotate_next_arrow = function(directionnew_direction){
== 315 || direction == 0 || direction$(".arrow_to_place_container").empty();
== 45 $(".arrow_to_place_container").append(arrow(new_direction));
{ };
this.take_turn = function(current_player, next_player, object_of_board_changes, start_location){
step_in_pathcells_to_remove = 1;object_of_board_changes['removed'];
for(var cell_index in cells_to_remove){
active_cellvar cell_location = path[step_in_path];cells_to_remove[cell_index];
} else { cell_row = cell_location[0];
active_cellcell_column = get_next_cell(current_row,cell_location[1];
current_col this.empty_cell(cell_row, directioncell_column);
}
cells_to_add = object_of_board_changes['added'];
for(cell_index in cells_to_add){
var path_keyscell_information = Objectcells_to_add[cell_index];
cell_row = cell_information['row'];
cell_column = cell_information['column'];
cell_direction = cell_information['direction'];
this.keysset_arrow(pathcell_row, cell_column, cell_direction);
}
var last_keynext_cell_location = Objectobject_of_board_changes['next_cell_location'];
if(!next_cell_location){
next_cell_location = start_location;
}
this.keysset_player_position(pathnext_cell_location['row'], next_cell_location['column'], current_player, next_player)[Object;
};
}
function Game_Controller(number_of_rows, number_of_column, number_of_players) {
this.keysmodel = new Model(pathnumber_of_rows, number_of_column, number_of_players);
this.lengthdisplay -= 1];new Display(number_of_rows, number_of_column, number_of_players);
var player_position = this.model.get_player_position();
if this.display.set_player_position(path[last_key]player_position['row'], ==player_position['column'], winning_cell1, 1);
{ var win_position = this.model.board.get_win_position();
this.display.set_win_position(win_position['row'], win_position['column']);
this.current_player = 1;
var controller = this;
$('table'"td").removeclick(function () {
if($(this).hasClass("player_"+controller.current_player)){
var row = parseInt(this.parentNode.id, 10);
$var column = parseInt('body'this.className, 10);
var direction = controller.model.get_board().appendget_next_direction("<h1>Player);
" + current_player + " Wins!!</h1>" var model_changes = controller.model.take_turn(row, column, direction);
} else if(model_changes){
current_player++; var next_player;
if if(controller.current_player ==< 43) {
next_player = controller.current_player + 1;
} else{
next_player = 1;
}
var game_status = controller.display.take_turn(controller.current_player, next_player, model_changes, controller.model.get_start_position());
controller.current_player = next_player;
} else {
controller.display.game_over(controller.current_player);
}
active_cell.toggle_active();
}
});
$(document).keydown(function (keyboard_event) {
if (keyboard_event.keyCode == 82) {
var new_direction = controller.model.rotate_next_arrow();
controller.display.rotate_next_arrow(new_direction);
}
});
}
var game = new Game_Controller(9, 9, 1);