connect_cuatro 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07ff3f60ceb45977060c65c2589af0eafd766e1730ce122d53f3bcdde980b3ef
4
- data.tar.gz: 3f5fc98c83e067b825386028088218edbba01b4b42c88a4fb61204205e2e180c
3
+ metadata.gz: d32f7b0ef5a218571b39947d24d9ed600e68b89820be801790ca8ae70f9d8c79
4
+ data.tar.gz: 577496c0635027112f11e0cf06797475c549ce258f6cb79a645cb88e889d7805
5
5
  SHA512:
6
- metadata.gz: f930ad3eacd2bf8f7312905ec7fc77b4721543ea238077593ec51a1b863a1aa402e4150cc37c35929b13a93c99fa73c2acfc39dafa5d8b11e4fd06fc3dab11d6
7
- data.tar.gz: d7efd9647459774b052e88dccab13f207f819b1a290da20820ae55ba10da155a99ce9f65b426d0914e820be6c8754ca5e938f641db6faef6ba28cae4839848ab
6
+ metadata.gz: af2e17e8e65cd9f16f942fd341a2a7b513ca049cea105771845a3c8b844d6451ae60d0ece75b33506d862effd3e3f59015803ae9c4c39e957e7b4079d02f5a6c
7
+ data.tar.gz: 55d87d9d5eeee647b8f813dbe3e7af31c32a8da43ef64ccccc1f09a216c4e08b3a9edce92a3d11dd7e85ddcd114e0c305201d90be1e9c5e6c30c2b3ffe58f871
data/lib/board.rb CHANGED
@@ -1,101 +1,101 @@
1
- class Board
2
- attr_reader :board
3
-
4
- def initialize(rows = 6, columns = 7)
5
- # board 'height'
6
- @num_rows = rows
7
- # board 'width'
8
- @num_columns = columns
9
- # Initialize an empty board filled with '.'
10
- @board = Array.new(@num_rows) { Array.new(@num_columns, '.') }
11
- end
12
-
13
- # return x, y coordinates
14
- def drop_token(column, token)
15
- col_idx = column_to_index(column)
16
- row_idx = @num_rows - 1
17
- @board.reverse_each do |row|
18
- if row[col_idx] == "."
19
- # animate dropping of token before return
20
- self.animate_token(col_idx, row_idx, token)
21
- row[col_idx] = token
22
- return col_idx, row_idx
23
- end
24
- row_idx -= 1
25
- end
26
- end
27
-
28
- def animate_token(col_idx, row_idx, token)
29
- row_idx.times do |i|
30
- sleep 0.77
31
- CLI.clear
32
- @board.each_with_index do |row, idx|
33
- pseudo_row = row.dup
34
- if idx == i
35
- pseudo_row[col_idx] = token
36
- puts pseudo_row.join(' ')
37
- else
38
- puts row.join(' ')
39
- end
40
- end
41
- # Print column numbers for easier reference
42
- puts COLUMNS[0...@num_columns].join(' ')
43
- end
44
- sleep 0.77
45
- CLI.clear
46
- end
47
-
48
- def display
49
- # Loop through each row and print it
50
- @board.each do |row|
51
- puts row.join(' ')
52
- end
53
- # Print column numbers for easier reference
54
- puts COLUMNS[0...@num_columns].join(' ')
55
- end
56
-
57
- def column_to_index(column)
58
- COLUMNS.index(column)
59
- end
60
-
61
- def board_full?
62
- !@board.flatten.include?(".")
63
- end
64
-
65
- def check_win(column, row, token)
66
- DIRECTIONS.each do |dx, dy|
67
- count = 1 # Start with the token just placed
68
-
69
- # Check one direction
70
- count += check_direction(column, row, dx, dy, token)
71
- # Check the opposite direction
72
- count += check_direction(column, row, -dx, -dy, token)
73
-
74
- return true if count >= 4 # Four or more in a row
75
- end
76
- false
77
- end
78
-
79
- def check_direction(column, row, dx, dy, token)
80
- count = 0
81
- x, y = column + dx, row - dy
82
-
83
- while y.between?(0, @num_rows - 1) && x.between?(0, @num_columns - 1) && @board[y][x] == token
84
- count += 1
85
- x += dx
86
- y -= dy
87
- end
88
-
89
- count
90
- end
91
-
92
-
93
- COLUMNS = %w{A B C D E F G}
94
-
95
- DIRECTIONS = [
96
- [0, 1], # Horizontal
97
- [1, 0], # Vertical
98
- [1, 1], # Diagonal right
99
- [1, -1] # Diagonal left
100
- ]
101
- end
1
+ class Board
2
+ attr_reader :board
3
+
4
+ def initialize(rows = 6, columns = 7)
5
+ # board 'height'
6
+ @num_rows = rows
7
+ # board 'width'
8
+ @num_columns = columns
9
+ # Initialize an empty board filled with '.'
10
+ @board = Array.new(@num_rows) { Array.new(@num_columns, ".") }
11
+ end
12
+
13
+ # return x, y coordinates
14
+ def drop_token(column, token)
15
+ col_idx = column_to_index(column)
16
+ row_idx = @num_rows - 1
17
+ @board.reverse_each do |row|
18
+ if row[col_idx] == "."
19
+ # animate dropping of token before return
20
+ animate_token(col_idx, row_idx, token)
21
+ row[col_idx] = token
22
+ return col_idx, row_idx
23
+ end
24
+ row_idx -= 1
25
+ end
26
+ end
27
+
28
+ def animate_token(col_idx, row_idx, token)
29
+ row_idx.times do |i|
30
+ sleep 0.26
31
+ CLI.clear
32
+ @board.each_with_index do |row, idx|
33
+ pseudo_row = row.dup
34
+ if idx == i
35
+ pseudo_row[col_idx] = token
36
+ puts pseudo_row.join(" ")
37
+ else
38
+ puts row.join(" ")
39
+ end
40
+ end
41
+ # Print column numbers for easier reference
42
+ puts COLUMNS[0...@num_columns].join(" ")
43
+ end
44
+ sleep 0.77
45
+ CLI.clear
46
+ end
47
+
48
+ def display
49
+ # Loop through each row and print it
50
+ @board.each do |row|
51
+ puts row.join(" ")
52
+ end
53
+ # Print column numbers for easier reference
54
+ puts COLUMNS[0...@num_columns].join(" ")
55
+ end
56
+
57
+ def column_to_index(column)
58
+ COLUMNS.index(column)
59
+ end
60
+
61
+ def board_full?
62
+ !@board.flatten.include?(".")
63
+ end
64
+
65
+ def check_win(column, row, token)
66
+ DIRECTIONS.each do |dx, dy|
67
+ count = 1 # Start with the token just placed
68
+
69
+ # Check one direction
70
+ count += check_direction(column, row, dx, dy, token)
71
+ # Check the opposite direction
72
+ count += check_direction(column, row, -dx, -dy, token)
73
+
74
+ return true if count >= 4 # Four or more in a row
75
+ end
76
+ false
77
+ end
78
+
79
+ def check_direction(column, row, dx, dy, token)
80
+ count = 0
81
+ x, y = column + dx, row - dy
82
+
83
+ while y.between?(0, @num_rows - 1) && x.between?(0, @num_columns - 1) && @board[y][x] == token
84
+ count += 1
85
+ x += dx
86
+ y -= dy
87
+ end
88
+
89
+ count
90
+ end
91
+
92
+
93
+ COLUMNS = %w[A B C D E F G]
94
+
95
+ DIRECTIONS = [
96
+ [0, 1], # Horizontal
97
+ [1, 0], # Vertical
98
+ [1, 1], # Diagonal right
99
+ [1, -1] # Diagonal left
100
+ ]
101
+ end
data/lib/cli.rb CHANGED
@@ -1,9 +1,9 @@
1
- module CLI
2
- def self.get_input
3
- STDIN.gets.chomp.upcase
4
- end
5
-
6
- def self.clear
7
- system('clear')
8
- end
9
- end
1
+ module CLI
2
+ def self.get_input
3
+ STDIN.gets.chomp.upcase
4
+ end
5
+
6
+ def self.clear
7
+ system("clear")
8
+ end
9
+ end
data/lib/connect_four.rb CHANGED
@@ -1,90 +1,85 @@
1
- # frozen_string_literal: true
2
- require_relative 'game_engine'
3
- require_relative 'multiplayer_game_engine'
4
- require_relative 'msg'
5
- require_relative 'ip_config'
6
-
7
- class ConnectFour
8
- include MSG, IP_CONFIG
9
-
10
- attr_reader :game_engine
11
-
12
- def initialize
13
- @game_engine = nil
14
- end
15
-
16
- def main_menu
17
- puts WELCOME_MSG
18
- play_quit = CLI.get_input
19
- # play_quit = "P" # testing
20
- if play_quit == "Q"
21
- abort(BYE_MSG)
22
- elsif play_quit == "P"
23
- puts PLAY_MSG
24
- set_game_engine
25
- else
26
- puts P_OR_Q_ERR_MSG
27
- main_menu
28
- end
29
- end
30
-
31
- #returns game engine MP or SP
32
- def set_game_engine
33
- puts ONEPLAYER_TWOPLAYER
34
- game_mode = CLI.get_input
35
- # game_mode = "2P" # testing
36
- if game_mode == "1P"
37
- @game_engine = GameEngine.new
38
- self.start
39
- elsif game_mode == "2P"
40
- @game_engine = MPGameEngine.new
41
- self.start
42
- else
43
- puts INPUT_ERR_MSG(game_mode)
44
- set_game_engine
45
- end
46
- end
47
-
48
- def start
49
- if @game_engine.class == MPGameEngine
50
- self.loiter # wait in lobby
51
- @game_engine.play_game
52
- self.main_menu
53
- else
54
- @game_engine.play_game
55
- self.main_menu
56
- end
57
- end
58
-
59
- def loiter
60
- # make initial curl request
61
- username = ENV['USER']
62
- foe = ""
63
- p1 = ""
64
- # send /init request
65
- response = `curl -s "#{P2P_IP}/init?player=#{username}"`.chomp # => '...patient'
66
- until response == "start"
67
- print WAITING_MSG
68
- # send /start request; if game ready to start, will return foe
69
- response = `curl -s "#{P2P_IP}/start?player=#{username}"`.chomp
70
- if response.include?("start")
71
- start_responses = response.split(" ")
72
- foe = start_responses[1]
73
- p1 = start_responses[2] # p1 used to set @current_player
74
- response = "start"
75
- break
76
- end
77
- LOADER_MSG(7) # wait 7 seconds
78
- end
79
-
80
- puts ""
81
- puts OPP_FOUND
82
- @game_engine.player1 = Player.new(username, token = "X")
83
- @game_engine.player2 = Player.new(foe, token = "O")
84
- @game_engine.set_current_player(p1)
85
- print "game ready to start"
86
- LOADER_MSG(3) # wait 3 seconds
87
- end
88
- end
89
-
90
- # ConnectFour.new.main_menu
1
+ # frozen_string_literal: true
2
+ require_relative "game_engine"
3
+ require_relative "multiplayer_game_engine"
4
+ require_relative "msg"
5
+ require_relative "ip_config"
6
+
7
+ class ConnectFour
8
+ include IpConfig
9
+ include MSG
10
+
11
+ attr_reader :game_engine
12
+
13
+ def initialize
14
+ @game_engine = nil
15
+ end
16
+
17
+ def main_menu
18
+ puts WELCOME_MSG
19
+ play_quit = CLI.get_input
20
+ # play_quit = "P" # testing
21
+ if play_quit == "Q"
22
+ abort(BYE_MSG)
23
+ elsif play_quit == "P"
24
+ puts PLAY_MSG
25
+ set_game_engine
26
+ else
27
+ puts P_OR_Q_ERR_MSG
28
+ main_menu
29
+ end
30
+ end
31
+
32
+ # returns game engine MP or SP
33
+ def set_game_engine
34
+ puts ONEPLAYER_TWOPLAYER
35
+ game_mode = CLI.get_input
36
+ # game_mode = "2P" # testing
37
+ if game_mode == "1P"
38
+ @game_engine = GameEngine.new
39
+ elsif game_mode == "2P"
40
+ @game_engine = MPGameEngine.new
41
+ else
42
+ puts INPUT_ERR_MSG(game_mode)
43
+ set_game_engine
44
+ end
45
+ start
46
+ end
47
+
48
+ def start
49
+ loiter if @game_engine.instance_of?(MPGameEngine)
50
+ @game_engine.play_game
51
+ main_menu
52
+ end
53
+
54
+ def loiter
55
+ # make initial curl request
56
+ username = ENV["USER"]
57
+ foe = ""
58
+ p1 = ""
59
+ # send /init request
60
+ response = `curl -s "#{P2P_IP}/init?player=#{username}"`.chomp # => '...patient'
61
+ until response == "start"
62
+ print WAITING_MSG
63
+ # send /start request; if game ready to start, will return foe
64
+ response = `curl -s "#{P2P_IP}/start?player=#{username}"`.chomp
65
+ if response.include?("start")
66
+ start_responses = response.split(" ")
67
+ foe = start_responses[1]
68
+ p1 = start_responses[2] # p1 used to set @current_player
69
+ response = "start"
70
+ break
71
+ end
72
+ LOADER_MSG(7) # wait 7 seconds
73
+ end
74
+
75
+ puts ""
76
+ puts OPP_FOUND
77
+ @game_engine.player1 = Player.new(username, "X")
78
+ @game_engine.player2 = Player.new(foe, "O")
79
+ @game_engine.set_current_player(p1)
80
+ print "game ready to start"
81
+ LOADER_MSG(3) # wait 3 seconds
82
+ end
83
+ end
84
+
85
+ # ConnectFour.new.main_menu
data/lib/game_engine.rb CHANGED
@@ -1,99 +1,98 @@
1
- require_relative 'board'
2
- require_relative 'player'
3
- require_relative 'msg'
4
- require_relative 'cli'
5
-
6
- class GameEngine
7
- include MSG
8
-
9
- attr_reader :player1,
10
- :ai,
11
- :players,
12
- :current_player,
13
- :board,
14
- :piece_count
15
-
16
- def initialize
17
- @player1 = Player.new(ENV['USER'], "X")
18
- @ai = Player.new("HAL", "O")
19
- @players = [@player1, @ai]
20
- @board = Board.new
21
- @current_player = @players[0]
22
- end
23
-
24
- def play_game # Player has hit 'p'
25
- game_over = false
26
- until game_over
27
- puts @board.display
28
- # keep false until valid input => in-range, un-filled column
29
- turn_over = false
30
- plyr = whose_turn
31
- token_x, token_y = nil, nil # returned from #drop_token and passed to #win_condition
32
- # if human player
33
- if plyr == @player1
34
- # force user to enter valid input
35
- until turn_over
36
- # only runs once (right after opponent takes turn)
37
- puts PLAYER_TURN_MSG
38
- column = CLI.get_input
39
- if valid_input(column)
40
- token_x, token_y = drop_token(column, plyr.token)
41
- turn_over = true
42
- else
43
- # continue to run until HUMAN user enters valid input
44
- puts INPUT_ERR_MSG(column)
45
- end
46
- end
47
- else
48
- # computer's turn
49
- # TODO trash talk
50
- # keep false until computer picks unfilled column (idx always in-range)
51
- until turn_over
52
- column = Board::COLUMNS.sample
53
- if valid_input(column)
54
- token_x, token_y = drop_token(column, plyr.token)
55
- turn_over = true
56
- end
57
- end
58
- end
59
- if @board.check_win(token_x, token_y, plyr.token)
60
- puts @board.display
61
- puts "#{VICTORY_MSG(plyr.name)}"
62
- game_over = true
63
- end
64
- if @board.board_full?
65
- puts @board.display
66
- puts TIE_GAME_MSG
67
- game_over = true
68
- end
69
- end
70
- end
71
-
72
- def valid_input(column)
73
- idx = @board.column_to_index(column)
74
- if Board::COLUMNS.include?(column) && @board.board[0][idx] == '.'
75
- return true
76
- else
77
- return false
78
- end
79
- end
80
-
81
- # returns player object and increments queue
82
- def whose_turn
83
- plyr = @current_player
84
- if plyr == @players[0]
85
- @current_player = @players[1]
86
- else
87
- @current_player = @players[0]
88
- end
89
- return plyr
90
- end
91
-
92
- def drop_token(column, token)
93
- idx = @board.column_to_index(column)
94
- @board.drop_token(column, token)
95
- end
96
- end
97
-
98
- # session = GameEngine.new
99
- # session.main_menu
1
+ require_relative "board"
2
+ require_relative "player"
3
+ require_relative "msg"
4
+ require_relative "cli"
5
+
6
+ class GameEngine
7
+ include MSG
8
+
9
+ attr_reader :player1,
10
+ :ai,
11
+ :players,
12
+ :current_player,
13
+ :board,
14
+ :piece_count
15
+
16
+ def initialize
17
+ @player1 = Player.new(ENV["USER"], "X")
18
+ @ai = Player.new("HAL", "O")
19
+ @players = [@player1, @ai]
20
+ @board = Board.new
21
+ @current_player = @players[0]
22
+ end
23
+
24
+ def play_game # Player has hit 'p'
25
+ game_over = false
26
+ until game_over
27
+ puts @board.display
28
+ # keep false until valid input => in-range, un-filled column
29
+ turn_over = false
30
+ plyr = whose_turn
31
+ token_x, token_y = nil, nil # returned from #drop_token and passed to #win_condition
32
+ # if human player
33
+ if plyr == @player1
34
+ # force user to enter valid input
35
+ until turn_over
36
+ # only runs once (right after opponent takes turn)
37
+ puts PLAYER_TURN_MSG
38
+ column = CLI.get_input
39
+ if valid_input(column)
40
+ token_x, token_y = drop_token(column, plyr.token)
41
+ turn_over = true
42
+ else
43
+ # continue to run until HUMAN user enters valid input
44
+ puts INPUT_ERR_MSG(column)
45
+ end
46
+ end
47
+ else
48
+ # computer's turn
49
+ # TODO trash talk
50
+ # keep false until computer picks unfilled column (idx always in-range)
51
+ until turn_over
52
+ column = Board::COLUMNS.sample
53
+ if valid_input(column)
54
+ token_x, token_y = drop_token(column, plyr.token)
55
+ turn_over = true
56
+ end
57
+ end
58
+ end
59
+ if @board.check_win(token_x, token_y, plyr.token)
60
+ puts @board.display
61
+ puts VICTORY_MSG(plyr.name)
62
+ game_over = true
63
+ end
64
+ if @board.board_full?
65
+ puts @board.display
66
+ puts TIE_GAME_MSG
67
+ game_over = true
68
+ end
69
+ end
70
+ end
71
+
72
+ def valid_input(column)
73
+ idx = @board.column_to_index(column)
74
+ if Board::COLUMNS.include?(column) && @board.board[0][idx] == "."
75
+ true
76
+ else
77
+ false
78
+ end
79
+ end
80
+
81
+ # returns player object and increments queue
82
+ def whose_turn
83
+ plyr = @current_player
84
+ @current_player = if plyr == @players[0]
85
+ @players[1]
86
+ else
87
+ @players[0]
88
+ end
89
+ plyr
90
+ end
91
+
92
+ def drop_token(column, token)
93
+ @board.drop_token(column, token)
94
+ end
95
+ end
96
+
97
+ # session = GameEngine.new
98
+ # session.main_menu
data/lib/ip_config.rb CHANGED
@@ -1,4 +1,4 @@
1
- module IP_CONFIG
2
- P2P_IP = '52.53.215.135:3333'
3
- TEST_IP = 'localhost:3333'
4
- end
1
+ module IpConfig
2
+ P2P_IP = "52.53.215.135:3333"
3
+ TEST_IP = "localhost:3333"
4
+ end
data/lib/msg.rb CHANGED
@@ -1,52 +1,51 @@
1
- module MSG
2
- ONEPLAYER_TWOPLAYER = "1P || 2P"
3
-
4
- WELCOME_MSG = "Let's play **** CONNECT FOUR ****
5
- Connect four of your checkers in a row while preventing your opponent from doing the same.\n
6
- press 'p' to play; 'q' to quit:"
7
-
8
- PLAY_MSG = "#{ENV["USER"]} says we're playing Connect Four!!"
9
-
10
- BYE_MSG = "Sucka’s only see what’s in front of them while real game playa’s see the whole board, – 777\nDeuces!"
11
-
12
- MP_BYE_MSG = "If you want to play again, rerun the script. Goodbye!"
13
-
14
- P_OR_Q_ERR_MSG = "Sorry, I didn't understand that selection. press 'p' to play; 'q' to quit:"
15
-
16
- PLAYER_TURN_MSG = "Choose where you want to drop your token"
17
-
18
- TIE_GAME_MSG = "The board is full!! It's a draw!"
19
-
20
- WAITING_MSG = "Waiting for opponent to join"
21
-
22
- OPP_FOUND = "Opponent found...establishing connection"
23
-
24
- def TIMES_UP_MSG(column)
25
- "Time's up: you randomly chose column #{column}"
26
- end
27
- def WAITING_FOR_PLYR_MSG(plyr_name)
28
- "Waiting for #{plyr_name} to make a move"
29
- end
30
-
31
- def LOADER_MSG(i)
32
- i.times do
33
- sleep 1.6
34
- print " . "
35
- end
36
- puts ""
37
- end
38
-
39
- def VICTORY_MSG(plyr_name)
40
- if plyr_name == "HAL"
41
- "HAL won!! You just lost to an unliving being!! Boom!!"
42
- else
43
- "#Hot Dog, we have a Winner! Congratulations #{plyr_name}!!!"
44
- end
45
- end
46
-
47
- def INPUT_ERR_MSG(input)
48
- "#{input} is an invalid selection"
49
- end
50
-
51
- # X_OR_O_MSG = "Pick your piece! X or O??"
52
- end
1
+ module MSG
2
+ ONEPLAYER_TWOPLAYER = "1P || 2P"
3
+
4
+ WELCOME_MSG = "Let's play **** CONNECT FOUR ****
5
+ Connect four of your checkers in a row while preventing your opponent from doing the same.\n
6
+ press 'p' to play; 'q' to quit:"
7
+
8
+ PLAY_MSG = "#{ENV["USER"]} says we're playing Connect Four!!"
9
+
10
+ BYE_MSG = "Sucka’s only see what’s in front of them while real game playa’s see the whole board, – 777\nDeuces!"
11
+
12
+ P_OR_Q_ERR_MSG = "Sorry, I didn't understand that selection. press 'p' to play; 'q' to quit:"
13
+
14
+ PLAYER_TURN_MSG = "Choose where you want to drop your token"
15
+
16
+ TIE_GAME_MSG = "The board is full!! It's a draw!"
17
+
18
+ WAITING_MSG = "Waiting for opponent to join"
19
+
20
+ OPP_FOUND = "Opponent found...establishing connection"
21
+
22
+ def TIMES_UP_MSG(column)
23
+ "Time's up: you randomly chose column #{column}"
24
+ end
25
+
26
+ def WAITING_FOR_PLYR_MSG(plyr_name)
27
+ "Waiting for #{plyr_name} to make a move"
28
+ end
29
+
30
+ def LOADER_MSG(i)
31
+ i.times do
32
+ sleep 1.6
33
+ print " . "
34
+ end
35
+ puts ""
36
+ end
37
+
38
+ def VICTORY_MSG(plyr_name)
39
+ if plyr_name == "HAL"
40
+ "HAL won!! You just lost to an unliving being!! Boom!!"
41
+ else
42
+ "#Hot Dog, we have a Winner! Congratulations #{plyr_name}!!!"
43
+ end
44
+ end
45
+
46
+ def INPUT_ERR_MSG(input)
47
+ "#{input} is an invalid selection"
48
+ end
49
+
50
+ # X_OR_O_MSG = "Pick your piece! X or O??"
51
+ end
@@ -1,149 +1,142 @@
1
- require_relative 'board'
2
- require_relative 'player'
3
- require_relative 'msg'
4
- require_relative 'cli'
5
- require_relative 'ip_config'
6
- require 'thread'
7
-
8
- class MPGameEngine
9
- include MSG, IP_CONFIG
10
-
11
- attr_reader :board
12
- attr_accessor :player1,
13
- :player2,
14
- :current_player
15
-
16
- def initialize
17
- @player1 = nil
18
- @player2 = nil
19
- @current_player = nil
20
- @board = Board.new
21
- end
22
-
23
- def players
24
- [@player1, @player2]
25
- end
26
-
27
- def set_current_player(p1)
28
- @current_player = self.players.filter { |player| player.name == p1 }.first
29
- end
30
-
31
- def play_game # Player has hit 'p'
32
- game_over = false
33
- until game_over
34
- puts @board.display
35
- turn_over = false
36
- plyr = whose_turn
37
- token_x, token_y = nil, nil # returned from #drop_token and passed to #win_condition
38
- # local client
39
- if plyr == @player1
40
- input_received = false
41
- column = nil
42
- mutex = Mutex.new
43
-
44
- input_thread = Thread.new do
45
- puts PLAYER_TURN_MSG
46
- # keep false until valid input => in-range, un-filled column
47
- until turn_over
48
- ready = IO.select([STDIN], nil, nil, 1.6) # 4th arg is 'release after time' (s)
49
-
50
- if ready
51
- column = STDIN.gets.chomp.upcase
52
- if valid_input(column)
53
- mutex.synchronize do
54
- input_received = true
55
- turn_over = true
56
- column = column
57
- end
58
- else
59
- puts INPUT_ERR_MSG(column)
60
- # continue to run until local client enters valid input
61
- # loops back to until turn_over
62
- end
63
- end
64
- end
65
- end
66
-
67
- timer_thread = Thread.new do
68
- 10.times do |i|
69
- print "#{10 - i }. . "
70
- sleep 1.6
71
- break if mutex.synchronize { input_received }
72
- end
73
- # if the player doesn't select a column, random valid selection will occur
74
- until turn_over
75
- column = Board::COLUMNS.sample
76
- if valid_input(column)
77
- puts TIMES_UP_MSG(column)
78
- mutex.synchronize do
79
- input_received = true
80
- turn_over = true
81
- column = column
82
- end
83
- end
84
- end
85
- end
86
-
87
- [input_thread, timer_thread].each(&:join)
88
-
89
- token_x, token_y = drop_token(column, plyr.token)
90
- # send valid column selection to server
91
- `curl -s "#{P2P_IP}/move?player=#{plyr.name}?column=#{column}"`
92
- else # remote client || @player2
93
- until turn_over
94
- 11.times do
95
- puts WAITING_FOR_PLYR_MSG(plyr.name)
96
- response = `curl -s "#{P2P_IP}/status?player=#{@player1.name}"`.chomp
97
- # require 'pry'; binding.pry
98
- unless response.include?("patience") # unless this fails => response == <valid letter>
99
- token_x, token_y = drop_token(response, plyr.token)
100
- turn_over = true
101
- break
102
- end
103
- sleep 1.6
104
- end
105
- end
106
- end
107
-
108
- if @board.check_win(token_x, token_y, plyr.token)
109
- puts @board.display
110
- puts "#{VICTORY_MSG(plyr.name)}"
111
- game_over = true
112
- end
113
-
114
- if @board.board_full?
115
- puts @board.display
116
- puts TIE_GAME_MSG
117
- game_over = true
118
- end
119
- end
120
- sleep 1.6
121
- # send /reset command to server to clear out stored variables
122
- `curl -s "#{P2P_IP}/reset"`
123
- end
124
-
125
- def valid_input(column)
126
- idx = @board.column_to_index(column)
127
- if Board::COLUMNS.include?(column) && @board.board[0][idx] == '.'
128
- true
129
- else
130
- false
131
- end
132
- end
133
-
134
- # returns player object and increments queue
135
- def whose_turn
136
- plyr = @current_player
137
- if plyr == players[0]
138
- @current_player = players[1]
139
- else
140
- @current_player = players[0]
141
- end
142
- plyr
143
- end
144
-
145
- def drop_token(column, token)
146
- idx = @board.column_to_index(column)
147
- @board.drop_token(column, token)
148
- end
149
- end
1
+ require_relative "board"
2
+ require_relative "player"
3
+ require_relative "msg"
4
+ require_relative "cli"
5
+ require_relative "ip_config"
6
+
7
+ class MPGameEngine
8
+ include IpConfig
9
+ include MSG
10
+
11
+ attr_reader :board
12
+ attr_accessor :player1,
13
+ :player2,
14
+ :current_player
15
+
16
+ def initialize
17
+ @player1 = nil
18
+ @player2 = nil
19
+ @current_player = nil
20
+ @board = Board.new
21
+ end
22
+
23
+ def players
24
+ [@player1, @player2]
25
+ end
26
+
27
+ def set_current_player(p1)
28
+ @current_player = players.find { |player| player.name == p1 }
29
+ end
30
+
31
+ def play_game # Player has hit 'p'
32
+ game_over = false
33
+ until game_over
34
+ puts @board.display
35
+ turn_over = false
36
+ plyr = whose_turn
37
+ token_x, token_y = nil, nil # returned from #drop_token and passed to #win_condition
38
+ # local client
39
+ if plyr == @player1
40
+ input_received = false
41
+ column = nil
42
+ mutex = Mutex.new
43
+
44
+ input_thread = Thread.new do
45
+ puts PLAYER_TURN_MSG
46
+ # keep false until valid input => in-range, un-filled column
47
+ until turn_over
48
+ ready = IO.select([$stdin], nil, nil, 1.6) # 4th arg is 'release after time' (s)
49
+
50
+ if ready
51
+ column = $stdin.gets.chomp.upcase
52
+ if valid_input(column)
53
+ mutex.synchronize do
54
+ input_received = true
55
+ turn_over = true
56
+ end
57
+ else
58
+ puts INPUT_ERR_MSG(column)
59
+ # continue to run until local client enters valid input
60
+ # loops back to until turn_over
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ timer_thread = Thread.new do
67
+ 10.times do |i|
68
+ print "#{10 - i}. . "
69
+ sleep 1.6
70
+ break if mutex.synchronize { input_received }
71
+ end
72
+ # if the player doesn't select a column, random valid selection will occur
73
+ until turn_over
74
+ column = Board::COLUMNS.sample
75
+ if valid_input(column)
76
+ puts TIMES_UP_MSG(column)
77
+ mutex.synchronize do
78
+ input_received = true
79
+ turn_over = true
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ [input_thread, timer_thread].each(&:join)
86
+
87
+ token_x, token_y = drop_token(column, plyr.token)
88
+ # send valid column selection to server
89
+ `curl -s "#{P2P_IP}/move?player=#{plyr.name}?column=#{column}"`
90
+ else # remote client || @player2
91
+ until turn_over
92
+ 11.times do
93
+ puts WAITING_FOR_PLYR_MSG(plyr.name)
94
+ response = `curl -s "#{P2P_IP}/status?player=#{@player1.name}"`.chomp
95
+ # require 'pry'; binding.pry
96
+ unless response.include?("patience") # unless this fails => response == <valid letter>
97
+ token_x, token_y = drop_token(response, plyr.token)
98
+ turn_over = true
99
+ break
100
+ end
101
+ sleep 1.6
102
+ end
103
+ end
104
+ end
105
+
106
+ if @board.check_win(token_x, token_y, plyr.token)
107
+ puts @board.display
108
+ puts VICTORY_MSG(plyr.name)
109
+ game_over = true
110
+ end
111
+
112
+ if @board.board_full?
113
+ puts @board.display
114
+ puts TIE_GAME_MSG
115
+ game_over = true
116
+ end
117
+ end
118
+ sleep 1.6
119
+ # send /reset command to server to clear out stored variables
120
+ `curl -s "#{P2P_IP}/reset"`
121
+ end
122
+
123
+ def valid_input(column)
124
+ idx = @board.column_to_index(column)
125
+ Board::COLUMNS.include?(column) && @board.board[0][idx] == "."
126
+ end
127
+
128
+ # returns player object and increments queue
129
+ def whose_turn
130
+ plyr = @current_player
131
+ @current_player = if plyr == players[0]
132
+ players[1]
133
+ else
134
+ players[0]
135
+ end
136
+ plyr
137
+ end
138
+
139
+ def drop_token(column, token)
140
+ @board.drop_token(column, token)
141
+ end
142
+ end
data/lib/player.rb CHANGED
@@ -1,9 +1,9 @@
1
- class Player
2
- attr_reader :name
3
- attr_accessor :token
4
-
5
- def initialize(name, token="X")
6
- @name = name
7
- @token = token
8
- end
9
- end
1
+ class Player
2
+ attr_reader :name
3
+ attr_accessor :token
4
+
5
+ def initialize(name, token = "X")
6
+ @name = name
7
+ @token = token
8
+ end
9
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: connect_cuatro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Darlington
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-09-14 00:00:00.000000000 Z
12
+ date: 2023-09-16 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Digital version of the Classic Connect Four boardgame.
15
15
  email: