connect_4_2307_nick_joop 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/connect_4_graphics +140 -0
- data/bin/connect_4_runner +6 -0
- data/lib/board.rb +98 -0
- data/lib/checker_criteria.rb +110 -0
- data/lib/computer_random.rb +16 -0
- data/lib/computer_smart.rb +83 -0
- data/lib/game_manager.rb +78 -0
- data/lib/player.rb +19 -0
- data/lib/require_helper.rb +8 -0
- data/lib/token.rb +7 -0
- data/lib/turn_manager.rb +43 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 712c64859e2aca132163b360976f53340762dda3a965207d4efd99fa299c7779
|
4
|
+
data.tar.gz: 563da52410152fb429a607d9ed745bf80c049f4aab155240b84922af41766ec9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 07da7340c19e38a0f557f4923626f98e8a57b6a34038daa79128cfab2c9b4bd3b7b5924660f0fe83cf25b61be89227ed927b4ca1380c209032911c5f91c2ee5f
|
7
|
+
data.tar.gz: 70ea227a35e4a63244fb5630284a74a53822e53198ce720d425d9d2e5000d692fde671f30d6ebaef81df084bb0173cf7cec1aa7cab20e85f44b95c42cf771d6a
|
@@ -0,0 +1,140 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'ruby2d'
|
3
|
+
require 'require_helper'
|
4
|
+
|
5
|
+
set width: 775
|
6
|
+
set height: 800
|
7
|
+
passed_menu = false
|
8
|
+
|
9
|
+
# cordinate data for rendering blank squares, as well as X's and O's when placed
|
10
|
+
# symbols correspond to the return from Player.place_piece and TurnManager.cpu_turn
|
11
|
+
cordinates = {
|
12
|
+
A5: [50, 700], A4: [50, 600], A3: [50, 500], A2: [50, 400], A1: [50, 300], A0: [50, 200],
|
13
|
+
B5: [150, 700], B4: [150, 600], B3: [150, 500], B2: [150, 400], B1: [150, 300], B0: [150, 200],
|
14
|
+
C5: [250, 700], C4: [250, 600], C3: [250, 500], C2: [250, 400], C1: [250, 300], C0: [250, 200],
|
15
|
+
D5: [350, 700], D4: [350, 600], D3: [350, 500], D2: [350, 400], D1: [350, 300], D0: [350, 200],
|
16
|
+
E5: [450, 700], E4: [450, 600], E3: [450, 500], E2: [450, 400], E1: [450, 300], E0: [450, 200],
|
17
|
+
F5: [550, 700], F4: [550, 600], F3: [550, 500], F2: [550, 400], F1: [550, 300], F0: [550, 200],
|
18
|
+
G5: [650, 700], G4: [650, 600], G3: [650, 500], G2: [650, 400], G1: [650, 300], G0: [650, 200]
|
19
|
+
|
20
|
+
}
|
21
|
+
|
22
|
+
def set_up_game_manager
|
23
|
+
board = Board.new
|
24
|
+
board.setup_game
|
25
|
+
player_1 = Player.new("X")
|
26
|
+
cpu = ComputerSmart.new(player_1.type)
|
27
|
+
TurnManager.new(board, player_1, cpu)
|
28
|
+
end
|
29
|
+
|
30
|
+
game = set_up_game_manager
|
31
|
+
|
32
|
+
# Uses cordinates Hash to render blank square positions representing connect 4 board
|
33
|
+
def render_game(cordinates, board)
|
34
|
+
set title: "Connect 4"
|
35
|
+
set background: "blue"
|
36
|
+
cordinates.each do |key, values|
|
37
|
+
Square.new(
|
38
|
+
x: values[0], y: values[1],
|
39
|
+
size: 85,
|
40
|
+
color: 'white', opacity: 1,
|
41
|
+
z: 0
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Helper method returns the corresponding symbol for selected column to drop token
|
47
|
+
def find_column(event)
|
48
|
+
return :A if event.x > 0 && event.x <= 140
|
49
|
+
return :B if event.x > 140 && event.x <= 240
|
50
|
+
return :C if event.x > 240 && event.x <= 340
|
51
|
+
return :D if event.x > 340 && event.x <= 440
|
52
|
+
return :E if event.x > 440 && event.x <= 540
|
53
|
+
return :F if event.x > 540 && event.x <= 640
|
54
|
+
return :G if event.x > 640 && event.x <= 800
|
55
|
+
end
|
56
|
+
|
57
|
+
# method gathers cordinates token is placed at, and uses cordinates hash to render
|
58
|
+
# token in the correct placement
|
59
|
+
def render_token(cords, type, cordinates)
|
60
|
+
Text.new(
|
61
|
+
"#{type}",
|
62
|
+
x: cordinates[cords][0] + 5, y: cordinates[cords][1] -10,
|
63
|
+
style: 'bold',
|
64
|
+
size: 85,
|
65
|
+
color: 'red'
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Images used for showing a game over message on screen
|
70
|
+
def render_game_over
|
71
|
+
Text.new(
|
72
|
+
"Game Over",
|
73
|
+
x: 125, y: 0,
|
74
|
+
style: 'bold',
|
75
|
+
size: 100,
|
76
|
+
color: 'red'
|
77
|
+
)
|
78
|
+
Text.new(
|
79
|
+
"press p to play again, or q to quit",
|
80
|
+
x: 130, y: 125,
|
81
|
+
size: 35,
|
82
|
+
color: 'red'
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
# key down and mouse down methods for game selection and token position selection
|
87
|
+
on :key_down do |event|
|
88
|
+
if event.key == "p"
|
89
|
+
clear
|
90
|
+
game.reset_game
|
91
|
+
render_game(cordinates, game.board)
|
92
|
+
passed_menu = true
|
93
|
+
end
|
94
|
+
if event.key == "q"
|
95
|
+
close
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
on :mouse_down do |event|
|
100
|
+
if passed_menu
|
101
|
+
checker = CheckerCriteria.new
|
102
|
+
column = find_column(event)
|
103
|
+
token_placement = game.board.place_piece(column, game.player.type)
|
104
|
+
if !(token_placement == "invalid column, column full")
|
105
|
+
render_token(token_placement, game.player.type, cordinates)
|
106
|
+
cpu_token = game.cpu_turn
|
107
|
+
render_token(cpu_token, game.cpu.type, cordinates)
|
108
|
+
game.board.render_board
|
109
|
+
if checker.check_win_conditions(game.board) || game.board.draw?
|
110
|
+
game.board.clear_board
|
111
|
+
game.board.setup_game
|
112
|
+
render_game_over
|
113
|
+
passed_menu = false
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
# key down and mouse down methods for game selection and token position selection
|
119
|
+
|
120
|
+
# set up the first start screen with p to play and q to quit options
|
121
|
+
def render_start_screen
|
122
|
+
Text.new(
|
123
|
+
"Welcome to connect 4",
|
124
|
+
x: 125, y: 325,
|
125
|
+
style: 'bold',
|
126
|
+
size: 50,
|
127
|
+
color: 'red'
|
128
|
+
)
|
129
|
+
Text.new(
|
130
|
+
"press p to play again, or q to quit",
|
131
|
+
x: 130, y: 475,
|
132
|
+
size: 35,
|
133
|
+
color: 'red'
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
render_start_screen
|
138
|
+
# set up the first start screen with p to play and q to quit options
|
139
|
+
|
140
|
+
show
|
data/lib/board.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require_relative 'token'
|
2
|
+
|
3
|
+
class Board
|
4
|
+
attr_reader :header, :columns
|
5
|
+
attr_accessor :play_area
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@play_area = {
|
9
|
+
A: [],
|
10
|
+
B: [],
|
11
|
+
C: [],
|
12
|
+
D: [],
|
13
|
+
E: [],
|
14
|
+
F: [],
|
15
|
+
G: []
|
16
|
+
}
|
17
|
+
@columns = @play_area.keys
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup_game
|
21
|
+
@play_area.values.each do |column|
|
22
|
+
6.times {column.append(Token.new)}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def read_cell(column, row)
|
27
|
+
row -= 1
|
28
|
+
@play_area[column][row].type
|
29
|
+
end
|
30
|
+
|
31
|
+
def render_board
|
32
|
+
puts @play_area.keys.join
|
33
|
+
board_array = @play_area.values.transpose
|
34
|
+
rows = board_array.map {|row| row.map {|token| token.type}}
|
35
|
+
rows.each {|line| puts line.join}
|
36
|
+
end
|
37
|
+
|
38
|
+
def clear_board
|
39
|
+
initialize
|
40
|
+
end
|
41
|
+
|
42
|
+
def place_piece(column, piece_type)
|
43
|
+
return "invalid column" if !@columns.include?(column)
|
44
|
+
i = -1
|
45
|
+
loop do
|
46
|
+
if @play_area[column][i].type == "."
|
47
|
+
@play_area[column][i].type = piece_type
|
48
|
+
cord = "#{column}#{i+6}"
|
49
|
+
return cord.intern
|
50
|
+
end
|
51
|
+
i -= 1
|
52
|
+
return "invalid column, column full" if i < -6
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def draw? #allways call win condition test first
|
57
|
+
all_tokens = @play_area.values.flatten
|
58
|
+
return false if all_tokens.any? {|token| token.type == "."}
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_draw_test
|
63
|
+
@play_area.each {|k,v| v.each {|token| token.type = "X"}}
|
64
|
+
end
|
65
|
+
# test if render_board outputs correct rows/columns
|
66
|
+
# by comparing to manually setting rows/columns
|
67
|
+
# def render_board_manual
|
68
|
+
# puts @play_area.keys.join
|
69
|
+
# i = 0
|
70
|
+
# rows = 5
|
71
|
+
# until i > rows do
|
72
|
+
# row = form_row(i)
|
73
|
+
# puts row
|
74
|
+
# i += 1
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
|
78
|
+
# def form_row(num)
|
79
|
+
# [@play_area[:A][num].type, @play_area[:B][num].type,
|
80
|
+
# @play_area[:C][num].type, @play_area[:D][num].type,
|
81
|
+
# @play_area[:E][num].type, @play_area[:F][num].type,
|
82
|
+
# @play_area[:G][num].type].join
|
83
|
+
# end
|
84
|
+
|
85
|
+
# def token_positions_by_type(type)
|
86
|
+
# counter = 0
|
87
|
+
# single_array =[]
|
88
|
+
# until counter == 7
|
89
|
+
# @play_area[@columns[counter]].select.with_index do |point, index|
|
90
|
+
# if point.type == type
|
91
|
+
# single_array << "#{@columns[counter].to_s}#{index}"
|
92
|
+
# end #if
|
93
|
+
# end #do
|
94
|
+
# counter += 1
|
95
|
+
# end #until
|
96
|
+
# single_array
|
97
|
+
# end #def
|
98
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
class CheckerCriteria
|
2
|
+
attr_reader :win, :winner
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@win = false
|
6
|
+
@winner = nil
|
7
|
+
@positive_diagonals = [["A5", "B4", "C3", "D2"],
|
8
|
+
["A4", "B3", "C2", "D1"],
|
9
|
+
["A3", "B2", "C1", "D0"],
|
10
|
+
["B5", "C4", "D3", "E2"],
|
11
|
+
["B4", "C3", "D2", "E1"],
|
12
|
+
["B3", "C2", "D1", "E0"],
|
13
|
+
["C5", "D4", "E3", "F2"],
|
14
|
+
["C4", "D3", "E2", "F1"],
|
15
|
+
["C3", "D2", "E1", "F0"],
|
16
|
+
["D5", "E4", "F3", "G2"],
|
17
|
+
["D4", "E3", "F2", "G1"],
|
18
|
+
["D3", "E2", "F1", "G0"]]
|
19
|
+
|
20
|
+
@negative_diagonals =
|
21
|
+
[["D5", "C4", "B3", "A2"],
|
22
|
+
["D4", "C3", "B2", "A1"],
|
23
|
+
["D3", "C2", "B1", "A0"],
|
24
|
+
["E5", "D4", "C3", "B2"],
|
25
|
+
["E4", "D3", "C2", "B1"],
|
26
|
+
["E3", "D2", "C1", "B0"],
|
27
|
+
["F5", "E4", "D3", "C2"],
|
28
|
+
["F4", "E3", "D2", "C1"],
|
29
|
+
["F3", "E2", "D1", "C0"],
|
30
|
+
["G5", "F4", "E3", "D2"],
|
31
|
+
["G4", "F3", "E2", "D1"],
|
32
|
+
["G3", "F2", "E1", "D0"]]
|
33
|
+
|
34
|
+
@columns = [:A, :B, :C, :D, :E, :F, :G]
|
35
|
+
end
|
36
|
+
|
37
|
+
def check_win_conditions(board)
|
38
|
+
check_vertical_win(board) || check_horizontal_win(board) || test_for_diagonal_wins(board)
|
39
|
+
end
|
40
|
+
|
41
|
+
#Private
|
42
|
+
|
43
|
+
def token_positions_by_type(type, board)
|
44
|
+
counter = 0
|
45
|
+
single_array =[]
|
46
|
+
until counter == 7
|
47
|
+
board.play_area[@columns[counter]].select.with_index do |point, index|
|
48
|
+
if point.type == type
|
49
|
+
single_array << "#{@columns[counter].to_s}#{index}"
|
50
|
+
end #if
|
51
|
+
end #do
|
52
|
+
counter += 1
|
53
|
+
end #until
|
54
|
+
single_array
|
55
|
+
end #def
|
56
|
+
|
57
|
+
def test_for_diagonal_wins(board)
|
58
|
+
@positive_diagonals.each do |win| if (win - token_positions_by_type("X", board)).empty?
|
59
|
+
@win = true
|
60
|
+
@winner = "X"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
@negative_diagonals.each do |win| if (win - token_positions_by_type("X", board)).empty?
|
64
|
+
@win = true
|
65
|
+
@winner = "X"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
@positive_diagonals.each do |win| if (win - token_positions_by_type("O", board)).empty?
|
69
|
+
@win = true
|
70
|
+
@winner = "O"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
@negative_diagonals.each do |win| if (win - token_positions_by_type("O", board)).empty?
|
74
|
+
@win = true
|
75
|
+
@winner = "O"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
@win
|
79
|
+
end
|
80
|
+
|
81
|
+
def check_vertical_win(board)
|
82
|
+
vert_strings = board.play_area.values.map do |column|
|
83
|
+
column.map {|token| token.type}
|
84
|
+
end
|
85
|
+
vert_wins = vert_strings.map {|col| col.join}
|
86
|
+
if vert_wins.any? { |str| str.include?("XXXX") }
|
87
|
+
@winner = "X"
|
88
|
+
@win = true
|
89
|
+
elsif vert_wins.any? { |str| str.include?("OOOO") }
|
90
|
+
@winner = "O"
|
91
|
+
@win = true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def check_horizontal_win(board)
|
96
|
+
horizontal_strings = board.play_area.values.transpose.map do |row|
|
97
|
+
row.map {|token| token.type}
|
98
|
+
end
|
99
|
+
horizontal_wins = horizontal_strings.map {|row| row.join}
|
100
|
+
if horizontal_wins.any? {|str| str.include?("XXXX")}
|
101
|
+
@winner = "X"
|
102
|
+
@win = true
|
103
|
+
elsif horizontal_wins.any? {|str| str.include?("OOOO")}
|
104
|
+
@winner = "O"
|
105
|
+
@win = true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class ComputerRandom
|
2
|
+
attr_reader :type, :enemy
|
3
|
+
def initialize(enemy_type = "X")
|
4
|
+
@type = OPPONENT[enemy_type]
|
5
|
+
@enemy = enemy_type
|
6
|
+
end
|
7
|
+
|
8
|
+
OPPONENT = {"O"=>"X", "X"=>"O"}
|
9
|
+
COLUMNS = [:A, :B, :C, :D, :E, :F, :G]
|
10
|
+
|
11
|
+
def place_piece(board)
|
12
|
+
board.place_piece(COLUMNS[rand(0..6)], @type)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class ComputerSmart
|
2
|
+
attr_reader :type, :enemy, :main_connected_tokens, :placement_column
|
3
|
+
|
4
|
+
def initialize(type = "X") #default needs to be removed eventually
|
5
|
+
@type = OPPONENT[type]
|
6
|
+
@enemy = type
|
7
|
+
@main_connected_tokens = 0
|
8
|
+
@placement_column = nil
|
9
|
+
@blocking = false
|
10
|
+
end
|
11
|
+
|
12
|
+
OPPONENT = {"O"=>"X", "X"=>"O"}
|
13
|
+
COLUMNS_SYM = [:A, :B, :C, :D, :E, :F, :G]
|
14
|
+
WEIGHTED_RANDOM = [:A, :A, :B, :B, :C, :C, :C, :C, :D, :D, :D, :E, :E, :E, :E, :F, :F, :G, :G]
|
15
|
+
|
16
|
+
def place_piece(board)
|
17
|
+
@main_connected_tokens = 0
|
18
|
+
tester(board, @enemy, false)
|
19
|
+
tester(board, @type, true)
|
20
|
+
case @main_connected_tokens
|
21
|
+
when 2..6
|
22
|
+
board.place_piece(COLUMNS_SYM[@placement_column], @type)
|
23
|
+
else
|
24
|
+
board.place_piece(WEIGHTED_RANDOM[rand(0..18)], @type)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Private
|
29
|
+
|
30
|
+
def tester(board, type_checker, blocking)
|
31
|
+
[*0..6].each do |column_number|
|
32
|
+
compass_tester(column_number, board, 1, -1, type_checker, blocking) #checks positive diagonal
|
33
|
+
compass_tester(column_number, board, -1, -1, type_checker, blocking) #checks negative diagonal
|
34
|
+
compass_tester(column_number, board, 1, 0, type_checker, blocking) #checks horizontal
|
35
|
+
compass_tester(column_number, board, 0, -1, type_checker, blocking) #checks vertical
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def compass_tester(column_number, board, array_number_num, item_number_num, type_checker, block)
|
40
|
+
connected_tokens = 0
|
41
|
+
array_number = column_number
|
42
|
+
item_number = find_empty(column_number, board)
|
43
|
+
rev_array_number = column_number
|
44
|
+
rev_item_number = find_empty(column_number, board)
|
45
|
+
loop do
|
46
|
+
array_number += array_number_num
|
47
|
+
item_number += item_number_num
|
48
|
+
break if array_number > 6 || array_number < 0
|
49
|
+
break if item_number > 5 || item_number < 0
|
50
|
+
break if board.play_area[COLUMNS_SYM[array_number]][item_number].type == "."
|
51
|
+
break if board.play_area[COLUMNS_SYM[array_number]][item_number].type == type_checker
|
52
|
+
connected_tokens += 1
|
53
|
+
end
|
54
|
+
loop do
|
55
|
+
rev_array_number += array_number_num * -1
|
56
|
+
rev_item_number += item_number_num * -1
|
57
|
+
break if rev_array_number > 6 || rev_array_number < 0
|
58
|
+
break if rev_item_number > 5 || rev_item_number < 0
|
59
|
+
break if board.play_area[COLUMNS_SYM[rev_array_number]][rev_item_number].type == "."
|
60
|
+
break if board.play_area[COLUMNS_SYM[rev_array_number]][rev_item_number].type == type_checker
|
61
|
+
connected_tokens += 1
|
62
|
+
end
|
63
|
+
if connected_tokens > @main_connected_tokens && find_empty(column_number, board) < 6
|
64
|
+
@main_connected_tokens = connected_tokens
|
65
|
+
@placement_column = column_number
|
66
|
+
@blocking = block
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def find_empty(column_number, board)
|
71
|
+
vertical_position = 5
|
72
|
+
previous = 6
|
73
|
+
loop do
|
74
|
+
if board.play_area[COLUMNS_SYM[column_number]][vertical_position].type == "."
|
75
|
+
return previous = vertical_position
|
76
|
+
end
|
77
|
+
vertical_position -= 1
|
78
|
+
break if vertical_position <= -1
|
79
|
+
end
|
80
|
+
previous
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
data/lib/game_manager.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative 'require_helper'
|
2
|
+
|
3
|
+
class GameManager
|
4
|
+
|
5
|
+
def start_game(board)
|
6
|
+
puts "Welcome to CONNECT FOUR"
|
7
|
+
puts "Enter p to play. Enter q to quit"
|
8
|
+
choice = gets.chomp
|
9
|
+
|
10
|
+
if choice.downcase == "p"
|
11
|
+
selection = ''
|
12
|
+
player_1 = x_or_o
|
13
|
+
cpu = select_cpu_type(player_1)
|
14
|
+
board.setup_game
|
15
|
+
game = TurnManager.new(board, player_1, cpu)
|
16
|
+
game_loop(board, game, cpu)
|
17
|
+
elsif choice.downcase == "q"
|
18
|
+
return false
|
19
|
+
else
|
20
|
+
puts "Invalid choice"
|
21
|
+
start_game(board)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def game_loop(board, game, cpu)
|
26
|
+
checker = CheckerCriteria.new
|
27
|
+
loop do
|
28
|
+
game.start_turn
|
29
|
+
break if check_re_render(board, checker)
|
30
|
+
game.cpu_turn
|
31
|
+
break if check_re_render(board, checker)
|
32
|
+
if board.draw?
|
33
|
+
puts "It's a draw"
|
34
|
+
board.render_board
|
35
|
+
board.clear_board
|
36
|
+
break
|
37
|
+
end
|
38
|
+
end
|
39
|
+
start_game(board)
|
40
|
+
end
|
41
|
+
|
42
|
+
def select_cpu_type(player)
|
43
|
+
puts "s for smart computer, r for random computer"
|
44
|
+
choice = gets.chomp
|
45
|
+
if choice == 's'
|
46
|
+
cpu = ComputerSmart.new(player.type)
|
47
|
+
elsif choice == 'r'
|
48
|
+
cpu = ComputerRandom.new(player.type)
|
49
|
+
else
|
50
|
+
puts "invalid selection"
|
51
|
+
select_cpu_type(player)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def check_re_render(board, checker)
|
56
|
+
if checker.check_win_conditions(board)
|
57
|
+
board.render_board
|
58
|
+
board.clear_board
|
59
|
+
puts "Game Over: #{checker.winner} wins"
|
60
|
+
return true
|
61
|
+
end
|
62
|
+
false
|
63
|
+
end
|
64
|
+
|
65
|
+
def x_or_o
|
66
|
+
puts "would you like X's or O's?('x/o')"
|
67
|
+
selection = gets.chomp
|
68
|
+
if selection == "x"
|
69
|
+
return player = Player.new("X")
|
70
|
+
elsif selection == "o"
|
71
|
+
return player = Player.new("O")
|
72
|
+
else
|
73
|
+
puts "invalid selecton"
|
74
|
+
x_or_o
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
data/lib/player.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class Player
|
2
|
+
attr_reader :type
|
3
|
+
def initialize(type)
|
4
|
+
@type = find_type(type)
|
5
|
+
end
|
6
|
+
|
7
|
+
def find_type(type)
|
8
|
+
case type
|
9
|
+
when 2, "x", "X"
|
10
|
+
"X"
|
11
|
+
when 1, "o", "O", 0
|
12
|
+
"O"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def place_piece(column, board)
|
17
|
+
board.place_piece(column, @type)
|
18
|
+
end
|
19
|
+
end
|
data/lib/token.rb
ADDED
data/lib/turn_manager.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
class TurnManager
|
2
|
+
attr_reader :board, :player, :cpu
|
3
|
+
def initialize(board, player, cpu)
|
4
|
+
@board = board
|
5
|
+
@player = player
|
6
|
+
@cpu = cpu
|
7
|
+
end
|
8
|
+
|
9
|
+
def start_turn
|
10
|
+
@board.render_board
|
11
|
+
puts "Select a column for your piece(A-G)"
|
12
|
+
column = gets.chomp.upcase.intern
|
13
|
+
new_token = @player.place_piece(column, @board)
|
14
|
+
check_column(new_token)
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_column(new_token)
|
18
|
+
if new_token == "invalid column, column full" || new_token == "invalid column"
|
19
|
+
until new_token != "invalid column, column full" && new_token != "invalid column"
|
20
|
+
puts "#{new_token}"
|
21
|
+
puts "Select another row(A-G)"
|
22
|
+
column = gets.chomp.upcase.intern
|
23
|
+
new_token = @player.place_piece(column, @board)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# method for cpu turn here
|
29
|
+
def cpu_turn
|
30
|
+
new_token = @cpu.place_piece(@board)
|
31
|
+
if new_token == "invalid column, column full" || new_token == "invalid column"
|
32
|
+
until new_token != "invalid column, column full" && new_token != "invalid column"
|
33
|
+
new_token = @cpu.place_piece(@board)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
new_token
|
37
|
+
end
|
38
|
+
|
39
|
+
def reset_game
|
40
|
+
@board.clear_board
|
41
|
+
@board.setup_game
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: connect_4_2307_nick_joop
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nick Spencer
|
8
|
+
- Joop Stark
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2023-07-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ruby2d
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.12.1
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.12.1
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rspec
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '3.12'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '3.12'
|
42
|
+
description: Connect 4, play either CLI or graphic interface vs computer
|
43
|
+
email:
|
44
|
+
- strangebrew202@gmail.com
|
45
|
+
- stark.joop@gmail.com
|
46
|
+
executables:
|
47
|
+
- connect_4_graphics
|
48
|
+
- connect_4_runner
|
49
|
+
extensions: []
|
50
|
+
extra_rdoc_files: []
|
51
|
+
files:
|
52
|
+
- bin/connect_4_graphics
|
53
|
+
- bin/connect_4_runner
|
54
|
+
- lib/board.rb
|
55
|
+
- lib/checker_criteria.rb
|
56
|
+
- lib/computer_random.rb
|
57
|
+
- lib/computer_smart.rb
|
58
|
+
- lib/game_manager.rb
|
59
|
+
- lib/player.rb
|
60
|
+
- lib/require_helper.rb
|
61
|
+
- lib/token.rb
|
62
|
+
- lib/turn_manager.rb
|
63
|
+
homepage:
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
metadata: {}
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubygems_version: 3.3.26
|
83
|
+
signing_key:
|
84
|
+
specification_version: 4
|
85
|
+
summary: Connect 4 game
|
86
|
+
test_files: []
|