gomoku 0.1.0 → 0.2.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
  SHA1:
3
- metadata.gz: 4871071f274fed79f3fcf6134767e2a81cc99df3
4
- data.tar.gz: f7ca22e0fa35c082f31bb9a6ca16cdfe0e4f2e4a
3
+ metadata.gz: 88d248a2fc1b72df046fde108c79b03565f66e1b
4
+ data.tar.gz: f66907aafbe1cd6c713b5a958fea7d94ad68c53d
5
5
  SHA512:
6
- metadata.gz: 07d691d25593e4660c67ef624d0b0486bb31053a5dbd7cbadd71833f2fdf0904e5823500262a9a12c7b741b20bb1558eb690cc277341f178ad8e8e7d71d929b5
7
- data.tar.gz: 03329eeb2cdf48a336685d94e4d8a2cbbcebdec16aadaf6f1bddf5e1966774a56821e354bf7caf8155f383121e2747115d0b6bacd98b172a99ea49cf38809cf7
6
+ metadata.gz: 29c840f0620434b79d8f583cdf072fc9f2a82cbff1ae98d1cba6fde434a6232b979e5a1d5a3d74e20f8340735d71b9f909218316dd6e27ad77ce6f385b0b9c9d
7
+ data.tar.gz: 0f9b6263e30be9eb827fd3915e692fd73d92c0aba8b4ef7e6d5b5f6aa8e733fffbcfa7bce3322b5f49c62351656bfc1a772e33b72c13901950f4c01c74fe0e3e
@@ -0,0 +1,9 @@
1
+ # 0.2.0
2
+
3
+ * Fixed issue where some win lines would not render correctly
4
+ * Refactor
5
+
6
+ # 0.1.0
7
+
8
+ * Initial release
9
+ * Local two player only
data/README.md CHANGED
@@ -1,13 +1,27 @@
1
- # Gomoku
1
+ # Gomoku [![Gem Version](https://badge.fury.io/rb/gomoku.svg)](https://rubygems.org/gems/gomoku) [![Build Status](https://travis-ci.org/dtcristo/gomoku.svg?branch=master)](https://travis-ci.org/dtcristo/gomoku) [![Code Climate](https://codeclimate.com/github/dtcristo/gomoku/badges/gpa.svg)](https://codeclimate.com/github/dtcristo/gomoku) [![Test Coverage](https://codeclimate.com/github/dtcristo/gomoku/badges/coverage.svg)](https://codeclimate.com/github/dtcristo/gomoku/coverage)
2
2
 
3
- Classic five-in-a-row board game
3
+ Gomoku is the classic five-in-a-row board game. Challenge a friend or take on the AI. Gomoku is built with [Gosu](https://www.libgosu.org/), the 2D game library for Ruby.
4
+
5
+ ![Screenshot](https://raw.github.com/dtcristo/gomoku/master/assets/screenshot.png)
4
6
 
5
7
  ## Installation
6
8
 
7
- Install it as a gem:
9
+ Gosu dependencies (OS X):
10
+
11
+ $ brew install sdl2 libogg libvorbis
12
+
13
+ For Linux dependencies, read [Getting Started on Linux](https://github.com/gosu/gosu/wiki/Getting-Started-on-Linux).
14
+
15
+ Install as a gem:
8
16
 
9
17
  $ gem install gomoku
10
18
 
11
- And run it:
19
+ And play:
12
20
 
13
21
  $ gomoku
22
+
23
+ ## Todo
24
+
25
+ * Build basic AI
26
+ * Add menus
27
+ * Add network play
Binary file
Binary file
Binary file
data/bin/gomoku CHANGED
@@ -3,4 +3,4 @@
3
3
  require 'gomoku'
4
4
 
5
5
  # Show the Gomoku window
6
- Gomoku::Gomoku.new.show
6
+ Gomoku::Window.new.show
@@ -1,188 +1,12 @@
1
1
  require 'gosu'
2
2
  require 'gomoku/version'
3
- require 'gomoku/utility'
4
- require 'gomoku/board'
5
- require 'gomoku/human'
6
- require 'gomoku/computer'
7
3
 
8
- class Gomoku::Gomoku < Gosu::Window
9
- def initialize
10
- super 800, 800, false
11
- self.caption = "Gomoku"
12
-
13
- @board = Board.new(self)
14
- @black_player = Human.new(self, @board, :black)
15
- @white_player = Human.new(self, @board, :white)
16
-
17
- # Start a new game
18
- new_game
19
- end
20
-
21
- def new_game
22
- # Reset the board
23
- @board.reset
24
-
25
- # Black goes first
26
- @turn = :black
27
-
28
- # Setup flag to indicate a turn needs to be processed
29
- @process_turn = false
30
-
31
- @winner = false
32
- end
33
-
34
- def needs_cursor?
35
- true
36
- end
37
-
38
- def button_down id
39
- case id
40
- when Gosu::KbEscape
41
- close
42
- when Gosu::MsLeft
43
- # If no winner, attempt a move
44
- if !@winner
45
- # Get the location of the click
46
- click_r = Utility.y_to_r mouse_y
47
- click_c = Utility.x_to_c mouse_x
48
-
49
- # Check for black space
50
- if @board.state[[click_r, click_c]] == :empty
51
- # Perform move
52
- @board.state[[click_r, click_c]] = @turn
53
- # Update turn
54
- if @turn == :black
55
- @turn = :white
56
- else
57
- @turn = :black
58
- end
59
-
60
- # Update flag
61
- @process_turn = true
62
- end
63
- else
64
- # We already have a winner, so start new game
65
- new_game
66
- end
67
- end
68
- end
69
-
70
- def button_up id
71
- end
72
-
73
- def update
74
- case @turn
75
- when :black
76
- @black_player.update
77
- when :white
78
- @white_player.update
79
- end
80
-
81
- # If a move has been made, process the turn
82
- if @process_turn
83
- # Loop through board cells and check winner, break when found
84
- catch :break do
85
- for r in (1..19)
86
- for c in (1..19)
87
- win = @board.check_win r, c
88
- if win != :none
89
- @winner = true
90
- @winner_direction = win
91
- @winner_r = r
92
- @winner_c = c
93
- throw :break
94
- end
95
- end
96
- end
97
- end
98
-
99
- # Done processing, reset flag
100
- @process_turn = false
101
- end
102
- end
103
-
104
- def draw
105
- @board.draw
106
-
107
- if !@winner
108
- case @turn
109
- when :black
110
- @black_player.draw
111
- when :white
112
- @white_player.draw
113
- end
114
- else
115
- # Winner, mark the winning sequence
116
-
117
- # Draw three adjacent 1px lines to make a single 3px line.
118
- # Worst code I ever wrote.
119
- case @winner_direction
120
- when :horizontal
121
- line_x1_1 = Utility.c_to_x(@winner_c)
122
- line_y1_1 = Utility.r_to_y(@winner_r) + 20
123
- line_x1_2 = Utility.c_to_x(@winner_c + 5)
124
- line_y1_2 = Utility.r_to_y(@winner_r) + 20
125
-
126
- line_x2_1 = line_x1_1
127
- line_y2_1 = line_y1_1 + 1
128
- line_x2_2 = line_x1_2
129
- line_y2_2 = line_y1_2 + 1
130
-
131
- line_x3_1 = line_x1_1
132
- line_y3_1 = line_y1_1 + 2
133
- line_x3_2 = line_x1_2
134
- line_y3_2 = line_y1_2 + 2
135
- when :vertical
136
- line_x1_1 = Utility.c_to_x(@winner_c) + 20
137
- line_y1_1 = Utility.r_to_y(@winner_r)
138
- line_x1_2 = Utility.c_to_x(@winner_c) + 20
139
- line_y1_2 = Utility.r_to_y(@winner_r + 5)
140
-
141
- line_x2_1 = line_x1_1 + 1
142
- line_y2_1 = line_y1_1
143
- line_x2_2 = line_x1_2 + 1
144
- line_y2_2 = line_y1_2
145
-
146
- line_x3_1 = line_x1_1 + 2
147
- line_y3_1 = line_y1_1
148
- line_x3_2 = line_x1_2 + 2
149
- line_y3_2 = line_y1_2
150
- when :diagonal_up
151
- line_x1_1 = Utility.c_to_x(@winner_c)
152
- line_y1_1 = Utility.r_to_y(@winner_r + 1)
153
- line_x1_2 = Utility.c_to_x(@winner_c + 5)
154
- line_y1_2 = Utility.r_to_y(@winner_r - 5)
155
-
156
- line_x2_1 = line_x1_1
157
- line_y2_1 = line_y1_1 + 1
158
- line_x2_2 = line_x1_2 + 1
159
- line_y2_2 = line_y1_2
160
-
161
- line_x3_1 = line_x1_1 + 1
162
- line_y3_1 = line_y1_1 + 1
163
- line_x3_2 = line_x1_2 + 1
164
- line_y3_2 = line_y1_2 + 1
165
- when :diagonal_down
166
- line_x1_1 = Utility.c_to_x(@winner_c)
167
- line_y1_1 = Utility.r_to_y(@winner_r)
168
- line_x1_2 = Utility.c_to_x(@winner_c + 5)
169
- line_y1_2 = Utility.r_to_y(@winner_r + 5)
170
-
171
- line_x2_1 = line_x1_1 + 1
172
- line_y2_1 = line_y1_1
173
- line_x2_2 = line_x1_2
174
- line_y2_2 = line_y1_2 - 1
175
-
176
- line_x3_1 = line_x1_1
177
- line_y3_1 = line_y1_1 + 1
178
- line_x3_2 = line_x1_2 - 1
179
- line_y3_2 = line_y1_2
180
- end
181
-
182
- # Render the three lines
183
- draw_line(line_x1_1, line_y1_1, Gosu::Color.argb(0xffff0000), line_x1_2, line_y1_2, Gosu::Color.argb(0xffff0000), 2, :default)
184
- draw_line(line_x2_1, line_y2_1, Gosu::Color.argb(0xffff0000), line_x2_2, line_y2_2, Gosu::Color.argb(0xffff0000), 2, :default)
185
- draw_line(line_x3_1, line_y3_1, Gosu::Color.argb(0xffff0000), line_x3_2, line_y3_2, Gosu::Color.argb(0xffff0000), 2, :default)
186
- end
187
- end
4
+ # Main Gomoku module
5
+ module Gomoku
6
+ autoload :Board, 'gomoku/board'
7
+ autoload :Computer, 'gomoku/computer'
8
+ autoload :Human, 'gomoku/human'
9
+ autoload :Player, 'gomoku/player'
10
+ autoload :Utility, 'gomoku/utility'
11
+ autoload :Window, 'gomoku/window'
188
12
  end
@@ -1,123 +1,126 @@
1
- require 'gosu'
2
- require 'gomoku/utility'
1
+ module Gomoku
2
+ # Defines the board state and rendering
3
+ class Board
4
+ attr_reader :state
3
5
 
4
- class Board
5
- attr_reader :state
6
-
7
- def initialize window
8
- # Setup sprites
9
- @grid = Gosu::Image.new(window, File.expand_path('../../../assets/grid.png', __FILE__), true)
10
- @black = Gosu::Image.new(window, File.expand_path('../../../assets/black.png', __FILE__), true)
11
- @white = Gosu::Image.new(window, File.expand_path('../../../assets/white.png', __FILE__), true)
12
- end
13
-
14
- def reset
15
- # Default value in @state is invalid move (outside grid)
16
- @state = Hash.new(:invalid)
6
+ def initialize(window)
7
+ # Setup sprites
8
+ @grid = Gosu::Image.new(window, Utility.asset_path('grid.png'), true)
9
+ @black = Gosu::Image.new(window, Utility.asset_path('black.png'), true)
10
+ @white = Gosu::Image.new(window, Utility.asset_path('white.png'), true)
11
+ @black_hover = Gosu::Image.new(window, Utility.asset_path('black_hover.png'), true)
12
+ @white_hover = Gosu::Image.new(window, Utility.asset_path('white_hover.png'), true)
13
+ end
17
14
 
18
- # Setup blank spaces within grid range
19
- for r in (1..19)
20
- for c in (1..19)
21
- @state[[r,c]] = :empty
15
+ def reset
16
+ # Default value in @state is invalid move (outside grid)
17
+ @state = Hash.new(:invalid)
18
+ # Setup blank spaces within grid range
19
+ Board.each_r_c do |r, c|
20
+ @state[[r, c]] = :empty
22
21
  end
23
22
  end
24
- end
25
23
 
26
- def draw
27
- # Draw the empty grid
28
- @grid.draw(0, 0, 0)
24
+ def draw
25
+ # Draw the empty grid
26
+ @grid.draw(0, 0, 0)
27
+ # Loop through board cells and render stones
28
+ Board.each_r_c do |r, c|
29
+ color = @state[[r, c]]
30
+ draw_stone(color, r, c)
31
+ end
32
+ end
29
33
 
30
- # Loop through board cells and render stones
31
- for r in (1..19)
32
- for c in (1..19)
33
- color = @state[[r,c]]
34
- draw_stone color, r, c
34
+ def draw_stone(color, r, c)
35
+ case color
36
+ when :black
37
+ @black.draw(Utility.c_to_x(c), Utility.r_to_y(r), 1)
38
+ when :white
39
+ @white.draw(Utility.c_to_x(c), Utility.r_to_y(r), 1)
35
40
  end
36
41
  end
37
- end
38
42
 
39
- def draw_stone color, r, c
40
- case color
41
- when :black
42
- @black.draw(Utility.c_to_x(c), Utility.r_to_y(r), 1)
43
- when :white
44
- @white.draw(Utility.c_to_x(c), Utility.r_to_y(r), 1)
43
+ def draw_hover(color, r, c)
44
+ case color
45
+ when :black
46
+ @black_hover.draw(Utility.c_to_x(c), Utility.r_to_y(r), 1)
47
+ when :white
48
+ @white_hover.draw(Utility.c_to_x(c), Utility.r_to_y(r), 1)
49
+ end
45
50
  end
46
- end
47
51
 
48
- def check_win r, c
49
- current = @state[[r,c]]
52
+ def check_win(r, c)
53
+ current = @state[[r, c]]
50
54
 
51
- # No winner if we're on an empty cell
52
- if current == :empty
53
- return :none
54
- end
55
+ # No winner if we're on an empty cell
56
+ return :none if current == :empty
55
57
 
56
- # Test horizontal sequence
57
- if c < 16
58
- count = 0
59
- (0..4).each do |offset|
60
- if @state[[r, c+offset]] == current
61
- count += 1
62
- else break
58
+ # Test horizontal sequence
59
+ if c < 16
60
+ count = 0
61
+ (0..4).each do |offset|
62
+ if @state[[r, c + offset]] == current
63
+ count += 1
64
+ else break
65
+ end
63
66
  end
67
+ # Winner found
68
+ return :horizontal if count == 5
64
69
  end
65
- # Winner found
66
- if count == 5
67
- return :horizontal
68
- end
69
- end
70
70
 
71
- # Test vertical sequence
72
- if r < 16
73
- count = 0
74
- (0..4).each do |offset|
75
- if @state[[r+offset, c]] == current
76
- count += 1
77
- else break
71
+ # Test vertical sequence
72
+ if r < 16
73
+ count = 0
74
+ (0..4).each do |offset|
75
+ if @state[[r + offset, c]] == current
76
+ count += 1
77
+ else break
78
+ end
78
79
  end
80
+ # Winner found
81
+ return :vertical if count == 5
79
82
  end
80
- # Winner found
81
- if count == 5
82
- return :vertical
83
- end
84
- end
85
83
 
86
- # Test diagonal-up sequence
87
- if r > 4 and c < 16
88
- count = 0
89
- (0..4).each do |offset|
90
- if @state[[r-offset, c+offset]] == current
91
- count += 1
92
- else break
84
+ # Test diagonal-up sequence
85
+ if r > 4 && c < 16
86
+ count = 0
87
+ (0..4).each do |offset|
88
+ if @state[[r - offset, c + offset]] == current
89
+ count += 1
90
+ else break
91
+ end
93
92
  end
93
+ # Winner found
94
+ return :diagonal_up if count == 5
94
95
  end
95
- # Winner found
96
- if count == 5
97
- return :diagonal_up
98
- end
99
- end
100
96
 
101
- # Test diagonal-down sequence
102
- if r < 16 and c < 16
103
- count = 0
104
- (0..4).each do |offset|
105
- if @state[[r+offset, c+offset]] == current
106
- count += 1
107
- else break
97
+ # Test diagonal-down sequence
98
+ if r < 16 && c < 16
99
+ count = 0
100
+ (0..4).each do |offset|
101
+ if @state[[r + offset, c + offset]] == current
102
+ count += 1
103
+ else break
104
+ end
108
105
  end
106
+ # Winner found
107
+ return :diagonal_down if count == 5
109
108
  end
110
- # Winner found
111
- if count == 5
112
- return :diagonal_down
113
- end
109
+
110
+ # No winner
111
+ :none
114
112
  end
115
113
 
116
- # No winner
117
- return :none
118
- end
114
+ def empty?(r, c)
115
+ state[[r, c]] == :empty
116
+ end
119
117
 
120
- def is_empty? r, c
121
- state[[r, c]] == :empty
118
+ def self.each_r_c
119
+ (1..19).each do |r|
120
+ (1..19).each do |c|
121
+ yield r, c
122
+ end
123
+ end
124
+ end
122
125
  end
123
126
  end
@@ -1,32 +1,43 @@
1
- require 'gomoku/player'
2
-
3
- class Computer < Player
4
- def is_human?
5
- false
6
- end
7
-
8
- def update
9
- catch :break do
10
- for r in (1..19)
11
- for c in (1..19)
1
+ module Gomoku
2
+ # Computer controlled player
3
+ class Computer < Player
4
+ def human?
5
+ false
6
+ end
12
7
 
13
- if @board.state[[r,c]] == :empty
8
+ def pick_move
9
+ @hover_r ||= 1
10
+ @hover_c ||= 1
14
11
 
15
- @board.state[[r,c]] = @window.turn
16
- # Update turn
17
- if @window.turn == :black
18
- @window.turn = :white
19
- else
20
- @window.turn = :black
21
- end
12
+ # Test position and maybe return move here
22
13
 
23
- # Update flag
24
- @window.process_turn = true
14
+ # Update hover location
15
+ unless hover_next
16
+ # No new hover
17
+ move_r = @hover_r
18
+ move_c = @hover_c
19
+ @hover_r, @hover_c = 1
20
+ end
21
+ [move_r, move_c]
22
+ end
25
23
 
26
- throw :break
27
- end
24
+ def hover_next
25
+ r = @hover_r
26
+ c = @hover_c
27
+ while r <= 19 && c <= 19
28
+ if c < 19
29
+ c += 1
30
+ else
31
+ r += 1
32
+ c = 1
33
+ end
34
+ if @board.empty?(r, c)
35
+ @hover_r = r
36
+ @hover_c = c
37
+ return true
28
38
  end
29
39
  end
40
+ false
30
41
  end
31
42
  end
32
43
  end
@@ -1,20 +1,28 @@
1
- require 'gomoku/player'
1
+ module Gomoku
2
+ # Human controlled player
3
+ class Human < Player
4
+ def human?
5
+ true
6
+ end
2
7
 
3
- class Human < Player
4
- def is_human?
5
- true
6
- end
8
+ def click(click_r, click_c)
9
+ @click_r = click_r
10
+ @click_c = click_c
11
+ end
7
12
 
8
- def update
9
- # Update mouse hover location
10
- @hover_r = Utility.y_to_r @window.mouse_y
11
- @hover_c = Utility.x_to_c @window.mouse_x
12
- end
13
+ def update
14
+ # Update mouse hover location
15
+ @hover_r = Utility.y_to_r(@window.mouse_y)
16
+ @hover_c = Utility.x_to_c(@window.mouse_x)
17
+ end
13
18
 
14
- def draw
15
- # Draw the hover for next piece
16
- if Utility.in_range?(@hover_r, @hover_c) and @board.is_empty?(@hover_r, @hover_c)
17
- @board.draw_stone @color, @hover_r, @hover_c
19
+ def pick_move
20
+ return unless @click_r && @click_c
21
+ return unless @board.empty?(@click_r, @click_c)
22
+ move_r = @click_r
23
+ move_c = @click_c
24
+ @click_r, @click_c = nil
25
+ [move_r, move_c]
18
26
  end
19
27
  end
20
28
  end
@@ -1,13 +1,27 @@
1
- class Player
2
- def initialize window, board, color
3
- @window = window
4
- @board = board
5
- @color = color
6
- end
1
+ module Gomoku
2
+ # Defines common functionality for all players
3
+ class Player
4
+ def initialize(window, board, color)
5
+ @window = window
6
+ @board = board
7
+ @color = color
8
+ end
7
9
 
8
- def update
9
- end
10
+ def click(_click_r, _click_c)
11
+ end
12
+
13
+ def update
14
+ end
15
+
16
+ def pick_move
17
+ end
10
18
 
11
- def draw
19
+ def draw
20
+ return unless @hover_r && @hover_c
21
+ return unless Utility.in_range?(@hover_r, @hover_c) &&
22
+ @board.empty?(@hover_r, @hover_c)
23
+ # Draw the hover for next piece
24
+ @board.draw_hover(@color, @hover_r, @hover_c)
25
+ end
12
26
  end
13
27
  end
@@ -1,22 +1,38 @@
1
- # Helper methods
2
- module Utility
3
- def Utility.r_to_y r
4
- r*40 - 20
5
- end
1
+ module Gomoku
2
+ # Helper methods
3
+ module Utility
4
+ module_function
6
5
 
7
- def Utility.c_to_x c
8
- c*40 - 20
9
- end
6
+ def r_to_y(r)
7
+ r * 40 - 20
8
+ end
10
9
 
11
- def Utility.x_to_c x
12
- (x.to_i + 20) / 40
13
- end
10
+ def c_to_x(c)
11
+ c * 40 - 20
12
+ end
14
13
 
15
- def Utility.y_to_r y
16
- (y.to_i + 20) / 40
17
- end
14
+ def x_to_c(x)
15
+ (x.to_i + 20) / 40
16
+ end
17
+
18
+ def y_to_r(y)
19
+ (y.to_i + 20) / 40
20
+ end
21
+
22
+ def in_range?(r, c)
23
+ r >= 1 && r <= 19 && c >= 1 && c <= 19
24
+ end
25
+
26
+ def toggle_color(color)
27
+ if color == :black
28
+ :white
29
+ else
30
+ :black
31
+ end
32
+ end
18
33
 
19
- def Utility.in_range? r, c
20
- r >= 1 and r <= 19 and c >= 1 and c <= 19
34
+ def asset_path(asset)
35
+ File.expand_path("../../../assets/#{asset}", __FILE__)
36
+ end
21
37
  end
22
38
  end
@@ -1,3 +1,4 @@
1
+ # Specifies the current gem version
1
2
  module Gomoku
2
- VERSION = '0.1.0'
3
+ VERSION = '0.2.0'
3
4
  end
@@ -0,0 +1,193 @@
1
+ module Gomoku
2
+ # Main Gomoku window and game loop
3
+ class Window < Gosu::Window
4
+ def initialize
5
+ super 800, 800, false
6
+ self.caption = 'Gomoku'
7
+ @board = Board.new(self)
8
+ @black_player = Human.new(self, @board, :black)
9
+ @white_player = Human.new(self, @board, :white)
10
+ # @white_player = Computer.new(self, @board, :white)
11
+ # Start a new game
12
+ new_game
13
+ end
14
+
15
+ def new_game
16
+ # Reset the board
17
+ @board.reset
18
+ # Black goes first
19
+ @turn = :black
20
+ # Setup flag to indicate a turn needs to be processed
21
+ @done_turn = false
22
+ @winner = false
23
+ end
24
+
25
+ def needs_cursor?
26
+ true
27
+ end
28
+
29
+ def button_down(id)
30
+ case id
31
+ when Gosu::KbEscape
32
+ close
33
+ when Gosu::MsLeft
34
+ process_click
35
+ end
36
+ end
37
+
38
+ def process_click
39
+ if @winner
40
+ # We already have a winner, so start new game
41
+ new_game
42
+ else
43
+ # Get the location of the click
44
+ click_r = Utility.y_to_r(mouse_y)
45
+ click_c = Utility.x_to_c(mouse_x)
46
+ case @turn
47
+ when :black
48
+ @black_player.click(click_r, click_c)
49
+ when :white
50
+ @white_player.click(click_r, click_c)
51
+ end
52
+ end
53
+ end
54
+
55
+ def button_up(_id)
56
+ end
57
+
58
+ def update
59
+ case @turn
60
+ when :black
61
+ @black_player.update
62
+ move = @black_player.pick_move
63
+ when :white
64
+ @white_player.update
65
+ move = @white_player.pick_move
66
+ end
67
+ # Perform the move
68
+ do_move(move) if move
69
+ # Process the turn if done
70
+ process_turn if @done_turn
71
+ end
72
+
73
+ def do_move(move)
74
+ r = move[0]
75
+ c = move[1]
76
+ # Return if not blank
77
+ return unless @board.state[[r, c]] == :empty
78
+ # Perform move
79
+ @board.state[[r, c]] = @turn
80
+ # Update turn
81
+ @turn = Utility.toggle_color(@turn)
82
+ # Update flag
83
+ @done_turn = true
84
+ end
85
+
86
+ # Loop through board cells and check winner, break when found
87
+ def process_turn
88
+ Board.each_r_c do |r, c|
89
+ win = @board.check_win(r, c)
90
+ unless win == :none
91
+ @winner = true
92
+ @winner_direction = win
93
+ @winner_r = r
94
+ @winner_c = c
95
+ break
96
+ end
97
+ end
98
+ # Done processing, reset flag
99
+ @done_turn = false
100
+ end
101
+
102
+ def draw
103
+ @board.draw
104
+ if @winner
105
+ # Mark the winning sequence
106
+ draw_winner
107
+ else
108
+ # No winner, draw the current player
109
+ case @turn
110
+ when :black
111
+ @black_player.draw
112
+ when :white
113
+ @white_player.draw
114
+ end
115
+ end
116
+ end
117
+
118
+ # Draw three adjacent 1px lines to make a single 3px line.
119
+ # Worst code I ever wrote.
120
+ def draw_winner
121
+ case @winner_direction
122
+ when :horizontal
123
+ line_x1_1 = Utility.c_to_x(@winner_c)
124
+ line_y1_1 = Utility.r_to_y(@winner_r) + 20
125
+ line_x1_2 = Utility.c_to_x(@winner_c + 5)
126
+ line_y1_2 = Utility.r_to_y(@winner_r) + 20
127
+
128
+ line_x2_1 = line_x1_1
129
+ line_y2_1 = line_y1_1 + 1
130
+ line_x2_2 = line_x1_2
131
+ line_y2_2 = line_y1_2 + 1
132
+
133
+ line_x3_1 = line_x1_1
134
+ line_y3_1 = line_y1_1 + 2
135
+ line_x3_2 = line_x1_2
136
+ line_y3_2 = line_y1_2 + 2
137
+ when :vertical
138
+ line_x1_1 = Utility.c_to_x(@winner_c) + 20
139
+ line_y1_1 = Utility.r_to_y(@winner_r)
140
+ line_x1_2 = Utility.c_to_x(@winner_c) + 20
141
+ line_y1_2 = Utility.r_to_y(@winner_r + 5)
142
+
143
+ line_x2_1 = line_x1_1 + 1
144
+ line_y2_1 = line_y1_1
145
+ line_x2_2 = line_x1_2 + 1
146
+ line_y2_2 = line_y1_2
147
+
148
+ line_x3_1 = line_x1_1 + 2
149
+ line_y3_1 = line_y1_1
150
+ line_x3_2 = line_x1_2 + 2
151
+ line_y3_2 = line_y1_2
152
+ when :diagonal_up
153
+ line_x1_1 = Utility.c_to_x(@winner_c)
154
+ line_y1_1 = Utility.r_to_y(@winner_r + 1)
155
+ line_x1_2 = Utility.c_to_x(@winner_c + 5)
156
+ line_y1_2 = Utility.r_to_y(@winner_r - 4)
157
+
158
+ line_x2_1 = line_x1_1
159
+ line_y2_1 = line_y1_1 + 1
160
+ line_x2_2 = line_x1_2 + 1
161
+ line_y2_2 = line_y1_2
162
+
163
+ line_x3_1 = line_x1_1 + 1
164
+ line_y3_1 = line_y1_1 + 1
165
+ line_x3_2 = line_x1_2 + 1
166
+ line_y3_2 = line_y1_2 + 1
167
+ when :diagonal_down
168
+ line_x1_1 = Utility.c_to_x(@winner_c)
169
+ line_y1_1 = Utility.r_to_y(@winner_r)
170
+ line_x1_2 = Utility.c_to_x(@winner_c + 5)
171
+ line_y1_2 = Utility.r_to_y(@winner_r + 5)
172
+
173
+ line_x2_1 = line_x1_1 + 1
174
+ line_y2_1 = line_y1_1
175
+ line_x2_2 = line_x1_2
176
+ line_y2_2 = line_y1_2 - 1
177
+
178
+ line_x3_1 = line_x1_1
179
+ line_y3_1 = line_y1_1 + 1
180
+ line_x3_2 = line_x1_2 - 1
181
+ line_y3_2 = line_y1_2
182
+ end
183
+
184
+ # Render the three lines
185
+ draw_line(line_x1_1, line_y1_1, Gosu::Color.argb(0xffff0000),
186
+ line_x1_2, line_y1_2, Gosu::Color.argb(0xffff0000), 2, :default)
187
+ draw_line(line_x2_1, line_y2_1, Gosu::Color.argb(0xffff0000),
188
+ line_x2_2, line_y2_2, Gosu::Color.argb(0xffff0000), 2, :default)
189
+ draw_line(line_x3_1, line_y3_1, Gosu::Color.argb(0xffff0000),
190
+ line_x3_2, line_y3_2, Gosu::Color.argb(0xffff0000), 2, :default)
191
+ end
192
+ end
193
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gomoku
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cristofaro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-19 00:00:00.000000000 Z
11
+ date: 2015-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gosu
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: codeclimate-test-reporter
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description:
84
98
  email:
85
99
  executables:
@@ -87,11 +101,15 @@ executables:
87
101
  extensions: []
88
102
  extra_rdoc_files: []
89
103
  files:
104
+ - CHANGES.md
90
105
  - LICENSE
91
106
  - README.md
92
107
  - assets/black.png
108
+ - assets/black_hover.png
93
109
  - assets/grid.png
110
+ - assets/screenshot.png
94
111
  - assets/white.png
112
+ - assets/white_hover.png
95
113
  - bin/gomoku
96
114
  - lib/gomoku.rb
97
115
  - lib/gomoku/board.rb
@@ -100,6 +118,7 @@ files:
100
118
  - lib/gomoku/player.rb
101
119
  - lib/gomoku/utility.rb
102
120
  - lib/gomoku/version.rb
121
+ - lib/gomoku/window.rb
103
122
  homepage: https://github.com/dtcristo/gomoku
104
123
  licenses:
105
124
  - MIT
@@ -110,9 +129,9 @@ require_paths:
110
129
  - lib
111
130
  required_ruby_version: !ruby/object:Gem::Requirement
112
131
  requirements:
113
- - - ">="
132
+ - - "~>"
114
133
  - !ruby/object:Gem::Version
115
- version: '0'
134
+ version: '2'
116
135
  required_rubygems_version: !ruby/object:Gem::Requirement
117
136
  requirements:
118
137
  - - ">="