Fix handling of alt move plays.
This commit is contained in:
parent
1dbe02966b
commit
c39c05969e
@ -23,6 +23,9 @@ impl Column {
|
|||||||
pub struct Tile {
|
pub struct Tile {
|
||||||
pub piece:Option<u8>,
|
pub piece:Option<u8>,
|
||||||
pub threat:[bool; 2],
|
pub threat:[bool; 2],
|
||||||
|
pub check:bool,
|
||||||
|
|
||||||
|
pub hex:Hex,
|
||||||
}
|
}
|
||||||
impl Tile {
|
impl Tile {
|
||||||
pub fn new() -> Self
|
pub fn new() -> Self
|
||||||
@ -30,6 +33,9 @@ impl Tile {
|
|||||||
Self {
|
Self {
|
||||||
piece:None,
|
piece:None,
|
||||||
threat:[false; 2],
|
threat:[false; 2],
|
||||||
|
check:false,
|
||||||
|
|
||||||
|
hex:Hex::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +87,7 @@ impl Board {
|
|||||||
(Piece::new(PIECE_DRAGON, PLAYER_DAWN), Hex::from_hex(4, 2)),
|
(Piece::new(PIECE_DRAGON, PLAYER_DAWN), Hex::from_hex(4, 2)),
|
||||||
(Piece::new(PIECE_BEHEMOTH, PLAYER_DAWN), Hex::from_hex(4, 1)),
|
(Piece::new(PIECE_BEHEMOTH, PLAYER_DAWN), Hex::from_hex(4, 1)),
|
||||||
|
|
||||||
(Piece::new(PIECE_OMEN, PLAYER_DAWN), Hex::from_hex(4, 0)),
|
(Piece::new(PIECE_SOURCE, PLAYER_DAWN), Hex::from_hex(4, 0)),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (piece, hex) in &layout {
|
for (piece, hex) in &layout {
|
||||||
|
@ -11,4 +11,4 @@ pub const PIECE_TOWER :u8 = 3;
|
|||||||
pub const PIECE_CASTLE :u8 = 4;
|
pub const PIECE_CASTLE :u8 = 4;
|
||||||
pub const PIECE_DRAGON :u8 = 5;
|
pub const PIECE_DRAGON :u8 = 5;
|
||||||
pub const PIECE_BEHEMOTH :u8 = 6;
|
pub const PIECE_BEHEMOTH :u8 = 6;
|
||||||
pub const PIECE_OMEN :u8 = 7;
|
pub const PIECE_SOURCE :u8 = 7;
|
||||||
|
@ -50,6 +50,8 @@ impl Game {
|
|||||||
|
|
||||||
if self.complete { return Err(()); }
|
if self.complete { return Err(()); }
|
||||||
|
|
||||||
|
let valid = true;
|
||||||
|
|
||||||
//
|
//
|
||||||
// TODO:
|
// TODO:
|
||||||
// - Check for piece promotion.
|
// - Check for piece promotion.
|
||||||
@ -58,85 +60,93 @@ impl Game {
|
|||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
// Move piece on board.
|
if valid {
|
||||||
if match play.source {
|
|
||||||
0 => {
|
|
||||||
if let Some(pid) = self.board.tiles[play.from as usize].piece {
|
|
||||||
if let Some(mut piece) = self.board.pieces[pid as usize] {
|
|
||||||
let mut swap = false;
|
|
||||||
|
|
||||||
if let Some(tid) = self.board.tiles[play.to as usize].piece {
|
// Move piece on board.
|
||||||
if let Some(target) = &mut self.board.pieces[tid as usize] {
|
if match play.source {
|
||||||
|
0 | 3 => {
|
||||||
|
if let Some(pid) = self.board.tiles[play.from as usize].piece {
|
||||||
|
if let Some(mut piece) = self.board.pieces[pid as usize] {
|
||||||
|
let mut swap = false;
|
||||||
|
|
||||||
// Check for piece swap.
|
if let Some(tid) = self.board.tiles[play.to as usize].piece {
|
||||||
if piece.player == target.player {
|
if let Some(target) = &mut self.board.pieces[tid as usize] {
|
||||||
swap = true;
|
|
||||||
target.tile = play.from;
|
|
||||||
|
|
||||||
// Check for target promotion.
|
// Check for piece swap.
|
||||||
let hex = Hex::from_tile(play.from);
|
if piece.player == target.player {
|
||||||
if !target.promoted && target.has_promotion() && Hex::is_back(hex.x, hex.y, target.player) {
|
swap = true;
|
||||||
target.promoted = true;
|
target.tile = play.from;
|
||||||
|
|
||||||
|
// Check for target promotion.
|
||||||
|
let hex = Hex::from_tile(play.from);
|
||||||
|
if !target.promoted && target.has_promotion() && Hex::is_back(hex.x, hex.y, target.player) {
|
||||||
|
target.promoted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add captured piece to pool.
|
||||||
|
else {
|
||||||
|
self.pool[piece.player as usize][target.class as usize] += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add captured piece to pool.
|
// Destroy piece if captured.
|
||||||
else {
|
if !swap { self.board.pieces[tid as usize] = None; }
|
||||||
self.pool[piece.player as usize][target.class as usize] += 1;
|
}
|
||||||
|
|
||||||
|
// Set tile/piece associations.
|
||||||
|
if swap {
|
||||||
|
self.board.tiles[play.from as usize].piece = self.board.tiles[play.to as usize].piece;
|
||||||
|
} else {
|
||||||
|
self.board.tiles[play.from as usize].piece = None;
|
||||||
|
}
|
||||||
|
self.board.tiles[play.to as usize].piece = Some(pid);
|
||||||
|
piece.tile = play.to;
|
||||||
|
|
||||||
|
self.board.pieces[pid as usize] = Some(piece);
|
||||||
|
|
||||||
|
// Check for piece promotion.
|
||||||
|
let hex = Hex::from_tile(play.to);
|
||||||
|
if !piece.promoted && piece.has_promotion() && Hex::is_back(hex.x, hex.y, piece.player) {
|
||||||
|
if let Some(piece) = &mut self.board.pieces[pid as usize] {
|
||||||
|
piece.promoted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy piece if captured.
|
self.turn += 1;
|
||||||
if !swap { self.board.pieces[tid as usize] = None; }
|
true
|
||||||
}
|
} else { false }
|
||||||
|
} else { false }
|
||||||
// Set tile/piece associations.
|
}
|
||||||
if swap {
|
|
||||||
self.board.tiles[play.from as usize].piece = self.board.tiles[play.to as usize].piece;
|
// Place piece from pool.
|
||||||
} else {
|
1 => {
|
||||||
self.board.tiles[play.from as usize].piece = None;
|
if self.pool[player as usize][play.from as usize] > 0 && self.board.tiles[play.to as usize].piece.is_none() {
|
||||||
}
|
self.pool[player as usize][play.from as usize] -= 1;
|
||||||
self.board.tiles[play.to as usize].piece = Some(pid);
|
let piece = Piece::new(play.from, player);
|
||||||
piece.tile = play.to;
|
self.board.set_piece(piece, play.to);
|
||||||
|
|
||||||
self.board.pieces[pid as usize] = Some(piece);
|
|
||||||
|
|
||||||
// Check for piece promotion.
|
|
||||||
let hex = Hex::from_tile(play.to);
|
|
||||||
if !piece.promoted && piece.has_promotion() && Hex::is_back(hex.x, hex.y, piece.player) {
|
|
||||||
if let Some(piece) = &mut self.board.pieces[pid as usize] {
|
|
||||||
piece.promoted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.turn += 1;
|
self.turn += 1;
|
||||||
true
|
true
|
||||||
} else { false }
|
} else { false }
|
||||||
} else { false }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Place piece from pool.
|
|
||||||
1 => {
|
|
||||||
if self.pool[player as usize][play.from as usize] > 0 && self.board.tiles[play.to as usize].piece.is_none() {
|
|
||||||
self.pool[player as usize][play.from as usize] -= 1;
|
|
||||||
let piece = Piece::new(play.from, player);
|
|
||||||
self.board.set_piece(piece, play.to);
|
|
||||||
|
|
||||||
self.turn += 1;
|
// Player retired.
|
||||||
|
2 => {
|
||||||
|
self.complete = true;
|
||||||
true
|
true
|
||||||
} else { false }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Player retired.
|
_ => false,
|
||||||
2 => {
|
} {
|
||||||
self.complete = true;
|
self.history.push(*play);
|
||||||
true
|
Ok(())
|
||||||
}
|
} else { Err(()) }
|
||||||
|
|
||||||
_ => false,
|
|
||||||
} {
|
|
||||||
self.history.push(*play);
|
|
||||||
Ok(())
|
|
||||||
} else { Err(()) }
|
} else { Err(()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_moves(_piece:&Piece) -> Vec<Play>
|
||||||
|
{
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ pub const PIECES :[PieceClass; PIECES_COUNT] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
PieceClass {
|
PieceClass {
|
||||||
name: "Omen",
|
name: "Source",
|
||||||
moves: MoveSet {
|
moves: MoveSet {
|
||||||
direction:0,
|
direction:0,
|
||||||
stride:0,
|
stride:0,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const ROWS :[u8; 10] = [ 0, 5, 11, 18, 26, 35, 43, 50, 56, 61 ];
|
const ROWS :[u8; 10] = [ 0, 5, 11, 18, 26, 35, 43, 50, 56, 61 ];
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct Hex {
|
pub struct Hex {
|
||||||
pub x:u8,
|
pub x:u8,
|
||||||
pub y:u8,
|
pub y:u8,
|
||||||
|
@ -211,7 +211,7 @@ async fn main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let about_path = std::path::Path::new("www/about");
|
let about_path = std::path::Path::new("www/pages/about");
|
||||||
for doc in [
|
for doc in [
|
||||||
"main",
|
"main",
|
||||||
] {
|
] {
|
||||||
@ -220,7 +220,7 @@ async fn main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let guide_path = std::path::Path::new("www/guide");
|
let guide_path = std::path::Path::new("www/pages/guide");
|
||||||
for doc in [
|
for doc in [
|
||||||
"game",
|
"game",
|
||||||
"pieces",
|
"pieces",
|
||||||
@ -230,7 +230,7 @@ async fn main()
|
|||||||
println!("error: failed to load: {}", doc);
|
println!("error: failed to load: {}", doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut tcp_server = TcpServer::new();
|
let mut tcp_server = TcpServer::new();
|
||||||
match tcp_server.bind("127.0.0.1:38611").await {
|
match tcp_server.bind("127.0.0.1:38611").await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
|
@ -36,9 +36,9 @@ impl Packet for PacketGamePlay {
|
|||||||
result.turn = unpack_u16(data, index);
|
result.turn = unpack_u16(data, index);
|
||||||
|
|
||||||
let play = unpack_u16(data, index) as u32;
|
let play = unpack_u16(data, index) as u32;
|
||||||
result.play.source = (play & mask(1, 0)) as u8;
|
result.play.source = (play & mask(4, 0)) as u8;
|
||||||
result.play.from = ((play & mask(6, 1)) >> 1) as u8;
|
result.play.from = ((play & mask(6, 4)) >> 4) as u8;
|
||||||
result.play.to = ((play & mask(6, 7)) >> 7) as u8;
|
result.play.to = ((play & mask(6, 10)) >> 10) as u8;
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
@ -151,11 +151,10 @@ GAME.MovementTile = class {
|
|||||||
};
|
};
|
||||||
|
|
||||||
GAME.Play = class {
|
GAME.Play = class {
|
||||||
constructor(source, from, to, alt=false) {
|
constructor(source, from, to) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.from = from;
|
this.from = from;
|
||||||
this.to = to;
|
this.to = to;
|
||||||
this.alt = alt;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -347,7 +346,8 @@ GAME.Game = class {
|
|||||||
|
|
||||||
// Move piece on board.
|
// Move piece on board.
|
||||||
switch(play.source) {
|
switch(play.source) {
|
||||||
case 0: {
|
case 0:
|
||||||
|
case 3: {
|
||||||
let piece_id = this.board.tiles[play.from].piece;
|
let piece_id = this.board.tiles[play.from].piece;
|
||||||
let piece = this.board.pieces[piece_id];
|
let piece = this.board.pieces[piece_id];
|
||||||
piece.tile = play.to;
|
piece.tile = play.to;
|
||||||
@ -387,7 +387,7 @@ GAME.Game = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle alt moves.
|
// Handle alt moves.
|
||||||
if(play.alt) {
|
if(play.source == 3) {
|
||||||
switch(piece.piece) {
|
switch(piece.piece) {
|
||||||
case GAME.Const.PieceId.Knight: {
|
case GAME.Const.PieceId.Knight: {
|
||||||
piece.promoted = false;
|
piece.promoted = false;
|
||||||
|
@ -241,8 +241,13 @@ const INTERFACE = {
|
|||||||
// Handle player action.
|
// Handle player action.
|
||||||
switch(result) {
|
switch(result) {
|
||||||
case 1: {
|
case 1: {
|
||||||
|
let source = INTERFACE_DATA.select.source;
|
||||||
|
if(source == 0 && INTERFACE_DATA.alt_mode) {
|
||||||
|
source = 3;
|
||||||
|
}
|
||||||
|
|
||||||
let play = new GAME.Play(
|
let play = new GAME.Play(
|
||||||
INTERFACE_DATA.select.source,
|
source,
|
||||||
INTERFACE_DATA.select.tile,
|
INTERFACE_DATA.select.tile,
|
||||||
INTERFACE_DATA.hover.tile,
|
INTERFACE_DATA.hover.tile,
|
||||||
INTERFACE_DATA.alt_mode
|
INTERFACE_DATA.alt_mode
|
||||||
@ -386,7 +391,7 @@ const INTERFACE = {
|
|||||||
let draw_piece = true;
|
let draw_piece = true;
|
||||||
if(INTERFACE_DATA.Animate.play !== null) {
|
if(INTERFACE_DATA.Animate.play !== null) {
|
||||||
let play = INTERFACE_DATA.Animate.play;
|
let play = INTERFACE_DATA.Animate.play;
|
||||||
draw_piece = draw_piece && !(play.source == 0 && (play.from == i || play.to == i));
|
draw_piece = draw_piece && !((play.source == 0 || play.source == 3) && (play.from == i || play.to == i));
|
||||||
draw_piece = draw_piece && !(play.source == 1 && play.to == i);
|
draw_piece = draw_piece && !(play.source == 1 && play.to == i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +430,7 @@ const INTERFACE = {
|
|||||||
case 1: ctx.fillStyle = INTERFACE.Color.TileLight; break;
|
case 1: ctx.fillStyle = INTERFACE.Color.TileLight; break;
|
||||||
case 2: ctx.fillStyle = INTERFACE.Color.TileDark; break;
|
case 2: ctx.fillStyle = INTERFACE.Color.TileDark; break;
|
||||||
}
|
}
|
||||||
if(GAME_DATA.turn > 0 && play.source < 2 && (play.to == i || (play.source == 0 && play.from == i))) {
|
if(GAME_DATA.turn > 0 && (play.source < 2 || play.source == 3) && (play.to == i || ((play.source == 0 || play.source == 3) && play.from == i))) {
|
||||||
ctx.fillStyle = INTERFACE.Color.HintPlay;
|
ctx.fillStyle = INTERFACE.Color.HintPlay;
|
||||||
} else if(GAME_DATA.state.check != 0 && piece !== null && piece.piece == GAME.Const.PieceId.Source && piece.player == (GAME_DATA.turn & 1)) {
|
} else if(GAME_DATA.state.check != 0 && piece !== null && piece.piece == GAME.Const.PieceId.Source && piece.player == (GAME_DATA.turn & 1)) {
|
||||||
ctx.fillStyle = INTERFACE.Color.HintCheck;
|
ctx.fillStyle = INTERFACE.Color.HintCheck;
|
||||||
@ -655,7 +660,8 @@ const INTERFACE = {
|
|||||||
let from_y = 0;
|
let from_y = 0;
|
||||||
switch(play.source) {
|
switch(play.source) {
|
||||||
// Lerp between board positions.
|
// Lerp between board positions.
|
||||||
case 0: {
|
case 0:
|
||||||
|
case 3: {
|
||||||
let coord_from = HEX.tile_to_hex(play.from);
|
let coord_from = HEX.tile_to_hex(play.from);
|
||||||
if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) {
|
if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) {
|
||||||
coord_from.x = 8 - coord_from.x;
|
coord_from.x = 8 - coord_from.x;
|
||||||
@ -1100,7 +1106,8 @@ const INTERFACE = {
|
|||||||
let valid = true;
|
let valid = true;
|
||||||
|
|
||||||
switch(play.source) {
|
switch(play.source) {
|
||||||
case 0: {
|
case 0:
|
||||||
|
case 3: {
|
||||||
let piece_id = GAME_DATA.board.tiles[play.from].piece;
|
let piece_id = GAME_DATA.board.tiles[play.from].piece;
|
||||||
let piece = GAME_DATA.board.pieces[piece_id];
|
let piece = GAME_DATA.board.pieces[piece_id];
|
||||||
valid = piece.player == (GAME_DATA.turn & 1);
|
valid = piece.player == (GAME_DATA.turn & 1);
|
||||||
@ -1134,7 +1141,7 @@ const INTERFACE = {
|
|||||||
|
|
||||||
// Send action to server for validation.
|
// Send action to server for validation.
|
||||||
case INTERFACE.Mode.Player: {
|
case INTERFACE.Mode.Player: {
|
||||||
let move_data = play.source | (play.from << 1) | (play.to << 7);
|
let move_data = play.source | (play.from << 4) | (play.to << 10);
|
||||||
MESSAGE_COMPOSE([
|
MESSAGE_COMPOSE([
|
||||||
PACK.u16(OpCode.GamePlay),
|
PACK.u16(OpCode.GamePlay),
|
||||||
PACK.u16(0),
|
PACK.u16(0),
|
||||||
@ -1211,26 +1218,32 @@ const INTERFACE = {
|
|||||||
let target = null;
|
let target = null;
|
||||||
while(INTERFACE_DATA.replay_turn < turn) {
|
while(INTERFACE_DATA.replay_turn < turn) {
|
||||||
play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn];
|
play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn];
|
||||||
if(play.source < 2) {
|
switch(play.source) {
|
||||||
if(play.source == 0) {
|
case 0:
|
||||||
let piece_id = GAME_DATA.board.tiles[play.from].piece;
|
case 1:
|
||||||
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id].clone(); }
|
case 3: {
|
||||||
|
if(play.source == 0 || play.source == 3) {
|
||||||
|
let piece_id = GAME_DATA.board.tiles[play.from].piece;
|
||||||
|
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id].clone(); }
|
||||||
|
|
||||||
piece_id = GAME_DATA.board.tiles[play.to].piece;
|
piece_id = GAME_DATA.board.tiles[play.to].piece;
|
||||||
if(piece_id !== null) { target = GAME_DATA.board.pieces[piece_id].clone(); }
|
if(piece_id !== null) { target = GAME_DATA.board.pieces[piece_id].clone(); }
|
||||||
else { target = null; }
|
else { target = null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
GAME_DATA.process(play);
|
||||||
|
|
||||||
|
if(play.source == 1) {
|
||||||
|
let piece_id = GAME_DATA.board.tiles[play.to].piece;
|
||||||
|
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id].clone(); }
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
GAME_DATA.process(play);
|
||||||
|
play = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
GAME_DATA.process(play);
|
|
||||||
|
|
||||||
if(play.source == 1) {
|
|
||||||
let piece_id = GAME_DATA.board.tiles[play.to].piece;
|
|
||||||
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id].clone(); }
|
|
||||||
target = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
GAME_DATA.process(play);
|
|
||||||
play = null;
|
|
||||||
}
|
}
|
||||||
INTERFACE_DATA.replay_turn++;
|
INTERFACE_DATA.replay_turn++;
|
||||||
}
|
}
|
||||||
|
@ -557,6 +557,17 @@ const SCENES = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Extras:class{
|
||||||
|
constructor() { }
|
||||||
|
load() {
|
||||||
|
UI.mainmenu("extras");
|
||||||
|
UI.mainnav([], []);
|
||||||
|
|
||||||
|
history.pushState(null, "Dzura - About", "/extras/");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
Game:class{
|
Game:class{
|
||||||
constructor() {
|
constructor() {
|
||||||
this.game = null;
|
this.game = null;
|
||||||
|
@ -165,7 +165,7 @@ const UI = {
|
|||||||
top.push(UI.button(LANG("guide"), () => { LOAD(SCENES.Guide); }, page == "guide"));
|
top.push(UI.button(LANG("guide"), () => { LOAD(SCENES.Guide); }, page == "guide"));
|
||||||
top.push(UI.button(LANG("about"), () => { LOAD(SCENES.About); }, page == "about"));
|
top.push(UI.button(LANG("about"), () => { LOAD(SCENES.About); }, page == "about"));
|
||||||
|
|
||||||
bottom.push(UI.button(LANG("extras"), () => { }));
|
bottom.push(UI.button(LANG("extras"), () => { LOAD(SCENES.Extras) }, page == "extras"));
|
||||||
|
|
||||||
if(sessionStorage.getItem("auth") !== null) {
|
if(sessionStorage.getItem("auth") !== null) {
|
||||||
bottom.push(UI.button(LANG("account"), () => { }));
|
bottom.push(UI.button(LANG("account"), () => { }));
|
||||||
|
@ -11,6 +11,17 @@ Dzura is a work of [Project Kirisame](https://kirisame.com).
|
|||||||
© 2024 Yukiri Corporation
|
© 2024 Yukiri Corporation
|
||||||
|
|
||||||
|
|
||||||
|
## Guidelines
|
||||||
|
|
||||||
|
1. Be polite, respectful, and honorable.
|
||||||
|
|
||||||
|
### Bots
|
||||||
|
|
||||||
|
1. Bots are generally permitted, provided they abide by these rules.
|
||||||
|
2. While not manidatory, we prefer that bots be labeled as such (e.g. in their handles).
|
||||||
|
3. Bots should not initiate games or send challenges.
|
||||||
|
|
||||||
|
|
||||||
## User Privacy
|
## User Privacy
|
||||||
|
|
||||||
This website does not collect any information beyond that used to implement user accounts and gameplay.
|
This website does not collect any information beyond that used to implement user accounts and gameplay.
|
Loading…
x
Reference in New Issue
Block a user