online multiplayer chess game (note server currently down)
yay threefold repetition draw(why was hard)
bendn 2022-04-29
parent f99fc51 · commit 4746a14
-rw-r--r--Grid.gd102
-rw-r--r--Square.gd6
-rw-r--r--Utils.gd45
-rw-r--r--pieces/Bishop.gd5
-rw-r--r--pieces/King.gd45
-rw-r--r--pieces/Knight.gd5
-rw-r--r--pieces/Pawn.gd5
-rw-r--r--pieces/Piece.gd31
-rw-r--r--pieces/Queen.gd5
-rw-r--r--pieces/Rook.gd5
-rw-r--r--project.godot6
-rw-r--r--sounds/SoundFX.gd1
12 files changed, 205 insertions, 56 deletions
diff --git a/Grid.gd b/Grid.gd
index 6a30359..64e8988 100644
--- a/Grid.gd
+++ b/Grid.gd
@@ -15,26 +15,72 @@ const Piece = preload("res://Piece.tscn")
const Square = preload("res://Square.tscn")
const piece_size = Vector2(100, 100)
+const default_metadata = {
+ "wccl": false, # white can castle left
+ "wccr": false, # white can castle right
+ "bccl": false, # black can castle left
+ "bccr": false, # black can castle right
+ "turn": true, # true = white, false = black
+ "wccp": [], # white can enpassant
+ "bccp": [], # black can enpassant
+}
var matrix = []
var background_matrix = []
+var history_matrixes: Dictionary = {}
var last_clicked
onready var piece_sets = walk_dir()
-func _ready(): # TODO: repetition draw
+func _ready(): # TODO: fill in wccp and bccp
Globals.grid = self # tell the globals that this is the grid
init_board() # create the tile squares
init_matrix() # create the pieces
Events.connect("turn_over", self, "_on_turn_over") # listen for turn_over events
+ # visualize the board
+ # for y in range(8):
+ # var strin = ""
+ # for x in range(8):
+ # strin += background_matrix[x][y].get_string() + " "
+ # print(strin)
+
+
+func threefoldrepetition():
+ for i in history_matrixes.values():
+ if i >= 3:
+ return true
+ return false
+
+
+func mat2str(mat = matrix):
+ var string = ""
+ for y in range(8):
+ for x in range(8):
+ var spot = mat[y][x]
+ if spot:
+ string += spot.mininame
+ else:
+ string += "*"
+ for i in mat[8].keys(): # store the metadata
+ var thing = mat[8][i]
+ string += i + "=" + str(thing)
+ return string
func _on_turn_over():
+ var matstr = mat2str()
+ if !history_matrixes.has(matstr):
+ history_matrixes[matstr] = 1
+ else:
+ history_matrixes[matstr] += 1
+ matrix[8].turn = Globals.turn
Globals.checking_piece = null # reset checking_piece
Globals.in_check = false # reset in_check
+ matrix[8] = default_metadata.duplicate() # add the metadata to the matrix
check_in_check(true) # check if in_check
- if can_move():
+ if !can_move():
+ print("what")
if Globals.in_check:
var winner = "black" if Globals.turn else "white"
print(winner, " won the game in ", Globals.turns(winner), " turns!")
@@ -46,11 +92,18 @@ func _on_turn_over():
SoundFx.play("Victory")
else:
print("stalemate")
- SoundFx.play("Draw")
- print_matrix_pretty()
- yield(get_tree().create_timer(5), "timeout")
- get_tree().reload_current_scene()
- SoundFx.play("Victory")
+ drawed()
+ elif threefoldrepetition():
+ print("draw by threefold repetition")
+ drawed()
+
+
+func drawed():
+ SoundFx.play("Draw")
+ print_matrix_pretty()
+ yield(get_tree().create_timer(5), "timeout")
+ get_tree().reload_current_scene()
+ SoundFx.play("Victory")
func check_in_check(prin = false): # check if in_check
@@ -62,7 +115,6 @@ func check_in_check(prin = false): # check if in_check
if prin:
Globals.in_check = true # set in_check
Globals.checking_piece = spot # set checking_piece
- print("check by " + spot.shortname) # print the check
SoundFx.play("Check")
return true # stop at the first check found
return false
@@ -74,8 +126,8 @@ func can_move():
var spot = matrix[i][j] # get the square
if spot and spot.white == Globals.turn: # fren
if spot.can_move():
- return false
- return true
+ return true
+ return false
func _exit_tree():
@@ -87,6 +139,7 @@ func init_matrix(): # create the matrix
matrix.append([]) # add a row
for _j in range(8): # for each column
matrix[i].append(null) # add a square
+ matrix.append(default_metadata.duplicate()) # metadata for threefold repetition check
add_pieces() # add the pieces
@@ -124,6 +177,7 @@ func add_pieces(): # add the pieces
add_bishops()
add_queens()
add_kings()
+ print_matrix_pretty()
func add_pawns():
@@ -165,17 +219,17 @@ func add_kings():
Globals.black_king = matrix[0][4] # set the black king
-const topper_header = "┏━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┓"
-const middle_header = "┣━━━╋━━━━╋━━━━╋━━━━╋━━━━╋━━━━╋━━━━╋━━━━╋━━━━┫"
-const middish_heads = "┗━━━╋━━━━╋━━━━╋━━━━╋━━━━╋━━━━╋━━━━╋━━━━╋━━━━┫"
-const bottom_header = "┗━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┛"
-const smaller_heads = " ┗━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┛"
-const letter_header = " ┃ a ┃ b ┃ c ┃ d ┃ e ┃ f ┃ g ┃ h ┃"
+const topper_header = "┏━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┓"
+const middle_header = "┣━━━╋━━━╋━━━╋━━━╋━━━╋━━━╋━━━╋━━━╋━━━┫"
+const middish_heads = "┗━━━╋━━━╋━━━╋━━━╋━━━╋━━━╋━━━╋━━━╋━━━┫"
+const bottom_header = "┗━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┛"
+const smaller_heads = " ┗━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┛"
+const letter_header = " ┃ a ┃ b ┃ c ┃ d ┃ e ┃ f ┃ g ┃ h ┃"
const ender = " ┃ "
func print_matrix_pretty(mat = matrix): # print the matrix
- for j in range(len(mat)): # for each row
+ for j in range(8): # for each row
var r = mat[j] # get the row
if j == 0:
print(topper_header) # print the top border
@@ -185,9 +239,9 @@ func print_matrix_pretty(mat = matrix): # print the matrix
for i in range(8): # for each column
var c = r[i] # get the column
if c: # if there is a piece
- row += c.shortname + ender # add the shortname
+ row += c.mininame + ender # add the shortname
else: # if there is no piece
- row += "00" + ender # add 00
+ row += " " + ender # add 00
print(row) # print the string
print(middish_heads)
print(letter_header)
@@ -228,8 +282,10 @@ func handle_move(position):
for i in range(len(last_clicked.can_castle)):
var castle_data = last_clicked.can_castle[i]
if castle_data[0] == position:
- last_clicked.castle(castle_data[0])
+ Utils.add_move(last_clicked.castle(castle_data[0]))
+ castle_data[1].override_moveto = true
castle_data[1].moveto(castle_data[2])
+ castle_data[1].override_moveto = false
turn_over()
return
if last_clicked is Pawn and last_clicked.enpassant:
@@ -262,13 +318,15 @@ func clear_fx(): # clear the circles
func _input(event): # input
- if event.is_action("debug"): # if debug
+ if event.is_action_released("debug"): # if debug
print_matrix_pretty() # print the matrix
- if event.is_action("kill"):
+ if event.is_action_released("kill"):
if last_clicked:
last_clicked.took() # kill the piece
last_clicked = null
clear_fx() # clear the circles
+ if event.is_action_released("fullscreen"):
+ OS.window_fullscreen = !OS.window_fullscreen
func walk_dir(path = "res://assets"): # walk the directory, finding the asset packs
diff --git a/Square.gd b/Square.gd
index 5a49c02..8853301 100644
--- a/Square.gd
+++ b/Square.gd
@@ -1,6 +1,7 @@
extends ColorRect
var real_position = Vector2()
+var algebraic_string = ""
var circle_on = false
onready var area = $Squarea
@@ -16,6 +17,7 @@ func _ready():
circle.visible = false
areacollisionshape.global_position += Globals.grid.piece_size / 2
areacollisionshape.shape.extents = Vector2(rect_size.x / 2, rect_size.y / 2)
+ algebraic_string = Utils.calculate_algebraic_position(real_position)
func _on_Squarea_input_event(_viewport: Node, event: InputEvent, _shape_idx: int):
@@ -23,6 +25,10 @@ func _on_Squarea_input_event(_viewport: Node, event: InputEvent, _shape_idx: int
emit_signal("clicked", real_position)
+func get_string():
+ return algebraic_string
+
+
func set_circle(boolean: bool, real = true):
circle_on = boolean
if real:
diff --git a/Utils.gd b/Utils.gd
index 07e0f77..62dab5f 100644
--- a/Utils.gd
+++ b/Utils.gd
@@ -1,5 +1,50 @@
extends Node
+var turn_moves := "1. "
+var turns_moves = []
+
+var counter = 0
+
+
+func _ready():
+ Events.connect("turn_over", self, "_on_turn_over")
+
+
+func _on_turn_over():
+ counter += 1
+ if counter >= 2:
+ counter = 0
+ print(turn_moves)
+ turns_moves.append(turn_moves)
+ turn_moves = str(Globals.white_turns + 1) + ". "
+
func is_pawn(inode):
return inode is Pawn
+
+
+func add_move(move):
+ turn_moves = turn_moves + " " + move
+
+
+func calculate_algebraic_position(real_position):
+ var algebraic_string = char(65 + (real_position.x)).to_lower()
+ algebraic_string += str(8 - real_position.y)
+ return algebraic_string
+
+
+func get_node_name(node):
+ if is_pawn(node):
+ return ["♙", "p"] if node.white else ["♟", "p"]
+ elif node is King:
+ return ["♔", "K"] if node.white else ["♚", "K"]
+ elif node is Queen:
+ return ["♕", "Q"] if node.white else ["♛", "Q"]
+ elif node is Rook:
+ return ["♖", "R"] if node.white else ["♜", "R"]
+ elif node is Bishop:
+ return ["♗", "B"] if node.white else ["♝", "B"]
+ elif node is Knight:
+ return ["♘", "N"] if node.white else ["♞", "N"]
+ else:
+ return ["", ""]
diff --git a/pieces/Bishop.gd b/pieces/Bishop.gd
index 8b2f2c1..d7848d4 100644
--- a/pieces/Bishop.gd
+++ b/pieces/Bishop.gd
@@ -4,8 +4,3 @@ class_name Bishop, "res://assets/california/wB.png"
func get_moves():
return .traverse(.all_dirs().slice(4, 8))
-
-
-func _ready():
- ._ready()
- shortname = "b" + team
diff --git a/pieces/King.gd b/pieces/King.gd
index c039f5b..356c8b5 100644
--- a/pieces/King.gd
+++ b/pieces/King.gd
@@ -20,6 +20,33 @@ func get_moves():
return moves
+func moveto(position, real = true, take = false):
+ if real: # assign metadata for threefold repetition draw check
+ castleing()
+ if can_castle.size() > 0:
+ for i in can_castle:
+ if i[3] == "O-O-O":
+ if white:
+ Globals.grid.matrix[8].wccl = true
+ else:
+ Globals.grid.matrix[8].bccl = true
+ else:
+ if white:
+ Globals.grid.matrix[8].wccr = true
+ else:
+ Globals.grid.matrix[8].wccr = true
+ else:
+ if white:
+ Globals.grid.matrix[8].wccl = false
+ Globals.grid.matrix[8].wccr = false
+ else:
+ Globals.grid.matrix[8].bccl = false
+ Globals.grid.matrix[8].bccr = false
+ if Input.is_action_pressed("ui_down") and real:
+ breakpoint
+ .moveto(position, real, take)
+
+
func castleing():
var moves = []
var rooks = [pos_around(Vector2.RIGHT * 3), pos_around(Vector2.LEFT * 4)]
@@ -38,19 +65,25 @@ func castleing():
continue
if checkcheck(posx2) or checkcheck(pos):
continue
- can_castle.append([posx2, rook, rook_motion[i]])
+ can_castle.append([posx2, rook, rook_motion[i], "O-O-O" if i == 1 else "O-O"])
moves.append(posx2)
return moves
func castle(position):
+ var return_string = ""
+ if can_castle.size() == 1:
+ return_string = can_castle[0][3]
+ else:
+ for i in can_castle:
+ if i[0] == position:
+ return_string = i[3]
+ break
+ override_moveto = true
can_castle.clear()
moveto(position)
-
-
-func _ready():
- ._ready()
- shortname = "k" + team
+ override_moveto = false
+ return return_string
func can_move(): # checks if you can legally move
diff --git a/pieces/Knight.gd b/pieces/Knight.gd
index 0f58fc5..af98835 100644
--- a/pieces/Knight.gd
+++ b/pieces/Knight.gd
@@ -22,8 +22,3 @@ func get_moves():
continue
final.append(i)
return final
-
-
-func _ready():
- ._ready()
- shortname = "n" + team
diff --git a/pieces/Pawn.gd b/pieces/Pawn.gd
index a183eb4..e6deb56 100644
--- a/pieces/Pawn.gd
+++ b/pieces/Pawn.gd
@@ -8,7 +8,7 @@ var just_set = false
var enpassant = []
-func moveto(position, real = true):
+func moveto(position, real = true, take = false):
# check if 2 step
if real and !twostepfirstmove and !has_moved:
if white and real_position.y - position.y == 2:
@@ -17,7 +17,7 @@ func moveto(position, real = true):
if !white and position.y - real_position.y == 2:
twostepfirstmove = true
just_set = true
- .moveto(position, real)
+ .moveto(position, real, take)
func _on_turn_over():
@@ -97,4 +97,3 @@ func en_passant(type: String = "moves"): # in passing
func _ready():
Events.connect("turn_over", self, "_on_turn_over")
._ready()
- shortname = "p" + team
diff --git a/pieces/Piece.gd b/pieces/Piece.gd
index 2d62ba3..735e3dd 100644
--- a/pieces/Piece.gd
+++ b/pieces/Piece.gd
@@ -4,12 +4,14 @@ class_name Piece, "res://assets/california/wP.png"
var real_position = Vector2.ZERO
var white := true
var shortname = ""
+var mininame = "♙"
var has_moved = false
var sprite
var frameon
var team = "w"
var check_spots_check = true
var no_enemys = false
+var override_moveto = false
onready var tween = $Tween
onready var anim = $AnimationPlayer
@@ -18,7 +20,9 @@ onready var frame = $Frame
func _ready():
- team = "W" if white else "B"
+ var tmp = Utils.get_node_name(self)
+ mininame = tmp[0]
+ shortname = tmp[1]
frame.position = Globals.grid.piece_size / 2
frame.modulate = Globals.grid.overlay_color
colorrect.color = Globals.grid.overlay_color
@@ -29,7 +33,6 @@ func clicked():
colorrect.show()
set_circle(get_moves())
set_circle(get_attacks(), "take")
- print(shortname, " was clicked")
func clear_clicked():
@@ -37,6 +40,20 @@ func clear_clicked():
Globals.grid.clear_fx()
+func algebraic_take_notation(position):
+ var starter = shortname if shortname != "p" else to_algebraic(real_position)[0]
+ return starter + "x" + to_algebraic(position)
+
+
+func algebraic_move_notation(position):
+ var starter = shortname if shortname != "p" else ""
+ return starter + to_algebraic(position)
+
+
+func to_algebraic(position):
+ return Globals.grid.background_matrix[position.x][position.y].get_string()
+
+
func move(newpos: Vector2): # dont use directly; use moveto
tween.interpolate_property(
self,
@@ -51,10 +68,15 @@ func move(newpos: Vector2): # dont use directly; use moveto
tween.start()
-func moveto(position, real = true):
+func moveto(position, real = true, take = false):
Globals.grid.matrix[real_position.y][real_position.x] = null
Globals.grid.matrix[position.y][position.x] = self
if real:
+ if !override_moveto:
+ if !take:
+ Utils.add_move(algebraic_move_notation(position))
+ else:
+ Utils.add_move(algebraic_take_notation(position))
real_position = position
move(position)
SoundFx.play("Move")
@@ -171,12 +193,11 @@ func is_on_board(vector: Vector2):
func take(piece: Piece):
clear_clicked()
piece.took()
- moveto(piece.real_position)
+ moveto(piece.real_position, true, true)
func took(): # called when piece is taken
SoundFx.play("Capture")
- print(shortname, "was killed")
Globals.grid.matrix[real_position.y][real_position.x] = null
anim.play("Take")
diff --git a/pieces/Queen.gd b/pieces/Queen.gd
index b853fed..2db02da 100644
--- a/pieces/Queen.gd
+++ b/pieces/Queen.gd
@@ -4,8 +4,3 @@ class_name Queen, "res://assets/california/wQ.png"
func get_moves():
return traverse(all_dirs())
-
-
-func _ready():
- ._ready()
- shortname = "q" + team
diff --git a/pieces/Rook.gd b/pieces/Rook.gd
index 03d2d40..fb4556f 100644
--- a/pieces/Rook.gd
+++ b/pieces/Rook.gd
@@ -4,8 +4,3 @@ class_name Rook, "res://assets/california/wR.png"
func get_moves():
return .traverse()
-
-
-func _ready():
- ._ready()
- shortname = "r" + team
diff --git a/project.godot b/project.godot
index 0f71ef7..43d4898 100644
--- a/project.godot
+++ b/project.godot
@@ -80,6 +80,7 @@ SoundFx="*res://sounds/SoundFX.tscn"
[debug]
+settings/crash_handler/message="fucking hell, make a issue at https://github.com/bend-n/chess"
gdscript/warnings/return_value_discarded=false
[display]
@@ -133,6 +134,11 @@ kill={
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":75,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
+fullscreen={
+"deadzone": 0.5,
+"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":70,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
+ ]
+}
[rendering]
diff --git a/sounds/SoundFX.gd b/sounds/SoundFX.gd
index 8a15875..be0aff0 100644
--- a/sounds/SoundFX.gd
+++ b/sounds/SoundFX.gd
@@ -14,6 +14,7 @@ var sounds = {
onready var sound_players = get_children()
+
func play(sound_string, pitch_scale = 1, volume_db = 0):
for soundPlayer in sound_players:
if not soundPlayer.playing: