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 ADDED
@@ -0,0 +1,7 @@
1
+ source :rubygems
2
+
3
+ group :dev do # not development <-> would add unneeded development dependencies in gemspec
4
+ gem 'rake'
5
+ gem 'rspec', '~>2'
6
+ gem 'jeweler'
7
+ end
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift 'lib'
2
+ require 'tic_tac_toe'
@@ -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
@@ -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