online multiplayer chess game (note server currently down)
| -rw-r--r-- | Grid.gd | 102 | ||||
| -rw-r--r-- | Square.gd | 6 | ||||
| -rw-r--r-- | Utils.gd | 45 | ||||
| -rw-r--r-- | pieces/Bishop.gd | 5 | ||||
| -rw-r--r-- | pieces/King.gd | 45 | ||||
| -rw-r--r-- | pieces/Knight.gd | 5 | ||||
| -rw-r--r-- | pieces/Pawn.gd | 5 | ||||
| -rw-r--r-- | pieces/Piece.gd | 31 | ||||
| -rw-r--r-- | pieces/Queen.gd | 5 | ||||
| -rw-r--r-- | pieces/Rook.gd | 5 | ||||
| -rw-r--r-- | project.godot | 6 | ||||
| -rw-r--r-- | sounds/SoundFX.gd | 1 |
12 files changed, 205 insertions, 56 deletions
@@ -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 @@ -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: @@ -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: |