gomoku 0.1.0 → 0.2.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
  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
  - - ">="