oxo 0.1.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 +7 -0
- data/README.md +42 -0
- data/Rakefile +27 -0
- data/bin/oxo +5 -0
- data/lib/oxo.rb +175 -0
- data/lib/oxo/board.rb +72 -0
- data/lib/oxo/computer.rb +21 -0
- data/lib/oxo/human.rb +46 -0
- data/lib/oxo/version.rb +5 -0
- data/oxo.gemspec +40 -0
- data/test/test_board.rb +15 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 57d6bbd4f6bdd8eefcd5c93ec1db4645b9ee8cc3
|
4
|
+
data.tar.gz: 1a5f97f7dbb659b20951af02d1bddc5852b518f3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 31d6af29d95dfd648649b8f55906d1909b86fa4b8f1ef1fa9ce8160c36fc75b3cebb7eafa2e7a2f4171742e48be48ad380ee618e7e2971594fdddb3e9b016302
|
7
|
+
data.tar.gz: 475eb3b11dc66209b9c5d4ca76be472dbdd7de717f081191b6de95057f20f349f41e85ec263a12151cb9a7c3af07b27ef7951a6739f705e46cc651be5807377e
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
oxo
|
2
|
+
===
|
3
|
+
|
4
|
+
`oxo` is a command line Tic-tac-toe game written in [Ruby][ruby].
|
5
|
+
|
6
|
+
## Getting Started
|
7
|
+
|
8
|
+
Start a game with
|
9
|
+
|
10
|
+
``` sh
|
11
|
+
$ oxo
|
12
|
+
```
|
13
|
+
|
14
|
+
and have fun!
|
15
|
+
|
16
|
+
## Documentation
|
17
|
+
|
18
|
+
Use `oxo --help` to display a brief help message.
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Use `gem install oxo` to install from RubyGems.org.
|
23
|
+
|
24
|
+
## Requirements
|
25
|
+
|
26
|
+
- [Ruby][ruby] 2.0.0 or higher
|
27
|
+
|
28
|
+
## Reporting Bugs
|
29
|
+
|
30
|
+
Report bugs on the `oxo` home page: <https://github.com/stomar/oxo/>
|
31
|
+
|
32
|
+
## License
|
33
|
+
|
34
|
+
Copyright © 2016 Marcus Stollsteimer
|
35
|
+
|
36
|
+
`oxo` is free software: you can redistribute it and/or modify it under
|
37
|
+
the terms of the GNU General Public License version 3 or later (GPLv3+),
|
38
|
+
see [www.gnu.org/licenses/gpl.html](http://www.gnu.org/licenses/gpl.html).
|
39
|
+
There is NO WARRANTY, to the extent permitted by law.
|
40
|
+
|
41
|
+
|
42
|
+
[ruby]: https://www.ruby-lang.org/
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "rake/testtask"
|
2
|
+
|
3
|
+
|
4
|
+
def gemspec_file
|
5
|
+
"oxo.gemspec"
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
task :default => [:test]
|
10
|
+
|
11
|
+
Rake::TestTask.new do |t|
|
12
|
+
t.pattern = "test/**/test_*.rb"
|
13
|
+
t.verbose = true
|
14
|
+
t.warning = true
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
desc "Build gem"
|
19
|
+
task :build do
|
20
|
+
sh "gem build #{gemspec_file}"
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
desc "Remove generated files"
|
25
|
+
task :clean do
|
26
|
+
FileUtils.rm(Dir.glob("*.gem"))
|
27
|
+
end
|
data/bin/oxo
ADDED
data/lib/oxo.rb
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
require "oxo/version"
|
4
|
+
require "oxo/board"
|
5
|
+
require "oxo/computer"
|
6
|
+
require "oxo/human"
|
7
|
+
|
8
|
+
# == Name
|
9
|
+
#
|
10
|
+
# oxo - a command line Tic-tac-toe game
|
11
|
+
#
|
12
|
+
# == See also
|
13
|
+
#
|
14
|
+
# Use <tt>oxo --help</tt> to display a brief help message.
|
15
|
+
#
|
16
|
+
# The full documentation for +oxo+ is available on the
|
17
|
+
# project home page.
|
18
|
+
#
|
19
|
+
# == Author
|
20
|
+
#
|
21
|
+
# Copyright (C) 2016 Marcus Stollsteimer
|
22
|
+
#
|
23
|
+
# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
24
|
+
#
|
25
|
+
module OXO
|
26
|
+
|
27
|
+
PROGNAME = "oxo"
|
28
|
+
|
29
|
+
COPYRIGHT = <<-copyright.gsub(/^ +/, "")
|
30
|
+
Copyright (C) 2016 Marcus Stollsteimer.
|
31
|
+
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
32
|
+
This is free software: you are free to change and redistribute it.
|
33
|
+
There is NO WARRANTY, to the extent permitted by law.
|
34
|
+
copyright
|
35
|
+
|
36
|
+
|
37
|
+
class Optionparser
|
38
|
+
|
39
|
+
# Parses the command line options from +argv+.
|
40
|
+
# (+argv+ is cleared).
|
41
|
+
# Might print out help or version information.
|
42
|
+
#
|
43
|
+
# +argv+ - array with the command line options
|
44
|
+
#
|
45
|
+
# Returns a hash containing the option parameters.
|
46
|
+
def self.parse!(argv)
|
47
|
+
|
48
|
+
options = {
|
49
|
+
:delay => 0
|
50
|
+
}
|
51
|
+
|
52
|
+
opt_parser = OptionParser.new do |opt|
|
53
|
+
opt.banner = "Usage: #{PROGNAME} [options]"
|
54
|
+
opt.separator %q{
|
55
|
+
oxo is a command line Tic-tac-toe game.
|
56
|
+
|
57
|
+
Options:
|
58
|
+
}.gsub(/^ +/, "")
|
59
|
+
|
60
|
+
# process --version and --help first,
|
61
|
+
# exit successfully (GNU Coding Standards)
|
62
|
+
opt.on_tail("-h", "--help", "Print a brief help message and exit.") do
|
63
|
+
puts opt_parser
|
64
|
+
puts "\nReport bugs on the #{PROGNAME} home page: <#{HOMEPAGE}>"
|
65
|
+
exit
|
66
|
+
end
|
67
|
+
|
68
|
+
opt.on_tail("-v", "--version",
|
69
|
+
"Print a brief version information and exit.") do
|
70
|
+
puts "#{PROGNAME} #{VERSION}"
|
71
|
+
puts COPYRIGHT
|
72
|
+
exit
|
73
|
+
end
|
74
|
+
|
75
|
+
opt.on("-d", "--delay SECONDS", Float,
|
76
|
+
"Set delay time for oxo's moves.") do |d|
|
77
|
+
options[:delay] = d
|
78
|
+
end
|
79
|
+
|
80
|
+
opt.separator ""
|
81
|
+
end
|
82
|
+
opt_parser.parse!(argv)
|
83
|
+
|
84
|
+
# nothing should be left in argv
|
85
|
+
raise(ArgumentError, "wrong number of arguments") unless argv.empty?
|
86
|
+
|
87
|
+
options
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
class Application
|
93
|
+
|
94
|
+
ERRORCODE = {:general => 1, :usage => 2}
|
95
|
+
|
96
|
+
def initialize
|
97
|
+
begin
|
98
|
+
options = Optionparser.parse!(ARGV)
|
99
|
+
rescue => e
|
100
|
+
usage_fail(e.message)
|
101
|
+
end
|
102
|
+
|
103
|
+
@delay = options[:delay]
|
104
|
+
end
|
105
|
+
|
106
|
+
def run
|
107
|
+
board = Board.new
|
108
|
+
|
109
|
+
case beginning_side
|
110
|
+
when :quit
|
111
|
+
return
|
112
|
+
when :human
|
113
|
+
players = [Human.new(:X), Computer.new(:O, delay: @delay)]
|
114
|
+
puts board
|
115
|
+
when :computer
|
116
|
+
players = [Computer.new(:X, delay: @delay), Human.new(:O)]
|
117
|
+
end
|
118
|
+
|
119
|
+
game_over = false
|
120
|
+
|
121
|
+
until game_over
|
122
|
+
player = players.first
|
123
|
+
move = player.make_move(board)
|
124
|
+
|
125
|
+
break if move == :quit
|
126
|
+
|
127
|
+
board.place(player.color, move[0], move[1])
|
128
|
+
|
129
|
+
puts board
|
130
|
+
puts "Move of #{player.name} was: #{(move[0] - 1) * 3 + move[1]}"
|
131
|
+
|
132
|
+
if board.win?(player.color)
|
133
|
+
puts "#{player.name} wins!"
|
134
|
+
game_over = true
|
135
|
+
elsif board.full?
|
136
|
+
puts "It's a draw."
|
137
|
+
game_over = true
|
138
|
+
end
|
139
|
+
|
140
|
+
players.rotate!
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def beginning_side
|
147
|
+
choices = {
|
148
|
+
"1" => :human, "" => :human,
|
149
|
+
"2" => :computer,
|
150
|
+
"0" => :quit, "q" => :quit
|
151
|
+
}
|
152
|
+
|
153
|
+
answer = nil
|
154
|
+
until choices.keys.include?(answer)
|
155
|
+
print "Beginning side (1=Human, 2=Computer, 0/q=quit)? "
|
156
|
+
answer = gets.chomp
|
157
|
+
end
|
158
|
+
|
159
|
+
choices[answer]
|
160
|
+
end
|
161
|
+
|
162
|
+
# Prints an error message and exits.
|
163
|
+
def general_fail(message)
|
164
|
+
warn "#{PROGNAME}: #{message}"
|
165
|
+
exit ERRORCODE[:general]
|
166
|
+
end
|
167
|
+
|
168
|
+
# Prints an error message and a short help information, then exits.
|
169
|
+
def usage_fail(message)
|
170
|
+
warn "#{PROGNAME}: #{message}"
|
171
|
+
warn "Use `#{PROGNAME} --help' for valid options."
|
172
|
+
exit ERRORCODE[:usage]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
data/lib/oxo/board.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
module OXO
|
2
|
+
class Board
|
3
|
+
|
4
|
+
attr_accessor :rows, :cols
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@rows, @cols = 3, 3
|
8
|
+
@board = Array.new(@rows) { Array.new(@cols) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def legal_move?(row, col)
|
12
|
+
on_board?(row, col) && !piece_at(row, col)
|
13
|
+
end
|
14
|
+
|
15
|
+
def place(color, row, col)
|
16
|
+
return unless legal_move?(row, col)
|
17
|
+
@board[row-1][col-1] = color
|
18
|
+
end
|
19
|
+
|
20
|
+
def legal_moves
|
21
|
+
empty_squares = []
|
22
|
+
|
23
|
+
1.upto(rows) do |row|
|
24
|
+
1.upto(cols) do |col|
|
25
|
+
empty_squares << [row, col] unless piece_at(row, col)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
empty_squares
|
30
|
+
end
|
31
|
+
|
32
|
+
def full?
|
33
|
+
!@board.flatten.include? nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def win?(color)
|
37
|
+
@board.each {|row| return true if row.uniq == [color] }
|
38
|
+
@board.transpose.each {|col| return true if col.uniq == [color] }
|
39
|
+
return true if @board.flatten.values_at(0, 4, 8).uniq == [color]
|
40
|
+
return true if @board.flatten.values_at(2, 4, 6).uniq == [color]
|
41
|
+
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
output = "\n"
|
47
|
+
hline = "+---" * @cols << "+\n"
|
48
|
+
|
49
|
+
characters = @board.map {|row| row.map {|pos| pos.to_s.ljust(1) } }
|
50
|
+
|
51
|
+
output << hline
|
52
|
+
characters.each do |row|
|
53
|
+
output << "| " << row.join(" | ") << " |" << "\n"
|
54
|
+
output << hline
|
55
|
+
end
|
56
|
+
|
57
|
+
output + "\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def on_board?(row, col)
|
63
|
+
(1..@rows).include?(row) && (1..@cols).include?(col)
|
64
|
+
end
|
65
|
+
|
66
|
+
def piece_at(row, col)
|
67
|
+
return unless on_board?(row, col)
|
68
|
+
|
69
|
+
@board[row-1][col-1]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/oxo/computer.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module OXO
|
2
|
+
class Computer
|
3
|
+
|
4
|
+
attr_reader :color
|
5
|
+
|
6
|
+
def initialize(color, delay: 0)
|
7
|
+
@color = color
|
8
|
+
@delay = delay
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
"oxo"
|
13
|
+
end
|
14
|
+
|
15
|
+
def make_move(board)
|
16
|
+
sleep @delay
|
17
|
+
|
18
|
+
board.legal_moves.sample
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/oxo/human.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module OXO
|
2
|
+
class Human
|
3
|
+
|
4
|
+
attr_reader :color
|
5
|
+
|
6
|
+
def initialize(color)
|
7
|
+
@color = color
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
"Human"
|
12
|
+
end
|
13
|
+
|
14
|
+
def make_move(board)
|
15
|
+
move = :illegal
|
16
|
+
|
17
|
+
while move == :illegal
|
18
|
+
print "Your move (1...9, 0/q=quit)? "
|
19
|
+
answer = gets.chomp
|
20
|
+
|
21
|
+
move = parse_answer(answer, board)
|
22
|
+
|
23
|
+
puts "Illegal move: #{answer}" if move == :illegal
|
24
|
+
end
|
25
|
+
|
26
|
+
move
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def parse_answer(answer, board)
|
32
|
+
case answer
|
33
|
+
when "0", "q", "quit"
|
34
|
+
:quit
|
35
|
+
when /\d/
|
36
|
+
number = answer.to_i
|
37
|
+
row = (number - 1) / board.rows + 1
|
38
|
+
col = (number - 1) % board.cols + 1
|
39
|
+
|
40
|
+
board.legal_move?(row, col) ? [row, col] : :illegal
|
41
|
+
else
|
42
|
+
:illegal
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/oxo/version.rb
ADDED
data/oxo.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative "lib/oxo/version"
|
2
|
+
|
3
|
+
version = OXO::VERSION
|
4
|
+
date = OXO::DATE
|
5
|
+
homepage = OXO::HOMEPAGE
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "oxo"
|
9
|
+
s.version = version
|
10
|
+
s.date = date
|
11
|
+
|
12
|
+
s.summary = "oxo is a command line Tic-tac-toe game."
|
13
|
+
s.description = s.summary
|
14
|
+
|
15
|
+
s.authors = ["Marcus Stollsteimer"]
|
16
|
+
s.email = "sto.mar@web.de"
|
17
|
+
s.homepage = homepage
|
18
|
+
|
19
|
+
s.license = "GPL-3.0"
|
20
|
+
|
21
|
+
s.required_ruby_version = ">= 2.0.0"
|
22
|
+
|
23
|
+
s.add_development_dependency "rake", "~> 11.1"
|
24
|
+
s.add_development_dependency "minitest", "~> 5.8"
|
25
|
+
|
26
|
+
s.executables = ["oxo"]
|
27
|
+
s.bindir = "bin"
|
28
|
+
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
|
31
|
+
s.files = %w[
|
32
|
+
oxo.gemspec
|
33
|
+
README.md
|
34
|
+
Rakefile
|
35
|
+
] +
|
36
|
+
Dir.glob("{bin,lib,test}/**/*")
|
37
|
+
|
38
|
+
s.extra_rdoc_files = %w[README.md]
|
39
|
+
s.rdoc_options = ["--charset=UTF-8", "--main=README.md"]
|
40
|
+
end
|
data/test/test_board.rb
ADDED
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oxo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Marcus Stollsteimer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-04-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '11.1'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '11.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.8'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.8'
|
41
|
+
description: oxo is a command line Tic-tac-toe game.
|
42
|
+
email: sto.mar@web.de
|
43
|
+
executables:
|
44
|
+
- oxo
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files:
|
47
|
+
- README.md
|
48
|
+
files:
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- bin/oxo
|
52
|
+
- lib/oxo.rb
|
53
|
+
- lib/oxo/board.rb
|
54
|
+
- lib/oxo/computer.rb
|
55
|
+
- lib/oxo/human.rb
|
56
|
+
- lib/oxo/version.rb
|
57
|
+
- oxo.gemspec
|
58
|
+
- test/test_board.rb
|
59
|
+
homepage: https://github.com/stomar/oxo/
|
60
|
+
licenses:
|
61
|
+
- GPL-3.0
|
62
|
+
metadata: {}
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options:
|
65
|
+
- "--charset=UTF-8"
|
66
|
+
- "--main=README.md"
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 2.0.0
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 2.5.1
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: oxo is a command line Tic-tac-toe game.
|
85
|
+
test_files: []
|