X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=scribe%2Fscribe.jsx;h=ae05690dd42febe119b2541ab37b8e7ee6bf33f9;hb=c4f9db9ff6ba1f1f94490a0d8e96acccf0eb549e;hp=e7654b417eba2dfdc746a07d91f2a021de4bf2bb;hpb=e52910fa1933db903b039a0f4f32b6470b3100d4;p=lmno.games
diff --git a/scribe/scribe.jsx b/scribe/scribe.jsx
index e7654b4..ae05690 100644
--- a/scribe/scribe.jsx
+++ b/scribe/scribe.jsx
@@ -1,8 +1,8 @@
function team_symbol(team) {
if (team === "+")
- return "ð¥";
+ return "+";
else
- return "ð";
+ return "o";
}
function undisplay(element) {
@@ -26,7 +26,9 @@ const events = new EventSource("events");
events.onerror = function(event) {
if (event.target.readyState === EventSource.CLOSED) {
+ setTimeout(() => {
add_message("danger", "Connection to server lost.");
+ }, 1000);
}
};
@@ -77,14 +79,148 @@ events.addEventListener("game-state", event => {
* Game and supporting classes *
*********************************************************/
+const scribe_glyphs = [
+ {
+ name: "Single",
+ squares: [1,0,0,
+ 0,0,0,
+ 0,0,0]
+ },
+ {
+ name: "Double",
+ squares: [1,1,0,
+ 0,0,0,
+ 0,0,0]
+ },
+ {
+ name: "Line",
+ squares: [1,1,1,
+ 0,0,0,
+ 0,0,0]
+ },
+ {
+ name: "Pipe",
+ squares: [0,0,1,
+ 1,1,1,
+ 0,0,0]
+ },
+ {
+ name: "Squat-T",
+ squares: [1,1,1,
+ 0,1,0,
+ 0,0,0]
+ },
+ {
+ name: "4-block",
+ squares: [1,1,0,
+ 1,1,0,
+ 0,0,0]
+ },
+ {
+ name: "T",
+ squares: [1,1,1,
+ 0,1,0,
+ 0,1,0]
+ },
+ {
+ name: "Cross",
+ squares: [0,1,0,
+ 1,1,1,
+ 0,1,0]
+ },
+ {
+ name: "6-block",
+ squares: [1,1,1,
+ 1,1,1,
+ 0,0,0]
+ },
+ {
+ name: "Bomber",
+ squares: [1,1,1,
+ 0,1,1,
+ 0,0,1]
+ },
+ {
+ name: "Chair",
+ squares: [0,0,1,
+ 1,1,1,
+ 1,0,1]
+ },
+ {
+ name: "J",
+ squares: [0,0,1,
+ 1,0,1,
+ 1,1,1]
+ },
+ {
+ name: "Earring",
+ squares: [0,1,1,
+ 1,0,1,
+ 1,1,1]
+ },
+ {
+ name: "House",
+ squares: [0,1,0,
+ 1,1,1,
+ 1,1,1]
+ },
+ {
+ name: "H",
+ squares: [1,0,1,
+ 1,1,1,
+ 1,0,1]
+ },
+ {
+ name: "U",
+ squares: [1,0,1,
+ 1,0,1,
+ 1,1,1]
+ },
+ {
+ name: "Ottoman",
+ squares: [1,1,1,
+ 1,1,1,
+ 1,0,1]
+ },
+ {
+ name: "O",
+ squares: [1,1,1,
+ 1,0,1,
+ 1,1,1]
+ },
+ {
+ name: "9-block",
+ squares: [1,1,1,
+ 1,1,1,
+ 1,1,1]
+ }
+];
+
+function copy_to_clipboard(id)
+{
+ const tmp = document.createElement("input");
+ tmp.setAttribute("value", document.getElementById(id).innerHTML);
+ document.body.appendChild(tmp);
+ tmp.select();
+ document.execCommand("copy");
+ document.body.removeChild(tmp);
+}
+
function GameInfo(props) {
if (! props.id)
return null;
return (
-
{props.id}
- Invite a friend to play by sending this URL: {props.url}
+ {props.id}
+ {" "}
+ Share this link to invite a friend:{" "}
+ {props.url}
+ {" "}
+ copy_to_clipboard('game-share-url')}
+ >Copy Link
);
}
@@ -130,7 +266,7 @@ function PlayerInfo(props) {
return (
-
Players
+
Players:
{props.player.name}
{props.player.team ? ` (${props.player.team})` : ""}
{props.first_move ? "" : " "}
@@ -146,6 +282,50 @@ function PlayerInfo(props) {
);
}
+function Glyph(props) {
+
+ const glyph_dots = [];
+
+ let last_square = 0;
+ for (let i = 0; i < 9; i++) {
+ if (props.squares[i])
+ last_square = i;
+ }
+
+ const height = Math.floor(20 * (Math.floor(last_square / 3) + 1));
+
+ const viewbox=`0 0 60 ${height}`;
+
+ for (let row = 0; row < 3; row++) {
+ for (let col = 0; col < 3; col++) {
+ if (props.squares[3 * row + col]) {
+ let cy = 10 + 20 * row;
+ let cx = 10 + 20 * col;
+ glyph_dots.push(
+
+ );
+ }
+ }
+ }
+
+ return (
+ {props.name}
+
+
+
+ {glyph_dots}
+
+
+
+
+ );
+}
+
function Square(props) {
let className = "square";
@@ -155,6 +335,10 @@ function Square(props) {
className += " open";
}
+ if (props.last_move) {
+ className += " last-move";
+ }
+
const onClick = props.active ? props.onClick : null;
return (
@@ -165,147 +349,121 @@ function Square(props) {
);
}
-class Board extends React.Component {
- render_square(i,j) {
- const value = this.props.squares[i][j];
+function MiniGrid(props) {
+ function grid_square(j) {
+ const value = props.squares[j];
+ const last_move = props.last_moves.includes(j);
+
+ /* Even if the grid is active, the square is only active if
+ * unoccupied. */
+ const square_active = (props.active && (value === null));
+
return (
this.props.onClick(i,j)}
+ active={square_active}
+ last_move={last_move}
+ onClick={() => props.onClick(j)}
/>
);
}
- render() {
- return (
-
-
- {this.render_square(0,0)}
- {this.render_square(0,1)}
- {this.render_square(0,2)}
- {" "}
- {this.render_square(1,0)}
- {this.render_square(1,1)}
- {this.render_square(1,2)}
- {" "}
- {this.render_square(2,0)}
- {this.render_square(2,1)}
- {this.render_square(2,2)}
-
-
- {this.render_square(0,3)}
- {this.render_square(0,4)}
- {this.render_square(0,5)}
- {" "}
- {this.render_square(1,3)}
- {this.render_square(1,4)}
- {this.render_square(1,5)}
- {" "}
- {this.render_square(2,3)}
- {this.render_square(2,4)}
- {this.render_square(2,5)}
-
-
- {this.render_square(0,6)}
- {this.render_square(0,7)}
- {this.render_square(0,8)}
- {" "}
- {this.render_square(1,6)}
- {this.render_square(1,7)}
- {this.render_square(1,8)}
- {" "}
- {this.render_square(2,6)}
- {this.render_square(2,7)}
- {this.render_square(2,8)}
-
+ /* Even if my parent thinks I'm active because of the last move, I
+ * might not _really_ be active if I'm full. */
+ let occupied = 0;
+ props.squares.forEach(element => {
+ if (element)
+ occupied++;
+ });
-
-
+ let class_name = "mini-grid";
+ if (props.active && occupied < 9)
+ class_name += " active";
-
- {this.render_square(3,0)}
- {this.render_square(3,1)}
- {this.render_square(3,2)}
- {" "}
- {this.render_square(4,0)}
- {this.render_square(4,1)}
- {this.render_square(4,2)}
- {" "}
- {this.render_square(5,0)}
- {this.render_square(5,1)}
- {this.render_square(5,2)}
-
-
- {this.render_square(3,3)}
- {this.render_square(3,4)}
- {this.render_square(3,5)}
- {" "}
- {this.render_square(4,3)}
- {this.render_square(4,4)}
- {this.render_square(4,5)}
- {" "}
- {this.render_square(5,3)}
- {this.render_square(5,4)}
- {this.render_square(5,5)}
-
-
- {this.render_square(3,6)}
- {this.render_square(3,7)}
- {this.render_square(3,8)}
- {" "}
- {this.render_square(4,6)}
- {this.render_square(4,7)}
- {this.render_square(4,8)}
- {" "}
- {this.render_square(5,6)}
- {this.render_square(5,7)}
- {this.render_square(5,8)}
-
+ return (
+
+ {grid_square(0)}
+ {grid_square(1)}
+ {grid_square(2)}
+ {grid_square(3)}
+ {grid_square(4)}
+ {grid_square(5)}
+ {grid_square(6)}
+ {grid_square(7)}
+ {grid_square(8)}
+
+ );
+}
-
-
+class Board extends React.Component {
+ mini_grid(i) {
+ /* This mini grid is active only if both:
+ *
+ * 1. It is our turn (this.props.active === true)
+ *
+ * 2. One of the following conditions is met:
+ *
+ * a. This is this players first turn (last_two_moves[0] === null)
+ * b. This mini grid corresponds to this players last turn
+ * c. The mini grid that corresponds to the players last turn is full
+ */
+ let grid_active = false;
+ if (this.props.active) {
+ grid_active = true;
+ if (this.props.last_two_moves.length > 1) {
+ /* First index (0) gives us our last move, (that is, of the
+ * last two moves, it's the first one, so two moves ago).
+ *
+ * Second index (1) gives us the second number from that move,
+ * (that is, the index within the mini-grid that we last
+ * played).
+ */
+ const target = this.props.last_two_moves[0][1];
+ let occupied = 0;
+ this.props.squares[target].forEach(element => {
+ if (element)
+ occupied++;
+ });
+ /* If the target mini-grid isn't full then this grid is
+ * only active if it is that target. */
+ if (occupied < 9)
+ grid_active = (i === target);
+ }
+ }
-
- {this.render_square(6,0)}
- {this.render_square(6,1)}
- {this.render_square(6,2)}
- {" "}
- {this.render_square(7,0)}
- {this.render_square(7,1)}
- {this.render_square(7,2)}
- {" "}
- {this.render_square(8,0)}
- {this.render_square(8,1)}
- {this.render_square(8,2)}
-
-
- {this.render_square(6,3)}
- {this.render_square(6,4)}
- {this.render_square(6,5)}
- {" "}
- {this.render_square(7,3)}
- {this.render_square(7,4)}
- {this.render_square(7,5)}
- {" "}
- {this.render_square(8,3)}
- {this.render_square(8,4)}
- {this.render_square(8,5)}
-
-
- {this.render_square(6,6)}
- {this.render_square(6,7)}
- {this.render_square(6,8)}
- {" "}
- {this.render_square(7,6)}
- {this.render_square(7,7)}
- {this.render_square(7,8)}
- {" "}
- {this.render_square(8,6)}
- {this.render_square(8,7)}
- {this.render_square(8,8)}
-
+ /* We want to highlight each of the last two moves (both "+" and
+ * "o"). So we filter the last two moves that have a first index
+ * that matches this mini_grid and pass down their second index
+ * be highlighted.
+ */
+ const last_moves = this.props.last_two_moves.filter(move => move[0] === i)
+ .map(move => move[1]);
+
+ const squares = this.props.squares[i];
+ return (
+
this.props.onClick(i,j)}
+ />
+ );
+ }
+ render() {
+ return (
+
+
+ {this.mini_grid(0)}
+ {this.mini_grid(1)}
+ {this.mini_grid(2)}
+ {this.mini_grid(3)}
+ {this.mini_grid(4)}
+ {this.mini_grid(5)}
+ {this.mini_grid(6)}
+ {this.mini_grid(7)}
+ {this.mini_grid(8)}
+
);
}
@@ -337,9 +495,9 @@ class Game extends React.Component {
game_info: {},
player_info: {},
other_players: [],
- squares: Array(9).fill(null).map(() => Array(9).fill(null)),
- moves: 0,
- next_to_play: "+"
+ squares: [...Array(9)].map(() => Array(9).fill(null)),
+ moves: [],
+ next_to_play: "+",
};
}
@@ -375,12 +533,13 @@ class Game extends React.Component {
}
receive_move(move) {
- if (this.state.moves === 81) {
+ if (this.state.moves.length === 81) {
return;
}
const symbol = team_symbol(this.state.next_to_play);
const new_squares = this.state.squares.map(arr => arr.slice());
new_squares[move[0]][move[1]] = symbol;
+ const new_moves = [...this.state.moves, move];
let next_to_play;
if (this.state.next_to_play === "+")
next_to_play = "o";
@@ -388,7 +547,7 @@ class Game extends React.Component {
next_to_play = "+";
this.setState({
squares: new_squares,
- moves: this.state.moves + 1,
+ moves: new_moves,
next_to_play: next_to_play
});
}
@@ -416,7 +575,7 @@ class Game extends React.Component {
render() {
const state = this.state;
- const first_move = state.moves === 0;
+ const first_move = state.moves.length === 0;
const my_team = state.player_info.team;
var board_active;
@@ -481,9 +640,23 @@ class Game extends React.Component {
this.handle_click(i, j, first_move)}
/>
+ ,
+
+ {
+ scribe_glyphs.map(glyph => {
+ return (
+
+ );
+ })
+ }
];
}