tetris
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
class_name Tetris
extends AspectRatioContainer

const ROWS = 20
const COLUMNS = 10

export(PoolColorArray) var colors

var current_shape: TetrisPiece
var matrix := Logic.create_matrix(ROWS, COLUMNS)
var bg_squares := []
var squares := []


func get_square(at: Vector2) -> Control:
	return squares[at.y * COLUMNS + at.x]


func init_squares():
	var bg := create_grid_container("background")
	add_child(bg)
	var fg := create_grid_container("foreground")
	add_child(fg)
	for _i in range(ROWS * COLUMNS):
		var bg_square := ReferenceRect.new()
		bg_square.editor_only = false
		bg_square.border_width = 1.5
		bg_square.border_color = Color.ghostwhite
		bg_square.name = "%d" % _i
		expand_control(bg_square)
		bg.add_child(bg_square)
		var fg_square = ColorRect.new()
		fg_square.color = Color.transparent
		fg_square.name = "%d" % _i
		expand_control(fg_square)
		fg.add_child(fg_square)
		squares.append(fg_square)


func create_grid_container(name: String) -> GridContainer:
	var g := GridContainer.new()
	g.columns = COLUMNS
	g.name = name
	g.add_constant_override("hseparation", 0)
	g.add_constant_override("vseparation", 0)
	g.set_anchors_and_margins_preset(PRESET_WIDE)
	return g


func expand_control(c: Control) -> void:
	c.size_flags_horizontal = SIZE_EXPAND_FILL
	c.size_flags_vertical = SIZE_EXPAND_FILL
	c.set_anchors_and_margins_preset(PRESET_WIDE)


func _ready() -> void:
	set_process(false)
	assert(len(colors) == Logic.shapes.size())  # 7
	ratio = float(COLUMNS) / float(ROWS)
	init_squares()
	start()


func start() -> void:
	set_process(true)
	# warning-ignore-all:integer_division
	current_shape = TetrisPiece.new(Vector2((COLUMNS / 2) - 2, 0))
	tick()


func draw_board(mat: Array = matrix.duplicate(true), shape: TetrisPiece = current_shape) -> void:
	shape.embed(mat)
	for y in range(ROWS):
		for x in range(COLUMNS):
			get_square(Vector2(x, y)).color = colors[mat[y][x] - 1] if mat[y][x] > 0 else Color.transparent


func _process(_delta):
	if Input.is_action_just_pressed("ui_left"):
		current_shape.move(Vector2(-1, 0), matrix)
	elif Input.is_action_just_pressed("ui_right"):
		current_shape.move(Vector2(1, 0), matrix)
	if Input.is_action_just_pressed("ui_up"):
		current_shape.rotate(matrix, true)
	if Input.is_action_just_pressed("ui_down"):
		while current_shape.move(Vector2(0, 1), matrix):
			continue
		tick(false)
	else:
		draw_board()


func tick(create_timer := true):
	if create_timer:
		var t := get_tree().create_timer(.25)
		t.connect("timeout", self, "tick")

	if not current_shape.move(Vector2(0, 1), matrix):  # invalid move: cant go down
		current_shape.embed(matrix)
		current_shape = TetrisPiece.new(Vector2(randi() % (COLUMNS - 4), 0))
		Logic.clear_lines(matrix)
		print(ascii(matrix))
	draw_board()


#warning-ignore:shadowed_variable
func ascii(matrix):
	var s = "+"
	for _x in range(COLUMNS):
		s += "-"
	s += "+"
	#warning-ignore:shadowed_variable
	for y in range(ROWS):
		s += "\n" + ("|" if y != ROWS - 1 else "+")
		for x in range(COLUMNS):
			if matrix[y][x] > 0:
				s += "ﱢ"
			else:
				s += "-"
		s += ("|" if y != ROWS - 1 else "+")
	return s