tic_tac_toe 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.
- data/Gemfile +7 -0
- data/Gemfile.lock +26 -0
- data/Rakefile +24 -0
- data/Readme.md +23 -0
- data/VERSION +1 -0
- data/bin/tic_tac_toe +50 -0
- data/lib/tic_tac_toe.rb +77 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/tic_tac_toe_spec.rb +109 -0
- data/tic_tac_toe.gemspec +47 -0
- metadata +77 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.5.2)
|
7
|
+
bundler (~> 1.0.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
rake (0.8.7)
|
11
|
+
rspec (2.3.0)
|
12
|
+
rspec-core (~> 2.3.0)
|
13
|
+
rspec-expectations (~> 2.3.0)
|
14
|
+
rspec-mocks (~> 2.3.0)
|
15
|
+
rspec-core (2.3.1)
|
16
|
+
rspec-expectations (2.3.0)
|
17
|
+
diff-lcs (~> 1.1.2)
|
18
|
+
rspec-mocks (2.3.0)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
jeweler
|
25
|
+
rake
|
26
|
+
rspec (~> 2)
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
task :default => :spec
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
4
|
+
t.rspec_opts = '--backtrace --color'
|
5
|
+
end
|
6
|
+
|
7
|
+
task :run do
|
8
|
+
exec "./bin/tic_tac_toe"
|
9
|
+
end
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
gem.name = 'tic_tac_toe'
|
15
|
+
gem.summary = "Play Tic-Tac-Toe using Curses"
|
16
|
+
gem.email = "michael@grosser.it"
|
17
|
+
gem.homepage = "http://github.com/grosser/#{gem.name}"
|
18
|
+
gem.authors = ["Michael Grosser"]
|
19
|
+
end
|
20
|
+
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler"
|
24
|
+
end
|
data/Readme.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Play Tic-Tac-Toe using Curses(full-screen-commandline app)
|
2
|
+
More of an example app.
|
3
|
+
|
4
|
+
|
5
|
+
Install
|
6
|
+
=======
|
7
|
+
sudo gem install tic_tac_toe
|
8
|
+
|
9
|
+
Usage
|
10
|
+
=====
|
11
|
+
tic_tac_toe
|
12
|
+
|
13
|
+
Use cursor keys to select field, enter to make your mark.
|
14
|
+
|
15
|
+
TODO
|
16
|
+
=====
|
17
|
+
- AI
|
18
|
+
|
19
|
+
Author
|
20
|
+
======
|
21
|
+
[Michael Grosser](http://grosser.it)
|
22
|
+
grosser.michael@gmail.com
|
23
|
+
Hereby placed under public domain, do what you want, just do not hold me accountable...
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bin/tic_tac_toe
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'curses'
|
3
|
+
require File.expand_path('../../lib/tic_tac_toe', __FILE__)
|
4
|
+
|
5
|
+
STATUS = 10
|
6
|
+
|
7
|
+
def write(x,y,text)
|
8
|
+
Curses.setpos(y,x)
|
9
|
+
Curses.addstr(text);
|
10
|
+
end
|
11
|
+
|
12
|
+
def init_screen
|
13
|
+
Curses.noecho
|
14
|
+
Curses.init_screen
|
15
|
+
Curses.stdscr.keypad(true)
|
16
|
+
begin
|
17
|
+
yield
|
18
|
+
ensure
|
19
|
+
Curses.close_screen
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def display(ttt)
|
24
|
+
write 0,0,ttt.board
|
25
|
+
if winner = ttt.winner
|
26
|
+
write(0, STATUS, "Player #{winner} has won!!!!")
|
27
|
+
else
|
28
|
+
write(0, STATUS, "It is #{ttt.player}`s turn...")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
init_screen do
|
33
|
+
write(0, STATUS+1, "q=Quit r=Reset")
|
34
|
+
|
35
|
+
ttt = TicTacToe.new
|
36
|
+
|
37
|
+
loop do
|
38
|
+
display ttt
|
39
|
+
|
40
|
+
case Curses.getch
|
41
|
+
when Curses::Key::UP then ttt.move(0,-1)
|
42
|
+
when Curses::Key::DOWN then ttt.move(0,1)
|
43
|
+
when Curses::Key::RIGHT then ttt.move(1,0)
|
44
|
+
when Curses::Key::LEFT then ttt.move(-1,0)
|
45
|
+
when 10 then ttt.set # enter
|
46
|
+
when ?q then break
|
47
|
+
when ?r then ttt = TicTacToe.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/tic_tac_toe.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
class String
|
2
|
+
def indexes(needle)
|
3
|
+
found = []
|
4
|
+
current_index = -1
|
5
|
+
while current_index = index(needle, current_index+1)
|
6
|
+
found << current_index
|
7
|
+
end
|
8
|
+
found
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class TicTacToe
|
13
|
+
VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
|
14
|
+
|
15
|
+
BOARD = <<BOARD
|
16
|
+
-------------
|
17
|
+
| X | X | X |
|
18
|
+
-------------
|
19
|
+
| X | X | X |
|
20
|
+
-------------
|
21
|
+
| X | X | X |
|
22
|
+
-------------
|
23
|
+
BOARD
|
24
|
+
PLAYERS = ['X','O']
|
25
|
+
|
26
|
+
attr_reader :position, :player
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@fields = Array.new(9).fill(' ')
|
30
|
+
@position = 0
|
31
|
+
@player = PLAYERS.first
|
32
|
+
end
|
33
|
+
|
34
|
+
def board
|
35
|
+
index = -1
|
36
|
+
BOARD.gsub(" X ") do
|
37
|
+
index += 1
|
38
|
+
field = @fields[index]
|
39
|
+
@position == index ? "[#{field}]" : " #{field} "
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def move(x,y)
|
44
|
+
x = (@position + x) % 3
|
45
|
+
y = ((@position / 3) + y) % 3
|
46
|
+
@position = x + (y * 3)
|
47
|
+
end
|
48
|
+
|
49
|
+
def set
|
50
|
+
return if @fields[@position] != ' '
|
51
|
+
@fields[@position] = @player
|
52
|
+
switch_player
|
53
|
+
end
|
54
|
+
|
55
|
+
def winner
|
56
|
+
[
|
57
|
+
[0,1,2],[3,4,5],[6,7,8], # vertical
|
58
|
+
[0,3,6],[1,4,7],[2,5,8], # horizontal
|
59
|
+
[0,4,8],[2,4,6] # diagonal
|
60
|
+
].each do |pattern|
|
61
|
+
players = pattern.map{|i| @fields[i] }.uniq
|
62
|
+
next if players.size != 1
|
63
|
+
winner = players.first
|
64
|
+
next if winner == ' '
|
65
|
+
return winner
|
66
|
+
end
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def switch_player
|
73
|
+
current_player = PLAYERS.index(@player)
|
74
|
+
next_player = (current_player + 1) % PLAYERS.size
|
75
|
+
@player = PLAYERS[next_player]
|
76
|
+
end
|
77
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require File.expand_path('spec/spec_helper')
|
2
|
+
|
3
|
+
describe TicTacToe do
|
4
|
+
def ttt; subject; end
|
5
|
+
|
6
|
+
board_width = 14
|
7
|
+
|
8
|
+
it "has a VERSION" do
|
9
|
+
TicTacToe::VERSION.should =~ /^\d+\.\d+\.\d+$/
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'on startup' do
|
13
|
+
it "should draw an empty board on startup" do
|
14
|
+
ttt.board.should_not include('X')
|
15
|
+
ttt.board.should_not include('O')
|
16
|
+
ttt.board.size.should == board_width * 7
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should position the cursor in the first position" do
|
20
|
+
ttt.board.indexes('[ ]').should == [board_width+1]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe :move do
|
25
|
+
{
|
26
|
+
[0,0] => 0,
|
27
|
+
[1,0] => 1,
|
28
|
+
[3,0] => 0,
|
29
|
+
[-1,0] => 2,
|
30
|
+
[0,1] => 3,
|
31
|
+
[0,3] => 0,
|
32
|
+
[0,-1] => 6,
|
33
|
+
}.each do |move,position|
|
34
|
+
it "is at position #{position} when moving from origin to #{move}" do
|
35
|
+
ttt = TicTacToe.new
|
36
|
+
ttt.move(*move)
|
37
|
+
ttt.position.should == position
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "updates the cursor" do
|
42
|
+
ttt.move(1,1)
|
43
|
+
ttt.board.index('[ ]').should == (board_width*3) + 5
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe :set do
|
48
|
+
it "marks the field for the current player" do
|
49
|
+
ttt.set
|
50
|
+
ttt.board.index('[X]').should == board_width + 1
|
51
|
+
end
|
52
|
+
|
53
|
+
it "switches the player" do
|
54
|
+
ttt.player.should == 'X'
|
55
|
+
ttt.set
|
56
|
+
ttt.player.should == 'O'
|
57
|
+
ttt.move(1,0)
|
58
|
+
ttt.set
|
59
|
+
ttt.player.should == 'X'
|
60
|
+
end
|
61
|
+
|
62
|
+
it "does not set an occupied field" do
|
63
|
+
ttt.set
|
64
|
+
ttt.set
|
65
|
+
ttt.board.index('[O]').should == nil
|
66
|
+
end
|
67
|
+
|
68
|
+
it "does not switch players when setting an occupied field" do
|
69
|
+
ttt.set
|
70
|
+
ttt.set
|
71
|
+
ttt.player.should == 'O'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe :winner do
|
76
|
+
def set_fields(a)
|
77
|
+
ttt.instance_eval{@fields = a}
|
78
|
+
end
|
79
|
+
|
80
|
+
it "is nil when no-one has set" do
|
81
|
+
ttt.winner.should == nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it "is nil when no-one has won" do
|
85
|
+
set_fields ['O','X','O', 'O','X','O', 'X','O','X']
|
86
|
+
ttt.winner.should == nil
|
87
|
+
end
|
88
|
+
|
89
|
+
it "finds diagonal" do
|
90
|
+
set_fields ['X','O',' ', ' ','X',' ', ' ','O','X']
|
91
|
+
ttt.winner.should == 'X'
|
92
|
+
end
|
93
|
+
|
94
|
+
it "finds vertical" do
|
95
|
+
set_fields ['X','O',' ', ' ','O',' ', ' ','O','X']
|
96
|
+
ttt.winner.should == 'O'
|
97
|
+
end
|
98
|
+
|
99
|
+
it "finds horizontal" do
|
100
|
+
set_fields ['X','O',' ', 'O','O','O', ' ','X','X']
|
101
|
+
ttt.winner.should == 'O'
|
102
|
+
end
|
103
|
+
|
104
|
+
it "finds multiple" do
|
105
|
+
set_fields ['O','O','O', 'X','O','X', ' ','X','O']
|
106
|
+
ttt.winner.should == 'O'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/tic_tac_toe.gemspec
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{tic_tac_toe}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Michael Grosser"]
|
12
|
+
s.date = %q{2010-12-31}
|
13
|
+
s.default_executable = %q{tic_tac_toe}
|
14
|
+
s.email = %q{michael@grosser.it}
|
15
|
+
s.executables = ["tic_tac_toe"]
|
16
|
+
s.files = [
|
17
|
+
"Gemfile",
|
18
|
+
"Gemfile.lock",
|
19
|
+
"Rakefile",
|
20
|
+
"Readme.md",
|
21
|
+
"VERSION",
|
22
|
+
"bin/tic_tac_toe",
|
23
|
+
"lib/tic_tac_toe.rb",
|
24
|
+
"spec/spec_helper.rb",
|
25
|
+
"spec/tic_tac_toe_spec.rb",
|
26
|
+
"tic_tac_toe.gemspec"
|
27
|
+
]
|
28
|
+
s.homepage = %q{http://github.com/grosser/tic_tac_toe}
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
s.rubygems_version = %q{1.3.7}
|
31
|
+
s.summary = %q{Play Tic-Tac-Toe using Curses}
|
32
|
+
s.test_files = [
|
33
|
+
"spec/spec_helper.rb",
|
34
|
+
"spec/tic_tac_toe_spec.rb"
|
35
|
+
]
|
36
|
+
|
37
|
+
if s.respond_to? :specification_version then
|
38
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
39
|
+
s.specification_version = 3
|
40
|
+
|
41
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
42
|
+
else
|
43
|
+
end
|
44
|
+
else
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tic_tac_toe
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Michael Grosser
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-12-31 00:00:00 +01:00
|
19
|
+
default_executable: tic_tac_toe
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description:
|
23
|
+
email: michael@grosser.it
|
24
|
+
executables:
|
25
|
+
- tic_tac_toe
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- Gemfile
|
32
|
+
- Gemfile.lock
|
33
|
+
- Rakefile
|
34
|
+
- Readme.md
|
35
|
+
- VERSION
|
36
|
+
- bin/tic_tac_toe
|
37
|
+
- lib/tic_tac_toe.rb
|
38
|
+
- spec/spec_helper.rb
|
39
|
+
- spec/tic_tac_toe_spec.rb
|
40
|
+
- tic_tac_toe.gemspec
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://github.com/grosser/tic_tac_toe
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
hash: 3
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 3
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.3.7
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: Play Tic-Tac-Toe using Curses
|
75
|
+
test_files:
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
- spec/tic_tac_toe_spec.rb
|