online multiplayer chess game (note server currently down)
-rw-r--r--Debug.gd2
-rw-r--r--Grid.gd4
-rw-r--r--SanParse/Move.gd6
-rw-r--r--SanParse/SanParse.gd9
-rw-r--r--SanParse/test.gd109
-rw-r--r--Utils.gd2
-rw-r--r--networking/PacketHandler.gd54
-rw-r--r--pieces/Pawn.gd35
-rw-r--r--pieces/Piece.gd2
-rw-r--r--test.gd11
-rw-r--r--ui/StartMenu.tscn2
11 files changed, 59 insertions, 177 deletions
diff --git a/Debug.gd b/Debug.gd
index 8ea2e04..1742653 100644
--- a/Debug.gd
+++ b/Debug.gd
@@ -15,7 +15,7 @@ static func is_debug() -> bool:
var args := Utils.get_args()
if "debug" in args:
return bool(args.debug)
- return false or OS.is_debug_build()
+ return OS.is_debug_build()
func _ready() -> void:
diff --git a/Grid.gd b/Grid.gd
index 6d2b001..5026c5c 100644
--- a/Grid.gd
+++ b/Grid.gd
@@ -77,7 +77,7 @@ static func print_matrix_pretty(mat: Array) -> void: # print the matrix
print(topper_header) # print the top border
else:
print(middle_header) # print the middle border
- var row := "%s%s %s " % [ender, 8 - j, ender] # init the string
+ var row := "%s %s%s" % [ender.strip_edges(), 8 - j, ender] # init the string
for i in range(8): # for each column
var c: Piece = r[i] # get the column
row += "%s%s" % [c.mininame, ender] if c else " " + ender # add the piece
@@ -339,7 +339,7 @@ func handle_move(position: Vector2) -> void:
var en_passant_data = pawn.enpassant[i]
if en_passant_data[0] == position:
# send some packet
- var mov = Move.new(SanParser.PAWN, [pawn.real_position, position])
+ var mov = Move.new(SanParser.PAWN, [pawn.real_position, position], true)
Globals.network.send_mov(mov)
return
elif check_promote(pawn, position):
diff --git a/SanParse/Move.gd b/SanParse/Move.gd
index 82076ea..5bb35b1 100644
--- a/SanParse/Move.gd
+++ b/SanParse/Move.gd
@@ -1,7 +1,6 @@
class_name Move
extends Resource
-enum CASTLETYPES { NONE, QUEEN_SIDE, KING_SIDE }
enum CHECKTYPES { NONE, CHECK, CHECKMATE }
var generated_from := ""
var piece := -1
@@ -19,7 +18,7 @@ func _init(newpiece: int, newmove, capture := false) -> void:
static func castle_type(type: String) -> int:
- return CASTLETYPES.QUEEN_SIDE if type == "O-O-O" else CASTLETYPES.KING_SIDE
+ return MoveKind.CASTLETYPES.QUEEN_SIDE if type == "O-O-O" else MoveKind.CASTLETYPES.KING_SIDE
func set_check_type(type: String) -> void:
@@ -103,6 +102,7 @@ func long_helper(vec: Vector2, attack: bool, move: bool, touch: Vector2):
class MoveKind:
extends Resource
+ enum CASTLETYPES { NONE, QUEEN_SIDE, KING_SIDE }
enum { NONE, NORMAL, CASTLE }
var type := 0
var data # string OR array
@@ -118,4 +118,4 @@ class MoveKind:
assert(false)
func to_str() -> String:
- return "O-O-O" if data == CASTLETYPES.QUEENSIDE else "O-O"
+ return "O-O-O" if data == CASTLETYPES.QUEEN_SIDE else "O-O"
diff --git a/SanParse/SanParse.gd b/SanParse/SanParse.gd
index 3669672..9a1f130 100644
--- a/SanParse/SanParse.gd
+++ b/SanParse/SanParse.gd
@@ -17,6 +17,7 @@ var regexs := {
"specific_row_piece_capture": compile("^([KQBNR])([0-9])x([a-h])([1-8])"),
"long_piece_capture": compile("^([KQBNR])([a-h])([0-9])x([a-h])([1-8])"),
"pawn_promotion": compile("^([a-h])([1-8])=?([KQBNR])"),
+ "long_pawn_promotion": compile("^([a-h])([1-8])([a-h])([1-8])=?([KQBNR])"),
"castling": compile("^(O-O-O|O-O)"),
}
@@ -144,6 +145,14 @@ func regexmatch(san: String) -> Move:
mov.set_check_type(cap[4])
return mov
+ re = regexs.long_pawn_promotion.search(san)
+ if re:
+ var cap = re.strings
+ var mov = Move.new(PAWN, [pos(cap[1], cap[2]), pos(cap[3], cap[4])], true)
+ mov.promotion = from_str(cap[5])
+ mov.set_check_type(cap[6])
+ return mov
+
re = regexs.castling.search(san)
if re:
var cap = re.strings
diff --git a/SanParse/test.gd b/SanParse/test.gd
deleted file mode 100644
index 137d7b9..0000000
--- a/SanParse/test.gd
+++ /dev/null
@@ -1,109 +0,0 @@
-extends Node
-
-
-class TestSan:
- extends SanParser
-
- func assert_castle(string: String, s):
- var m = parse(string)
- assert(m.move_kind.type == Move.MoveKind.CASTLE)
- assert(m.move_kind.data == s)
- assert(m.piece == KING)
- assert(m.promotion == -1)
- assert(m.check_type == Move.CHECKTYPES.NONE)
- assert(m.is_capture == false)
-
- func assert_move(mv: String, start: Vector2, dest: Vector2, piece: int) -> void:
- assert_all(parse(mv), PoolVector2Array([start, dest]), piece, false)
-
- func assert_capture(mv: String, start: Vector2, dest: Vector2, piece: int) -> void:
- assert_all(parse(mv), PoolVector2Array([start, dest]), piece, true)
-
- func assert_all(mv: Move, vectors: PoolVector2Array, piece: int, capture: bool, promote = -1) -> void:
- assert(mv.move_kind.type == Move.MoveKind.NORMAL)
- assert([mv.move_kind.data == vectors, mv.piece == piece, mv.is_capture == capture].min())
- if promote != -1:
- assert(mv.promotion == promote)
-
- func test_algebraic_conversion():
- assert(Utils.from_algebraic(Utils.to_algebraic(Vector2.ZERO)) == Vector2.ZERO)
- assert(Utils.from_algebraic(Utils.to_algebraic(Vector2.ONE)) == Vector2.ONE)
- assert(pos("a", "9") == Utils.from_algebraic("a9"))
- assert(Utils.col_pos("h") == 7)
- assert(Utils.row_pos("1") == 7)
-
- func test_castle_short():
- assert_castle("O-O", Move.CASTLETYPES.KING_SIDE)
-
- func test_castle_long():
- assert_castle("O-O-O", Move.CASTLETYPES.QUEEN_SIDE)
-
- func test_pawn():
- assert_move("e4", UNKNOWN_POS, Vector2(4, 4), PAWN)
-
- func test_pawn_long():
- assert_move("e2e4", Vector2(4, 6), Vector2(4, 4), PAWN)
-
- func test_piece():
- assert_move("Qe4", UNKNOWN_POS, Vector2(4, 4), QUEEN)
-
- func test_piece_file():
- assert_move("Qbe4", Vector2(1, -1), Vector2(4, 4), QUEEN)
-
- func test_piece_rank():
- assert_move("Q1e4", Vector2(-1, 7), Vector2(4, 4), QUEEN)
-
- func test_piece_long():
- assert_move("Qb1e4", Vector2(1, 7), Vector2(4, 4), QUEEN)
-
- func test_pawn_capture():
- assert_capture("exd4", Vector2(4, -1), Vector2(3, 4), PAWN)
-
- func test_pawn_capture_promotion():
- assert_all(parse("exd8=Q"), PoolVector2Array([Vector2(4, -1), Vector2(3, 0)]), PAWN, true, QUEEN)
-
- func test_pawn_capture_long():
- assert_capture("e3xd4", Vector2(4, 5), Vector2(3, 4), PAWN)
-
- func test_piece_capture():
- assert_capture("R1xh3", Vector2(-1, 7), Vector2(7, 5), ROOK)
-
- func test_piece_capture_file():
- assert_capture("Rexh3", Vector2(4, -1), Vector2(7, 5), ROOK)
-
- func test_piece_capture_long():
- assert_capture("Re3xh3", Vector2(4, 5), Vector2(7, 5), ROOK)
-
- func test_pawn_promotion():
- assert_all(parse("d8=Q"), PoolVector2Array([UNKNOWN_POS, Vector2(3, 0)]), PAWN, QUEEN)
-
- func test_compile():
- var s = Move.new(PAWN, [Vector2(4, -1), Vector2(3, 0)])
- s.promotion = QUEEN
- s.check_type = Move.CHECKTYPES.CHECK
- s.is_capture = true
- var result = s.compile()
- assert(result == "exd8=Q+")
-
- func _init():
- test_algebraic_conversion()
- test_castle_short()
- test_castle_long()
- test_pawn()
- test_pawn_long()
- test_piece()
- test_piece_file()
- test_piece_rank()
- test_piece_long()
- test_pawn_capture()
- test_pawn_capture_promotion()
- test_pawn_capture_long()
- test_piece_capture()
- test_piece_capture_file()
- test_piece_capture_long()
- test_pawn_promotion()
- test_compile()
-
-
-func _ready():
- TestSan.new()
diff --git a/Utils.gd b/Utils.gd
index 98e7147..9b6d7b2 100644
--- a/Utils.gd
+++ b/Utils.gd
@@ -50,7 +50,7 @@ func get_fen() -> String:
var enpassants := ""
for pawn in Globals.pawns:
- if pawn.twostepfirstmove and pawn.just_set:
+ if pawn.just_double_stepped and pawn.just_set:
enpassants += Utils.to_algebraic(pawn.real_position + (Vector2.DOWN * pawn.whiteint))
return (
"%s %s %s %s %s %s"
diff --git a/networking/PacketHandler.gd b/networking/PacketHandler.gd
index eb96f08..28ee0e8 100644
--- a/networking/PacketHandler.gd
+++ b/networking/PacketHandler.gd
@@ -98,65 +98,43 @@ func _start_game() -> void:
func _on_data(data: String) -> void:
Globals.add_turn()
Log.debug([data, " recieved"])
- Utils.add_move(data)
+ var san_to_add := data
var mov = SanParse.parse(data)
match mov.move_kind.type:
Move.MoveKind.CASTLE:
- var side = 7 if Globals.turn else 0
+ var side = 0 if Globals.turn else 7
var rook: Rook
var rook_goto: Vector2
var kingpos = Vector2(4, side)
var king: King = Piece.at_pos(kingpos)
var king_goto: Vector2
match mov.move_kind.data:
- Move.CASTLETYPES.KING_SIDE:
+ Move.MoveKind.CASTLETYPES.KING_SIDE:
rook = Piece.at_pos(Vector2(7, side))
rook_goto = Vector2(5, side)
king_goto = Vector2(6, side)
- Move.CASTLETYPES.QUEEN_SIDE:
+ Move.MoveKind.CASTLETYPES.QUEEN_SIDE:
rook = Piece.at_pos(Vector2(0, side))
rook_goto = Vector2(3, side)
king_goto = Vector2(2, side)
- _:
- Log.error("Invalid castle type")
- return
rook.moveto(rook_goto)
king.castle(king_goto)
Move.MoveKind.NORMAL:
- # this needs to handle enpassant, taking, and promotion.
+ # this handles promotion, taking, enpassant, and moves.
mov.make_long()
var positions = mov.move_kind.data
- if mov.promotion != -1:
- var promote_to = SanParse.from_str(mov.promotion)
+ if mov.promotion != -1: # promotion part
+ Globals.grid.print_matrix_pretty(Globals.grid.matrix)
+ var promote_to = Utils.to_str(mov.promotion)
Piece.at_pos(positions[0]).promote_to(promote_to, mov.is_capture, positions[1])
- elif mov.is_capture:
- Piece.at_pos(positions[0]).take(Piece.at_pos(positions[1]))
-
- elif not Piece.at_pos(positions[1]) and mov.piece == SanParser.PAWN: # if not positions[1] and piece is pawn: enpassant!
- var pawn: Pawn = Piece.at_pos(positions[0])
- pawn.passant(positions[1])
+ elif mov.is_capture: # taking part
+ if Piece.at_pos(positions[1]):
+ Piece.at_pos(positions[0]).take(Piece.at_pos(positions[1]))
+ elif mov.piece == SanParser.PAWN: # enpassant part
+ var pawn: Pawn = Piece.at_pos(positions[0])
+ pawn.passant(positions[1])
+ san_to_add += " e.p."
else: # a very normal move
Piece.at_pos(positions[0]).moveto(positions[1])
-
- # Events.emit_signal("data_recieved")
- # match data["type"]:
- # Network.MOVEHEADERS.passant:
- # # en passant
- # var end_pos := dict2vec(data["positions"][1])
- # var start_piece := Piece.at_pos(dict2vec(data["positions"][0]))
- # Piece.at_pos(dict2vec(data["positions"][2])).took() # kill the unfortunate
- # start_piece.passant(end_pos)
- # Network.MOVEHEADERS.move:
- # var start_piece := Piece.at_pos(dict2vec(data["positions"][0]))
- # var end_pos := dict2vec(data["positions"][1])
- # var end_piece := Piece.at_pos(end_pos)
- # if end_piece != null:
- # start_piece.take(end_piece)
- # else:
- # start_piece.moveto(end_pos)
-
- # Network.MOVEHEADERS.promote:
- # var dict_data: Dictionary = data["positions"] # positions is a dict for readability sometimes
- # _:
- # Log.err("Wtf")
+ Utils.add_move(san_to_add)
diff --git a/pieces/Pawn.gd b/pieces/Pawn.gd
index 93efb31..f17bca3 100644
--- a/pieces/Pawn.gd
+++ b/pieces/Pawn.gd
@@ -3,7 +3,7 @@ class_name Pawn, "res://assets/pieces/california/wP.png"
const promotables := "QNRB"
-var twostepfirstmove := false
+var just_double_stepped := false
var just_set := false
var enpassant: Array = []
@@ -23,7 +23,9 @@ func _ready() -> void:
for i in range(0, 4): # add 3 sprites
var newsprite: Node2D = load("res://ui/ClickableSprite.tscn").instance()
newsprite.position = (sprite.position + Vector2(0, (i * Globals.grid.piece_size.y) * whiteint))
- newsprite.get_node("Sprite").texture = load("%s%s%s.png" % [Globals.grid.ASSETS_PATH, team.to_lower(), promotables[i]])
+ newsprite.get_node("Sprite").texture = load(
+ "%s%s%s.png" % [Globals.grid.ASSETS_PATH, team.to_lower(), promotables[i]]
+ )
newsprite.name = promotables[i]
newsprite.connect("clicked", self, "handle_sprite_input_event", [newsprite.name])
newsprite.z_index = 5 # its not a texturebutton so i can use this
@@ -41,12 +43,12 @@ func _exit_tree() -> void:
func moveto(position: Vector2, real := true) -> void:
# check if 2 step
if real:
- if !twostepfirstmove and !has_moved:
+ if !just_double_stepped and !has_moved:
if white and real_position.y - position.y == 2:
- twostepfirstmove = true
+ just_double_stepped = true
just_set = true
if !white and position.y - real_position.y == 2:
- twostepfirstmove = true
+ just_double_stepped = true
just_set = true
.moveto(position, real)
if real:
@@ -76,16 +78,16 @@ static func can_promote(position: Vector2) -> bool:
func passant(position: Vector2) -> void:
- var to_take = position + Vector2(-1, -1) * whiteint
- if !at_pos(to_take):
- if at_pos(to_take + Vector2(2, 0)):
- to_take += Vector2(2, 0)
- if at_pos(position):
- at_pos(position).took()
+ var to_take = position + Vector2(0, whiteint)
+ at_pos(to_take).took()
enpassant.resize(0)
moveto(position)
+func valid_to_passant_take(piece) -> bool:
+ return !piece or !Utils.is_pawn(piece) or piece.white != white or !piece.just_double_stepped
+
+
func get_attacks(check_spots_check := true) -> PoolVector2Array:
var points := [Vector2.UP + Vector2.RIGHT, Vector2.UP + Vector2.LEFT]
var moves: PoolVector2Array = []
@@ -99,7 +101,7 @@ func get_attacks(check_spots_check := true) -> PoolVector2Array:
continue
if at_pos(point) != null and at_pos(point).white != white:
moves.append(point)
- en_passant()
+ en_passant() # for the fen
return moves
@@ -114,7 +116,7 @@ func en_passant(turncheck := true, check_spots_check := true) -> Array: # in pa
continue
if turncheck and white != Globals.turn:
continue
- if !spot.twostepfirstmove:
+ if !spot.just_double_stepped:
continue
if check_spots_check and checkcheck(i):
continue
@@ -145,7 +147,8 @@ func promote_to(promote_to: String, is_capture: bool, position: Vector2):
func handle_sprite_input_event(promote_to: String) -> void:
darken.hide()
- var mov = Move.new(SanParser.PAWN, [real_position, promoteposition])
+ var is_cap = at_pos(promoteposition) != null
+ var mov = Move.new(SanParser.PAWN, [real_position, promoteposition], is_cap)
mov.promotion = SanParse.from_str(promote_to)
Globals.network.send_mov(mov)
@@ -168,8 +171,8 @@ func _on_turn_over() -> void:
if just_set:
just_set = false
return
- if twostepfirstmove:
- twostepfirstmove = false
+ if just_double_stepped:
+ just_double_stepped = false
func _just_before_turn_over() -> void:
diff --git a/pieces/Piece.gd b/pieces/Piece.gd
index 0c52252..07b4b4a 100644
--- a/pieces/Piece.gd
+++ b/pieces/Piece.gd
@@ -119,7 +119,7 @@ func traverse(arr: PoolVector2Array = [], no_enemys := false, check_spots_check
static func at_pos(vector: Vector2) -> Piece:
- if is_instance_valid(Globals.grid):
+ if is_on_board(vector):
return Globals.grid.matrix[vector.y][vector.x]
return null
diff --git a/test.gd b/test.gd
index 87552e8..3e08022 100644
--- a/test.gd
+++ b/test.gd
@@ -9,7 +9,7 @@ class TestSan:
assert(m.move_kind.type == Move.MoveKind.CASTLE)
assert(m.move_kind.data == s)
assert(m.piece == KING)
- assert(m.promotion == 0)
+ assert(m.promotion == -1)
assert(m.check_type == Move.CHECKTYPES.NONE)
assert(m.is_capture == false)
@@ -33,10 +33,10 @@ class TestSan:
assert(Utils.row_pos("1") == 7)
func test_castle_short():
- assert_castle("O-O", Move.CASTLETYPES.KING_SIDE)
+ assert_castle("O-O", Move.MoveKind.CASTLETYPES.KING_SIDE)
func test_castle_long():
- assert_castle("O-O-O", Move.CASTLETYPES.QUEEN_SIDE)
+ assert_castle("O-O-O", Move.MoveKind.CASTLETYPES.QUEEN_SIDE)
func test_pawn():
assert_move("e4", UNKNOWN_POS, Vector2(4, 4), PAWN)
@@ -84,7 +84,7 @@ class TestSan:
s.is_capture = true
var result = s.compile()
assert(result == "exd8=Q+")
- assert(Move.parse("e4").compile() == "e4")
+ assert((SanParse.parse("e4").compile()) == "e4")
func _init():
test_algebraic_conversion()
@@ -107,4 +107,5 @@ class TestSan:
func _ready():
- TestSan.new()
+ if Debug.is_debug():
+ TestSan.new()
diff --git a/ui/StartMenu.tscn b/ui/StartMenu.tscn
index 2d8a117..80304ee 100644
--- a/ui/StartMenu.tscn
+++ b/ui/StartMenu.tscn
@@ -6,7 +6,7 @@
[ext_resource path="res://ui/Lobby.tscn" type="PackedScene" id=4]
[ext_resource path="res://assets/ui/verdana-bold.ttf" type="DynamicFontData" id=5]
[ext_resource path="res://ui/account/Account.tscn" type="PackedScene" id=6]
-[ext_resource path="res://SanParse/test.gd" type="Script" id=7]
+[ext_resource path="res://test.gd" type="Script" id=7]
[sub_resource type="DynamicFont" id=1]
size = 400