connect_cuatro 0.2.0 → 0.3.0

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 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: