bashrw_ttt 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.
Files changed (130) hide show
  1. data/bin/play.rb +10 -0
  2. data/lib/ttt/ai.rb +33 -0
  3. data/lib/ttt/ai_easy.rb +17 -0
  4. data/lib/ttt/ai_hard.rb +21 -0
  5. data/lib/ttt/ai_medium.rb +21 -0
  6. data/lib/ttt/ai_medium_back.rb +58 -0
  7. data/lib/ttt/board.rb +37 -0
  8. data/lib/ttt/config_helper.rb +53 -0
  9. data/lib/ttt/config_options.rb +27 -0
  10. data/lib/ttt/context.rb +214 -0
  11. data/lib/ttt/four_by_four.rb +62 -0
  12. data/lib/ttt/game.rb +94 -0
  13. data/lib/ttt/game_history.rb +37 -0
  14. data/lib/ttt/game_interactor.rb +126 -0
  15. data/lib/ttt/human.rb +12 -0
  16. data/lib/ttt/interfaces/cli/lib/cli/board_selection.rb +34 -0
  17. data/lib/ttt/interfaces/cli/lib/cli/cli_game.rb +186 -0
  18. data/lib/ttt/interfaces/cli/lib/cli/cli_presenter.rb +216 -0
  19. data/lib/ttt/interfaces/cli/lib/cli/clio.rb +17 -0
  20. data/lib/ttt/interfaces/cli/lib/cli/play_again.rb +38 -0
  21. data/lib/ttt/interfaces/cli/lib/cli/player_selection.rb +43 -0
  22. data/lib/ttt/interfaces/cli/lib/cli/selection.rb +8 -0
  23. data/lib/ttt/interfaces/cli/lib/cli/walk_history.rb +48 -0
  24. data/lib/ttt/interfaces/cli/spec/cli/board_selection_spec.rb +29 -0
  25. data/lib/ttt/interfaces/cli/spec/cli/cli_game_spec.rb +376 -0
  26. data/lib/ttt/interfaces/cli/spec/cli/cli_presenter_spec.rb +147 -0
  27. data/lib/ttt/interfaces/cli/spec/cli/play_again_spec.rb +39 -0
  28. data/lib/ttt/interfaces/cli/spec/cli/player_selection_spec.rb +62 -0
  29. data/lib/ttt/interfaces/cli/spec/cli/walk_history_spec.rb +115 -0
  30. data/lib/ttt/interfaces/cli/spec/spec_helper.rb +14 -0
  31. data/lib/ttt/interfaces/limelight/four_by_four/props.rb +1 -0
  32. data/lib/ttt/interfaces/limelight/four_by_four/styles.rb +74 -0
  33. data/lib/ttt/interfaces/limelight/four_by_four_finished/props.rb +1 -0
  34. data/lib/ttt/interfaces/limelight/four_by_four_finished/styles.rb +74 -0
  35. data/lib/ttt/interfaces/limelight/game_list/players/load_button.rb +10 -0
  36. data/lib/ttt/interfaces/limelight/game_list/props.rb +17 -0
  37. data/lib/ttt/interfaces/limelight/game_list/styles.rb +8 -0
  38. data/lib/ttt/interfaces/limelight/main_menu/players/exit_ttt.rb +3 -0
  39. data/lib/ttt/interfaces/limelight/main_menu/players/load_game.rb +3 -0
  40. data/lib/ttt/interfaces/limelight/main_menu/players/new_game.rb +3 -0
  41. data/lib/ttt/interfaces/limelight/main_menu/props.rb +17 -0
  42. data/lib/ttt/interfaces/limelight/new_game/players/board_type.rb +1 -0
  43. data/lib/ttt/interfaces/limelight/new_game/players/new_game.rb +5 -0
  44. data/lib/ttt/interfaces/limelight/new_game/players/player_type.rb +1 -0
  45. data/lib/ttt/interfaces/limelight/new_game/players/setup_button.rb +21 -0
  46. data/lib/ttt/interfaces/limelight/new_game/props.rb +21 -0
  47. data/lib/ttt/interfaces/limelight/new_game/styles.rb +23 -0
  48. data/lib/ttt/interfaces/limelight/partials/board_partial.rb +14 -0
  49. data/lib/ttt/interfaces/limelight/partials/menu_button_partial.rb +5 -0
  50. data/lib/ttt/interfaces/limelight/partials/move_history_partial.rb +6 -0
  51. data/lib/ttt/interfaces/limelight/partials/title_history_partial.rb +10 -0
  52. data/lib/ttt/interfaces/limelight/players/board.rb +3 -0
  53. data/lib/ttt/interfaces/limelight/players/game.rb +4 -0
  54. data/lib/ttt/interfaces/limelight/players/generic_move_history.rb +5 -0
  55. data/lib/ttt/interfaces/limelight/players/generic_player.rb +8 -0
  56. data/lib/ttt/interfaces/limelight/players/left_button.rb +3 -0
  57. data/lib/ttt/interfaces/limelight/players/main_menu.rb +3 -0
  58. data/lib/ttt/interfaces/limelight/players/right_button.rb +3 -0
  59. data/lib/ttt/interfaces/limelight/playscripts/game_playscript.rb +169 -0
  60. data/lib/ttt/interfaces/limelight/production.rb +14 -0
  61. data/lib/ttt/interfaces/limelight/spec/game_playscript_spec.rb +218 -0
  62. data/lib/ttt/interfaces/limelight/spec/main_menu/main_menu_spec.rb +38 -0
  63. data/lib/ttt/interfaces/limelight/spec/new_game/new_game_spec.rb +45 -0
  64. data/lib/ttt/interfaces/limelight/spec/spec_helper.rb +8 -0
  65. data/lib/ttt/interfaces/limelight/stages.rb +6 -0
  66. data/lib/ttt/interfaces/limelight/styles.rb +119 -0
  67. data/lib/ttt/interfaces/limelight/three_by_three/props.rb +1 -0
  68. data/lib/ttt/interfaces/limelight/three_by_three/styles.rb +39 -0
  69. data/lib/ttt/interfaces/limelight/three_by_three_by_three/props.rb +1 -0
  70. data/lib/ttt/interfaces/limelight/three_by_three_by_three/styles.rb +119 -0
  71. data/lib/ttt/interfaces/limelight/three_by_three_by_three_finished/props.rb +1 -0
  72. data/lib/ttt/interfaces/limelight/three_by_three_by_three_finished/styles.rb +119 -0
  73. data/lib/ttt/interfaces/limelight/three_by_three_finished/props.rb +1 -0
  74. data/lib/ttt/interfaces/limelight/three_by_three_finished/styles.rb +39 -0
  75. data/lib/ttt/interfaces/rails/app/controllers/application_controller.rb +3 -0
  76. data/lib/ttt/interfaces/rails/app/controllers/ttt_games_controller.rb +86 -0
  77. data/lib/ttt/interfaces/rails/app/helpers/application_helper.rb +2 -0
  78. data/lib/ttt/interfaces/rails/app/models/ttt_game.rb +34 -0
  79. data/lib/ttt/interfaces/rails/app/presenters/web_game_presenter.rb +159 -0
  80. data/lib/ttt/interfaces/rails/autotest/discover.rb +1 -0
  81. data/lib/ttt/interfaces/rails/config/application.rb +67 -0
  82. data/lib/ttt/interfaces/rails/config/boot.rb +6 -0
  83. data/lib/ttt/interfaces/rails/config/environment.rb +5 -0
  84. data/lib/ttt/interfaces/rails/config/environments/development.rb +37 -0
  85. data/lib/ttt/interfaces/rails/config/environments/production.rb +67 -0
  86. data/lib/ttt/interfaces/rails/config/environments/test.rb +37 -0
  87. data/lib/ttt/interfaces/rails/config/initializers/backtrace_silencers.rb +7 -0
  88. data/lib/ttt/interfaces/rails/config/initializers/inflections.rb +15 -0
  89. data/lib/ttt/interfaces/rails/config/initializers/mime_types.rb +5 -0
  90. data/lib/ttt/interfaces/rails/config/initializers/secret_token.rb +7 -0
  91. data/lib/ttt/interfaces/rails/config/initializers/session_store.rb +8 -0
  92. data/lib/ttt/interfaces/rails/config/initializers/wrap_parameters.rb +14 -0
  93. data/lib/ttt/interfaces/rails/config/routes.rb +49 -0
  94. data/lib/ttt/interfaces/rails/db/schema.rb +28 -0
  95. data/lib/ttt/interfaces/rails/db/seeds.rb +7 -0
  96. data/lib/ttt/interfaces/rails/spec/controllers/ttt_games_controller_spec.rb +211 -0
  97. data/lib/ttt/interfaces/rails/spec/models/ttt_game_spec.rb +76 -0
  98. data/lib/ttt/interfaces/rails/spec/presenters/web_game_presenter_spec.rb +52 -0
  99. data/lib/ttt/interfaces/rails/spec/spec_helper.rb +13 -0
  100. data/lib/ttt/interfaces/web_interface/html_generator.rb +76 -0
  101. data/lib/ttt/interfaces/web_interface/web_game_presenter.rb +0 -0
  102. data/lib/ttt/minimax.rb +46 -0
  103. data/lib/ttt/move_history.rb +10 -0
  104. data/lib/ttt/move_traverser.rb +49 -0
  105. data/lib/ttt/player.rb +15 -0
  106. data/lib/ttt/riak_db.rb +53 -0
  107. data/lib/ttt/setup.rb +59 -0
  108. data/lib/ttt/three_by_three.rb +35 -0
  109. data/lib/ttt/three_by_three_by_three.rb +37 -0
  110. data/spec/spec_helper.rb +22 -0
  111. data/spec/ttt/ai_easy_spec.rb +15 -0
  112. data/spec/ttt/ai_hard_spec.rb +76 -0
  113. data/spec/ttt/ai_medium_spec.rb +65 -0
  114. data/spec/ttt/ai_spec.rb +50 -0
  115. data/spec/ttt/board_spec.rb +96 -0
  116. data/spec/ttt/config_helper_spec.rb +54 -0
  117. data/spec/ttt/context_spec.rb +398 -0
  118. data/spec/ttt/four_by_four_spec.rb +112 -0
  119. data/spec/ttt/game_history_spec.rb +41 -0
  120. data/spec/ttt/game_interactor_spec.rb +197 -0
  121. data/spec/ttt/game_spec.rb +246 -0
  122. data/spec/ttt/human_spec.rb +18 -0
  123. data/spec/ttt/move_history_spec.rb +13 -0
  124. data/spec/ttt/move_traverser_spec.rb +75 -0
  125. data/spec/ttt/player_spec.rb +13 -0
  126. data/spec/ttt/riak_db_spec.rb +64 -0
  127. data/spec/ttt/setup_spec.rb +63 -0
  128. data/spec/ttt/three_by_three_by_three_spec.rb +130 -0
  129. data/spec/ttt/three_by_three_spec.rb +110 -0
  130. metadata +238 -0
@@ -0,0 +1,18 @@
1
+ module TTT
2
+ describe Human do
3
+ let(:human) { Human.new(side: "x") }
4
+ let(:game) { Game.new(view: view, board: board) }
5
+
6
+ describe "#no_gui?" do
7
+ it "returns false" do
8
+ human.no_gui?.should == false
9
+ end
10
+ end
11
+
12
+ describe "#prompt" do
13
+ it "returns 'Player thinking'" do
14
+ human.prompt.should == "Enter move:"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ module TTT
4
+ describe MoveHistory do
5
+ describe "#new" do
6
+ it "returns a new TTT::MoveHistory object with side and move attributes" do
7
+ move_history = described_class.new(side: "x", move: 0)
8
+ move_history.side.should == "x"
9
+ move_history.move.should == 0
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ module TTT
4
+ describe MoveTraverser do
5
+ let(:board) { ThreeByThree.new }
6
+ let(:game_history) { GameHistory.new }
7
+ let(:traverser) { game_history.move_traverser }
8
+
9
+ context do
10
+ before(:each) do
11
+ game_history.record_move(0, 'x')
12
+ game_history.record_move(1, 'o')
13
+ game_history.record_move(2, 'x')
14
+ game_history.record_move(3, 'o')
15
+ game_history.record_move(4, 'x')
16
+ end
17
+
18
+ describe "#adjust_move_index" do
19
+
20
+ it "moves backward in the move history by 1 when its invoked with -1" do
21
+ traverser.adjust_move_index(-1)
22
+ traverser.move_index.should == 4
23
+ end
24
+
25
+ it "moves forward in the move history by 1 when its invoked with 1" do
26
+ traverser.move_index = 4
27
+ traverser.adjust_move_index(1)
28
+ traverser.move_index.should == 5
29
+ end
30
+
31
+ it "moves backward in the move history by 2 when its invoked with -2" do
32
+ traverser.adjust_move_index(-2)
33
+ traverser.move_index.should == 3
34
+ end
35
+
36
+ it "moves forward in the move history by 2 when its invoked with 2" do
37
+ traverser.move_index = 2
38
+ traverser.adjust_move_index(2)
39
+ traverser.move_index.should == 4
40
+ end
41
+
42
+ it "cannot move backwards beyond move index 0" do
43
+ traverser.move_index = 0
44
+ traverser.adjust_move_index(-1)
45
+ traverser.move_index.should == 0
46
+ end
47
+
48
+ it "cannot move beyond the max length" do
49
+ traverser.move_index = traverser.max_length
50
+ traverser.adjust_move_index(100)
51
+ traverser.move_index.should == traverser.max_length
52
+ end
53
+ end
54
+
55
+ describe "#history_board_builder" do
56
+ it "returns a board array representing the moves made up to move_number in history" do
57
+ traverser.history_board_builder(board, 3).should == ['x', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ']
58
+ board.board = Array.new(9, ' ')
59
+ traverser.history_board_builder(board, 5).should == ['x', 'o', 'x', 'o', 'x', ' ', ' ', ' ', ' ']
60
+ board.board = Array.new(9, ' ')
61
+ traverser.history_board_builder(board, 0).should == Array.new(9, ' ')
62
+ end
63
+
64
+ it "does not alter the original board" do
65
+ traverser.history_board_builder(board, 3).should_not == board.board
66
+ end
67
+
68
+ it "does not alter the original game history" do
69
+ original_history = traverser.game_history.history
70
+ traverser.game_history.history.should == original_history
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ module TTT
4
+ describe Player do
5
+
6
+ describe "#initialize" do
7
+ it "should initialize a blank new player" do
8
+ player = Player.new(side: "x")
9
+ player.side.should == "x"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ module TTT
4
+ describe RiakDB do
5
+ Riak.disable_list_keys_warnings = true
6
+ let(:setup) { Setup.new }
7
+ let(:players) { setup.players }
8
+ let(:boards) { setup.boards }
9
+ let(:game) { setup.new_game(player1: players.first, player2: players.first, board: boards.first) }
10
+ let(:riak) { setup.new_db }
11
+ let(:bucket) { riak.bucket }
12
+
13
+ describe "#new" do
14
+ it "establishes a connection with the Riak cluster" do
15
+ riak.client.should_not be_nil
16
+ end
17
+ end
18
+
19
+ describe "#add_game" do
20
+ it "adds a game to the game_list bucket" do
21
+ @id = riak.add_game(game)
22
+ riak.client[bucket].get(@id).data[:game].should_not == nil
23
+ end
24
+ end
25
+
26
+ describe "#game_list" do
27
+ it "returns a list of games available in the specified game bucket" do
28
+ num_keys_in_db = riak.client[bucket].keys.length
29
+ riak.game_list.length.should == num_keys_in_db
30
+ end
31
+ end
32
+
33
+ describe "#get_game" do
34
+ it "returns a game object from the Riak datastore" do
35
+ cur_id = riak.cur_id
36
+ riak.get_game(cur_id).class.should == Game
37
+ end
38
+
39
+ it "returns nil if there is no game at the specified id" do
40
+ riak.get_game(10000000000000000000).should == nil
41
+ end
42
+ end
43
+
44
+ describe "#save_game" do
45
+ it "saves an existing game to the Riak datastore" do
46
+ cur_id = riak.cur_id
47
+ new_game = riak.get_game(cur_id)
48
+ new_game.player1.side = "test"
49
+ riak.save_game(cur_id, new_game)
50
+ after_save = riak.get_game(cur_id)
51
+ new_game.player1.side.should == after_save.player1.side
52
+ end
53
+ end
54
+
55
+ describe "#delete_game" do
56
+ it "deletes an existing game from the Riak datastore" do
57
+ id = riak.add_game(game)
58
+ riak.get_game(id).class.should == Game
59
+ riak.delete_game(id)
60
+ riak.client[bucket].get_or_new(id).data.should == nil
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+ require 'ttt/config_options'
3
+
4
+ module TTT
5
+ describe Setup do
6
+ let(:setup) { Setup.new }
7
+
8
+ describe "#new_game" do
9
+ it "returns a new game object after instantiating the players, board, db and game history" do
10
+ game = setup.new_game(player1: "Human", player2: "AI Easy", board: "3x3")
11
+ game.player1.class.should == Human
12
+ game.player2.class.should == AIEasy
13
+ game.player1.side.should == "x"
14
+ game.player2.side.should == "o"
15
+ game.board.class.should == ThreeByThree
16
+ game.history.should_not be_nil
17
+ end
18
+ end
19
+
20
+ describe "#new_db" do
21
+ it "returns a new db object" do
22
+ db = setup.new_db
23
+ db.should respond_to(:client)
24
+ db.should respond_to(:bucket)
25
+ db.should respond_to(:cur_id)
26
+ db.should respond_to(:save_game)
27
+ db.should respond_to(:get_game)
28
+ db.should respond_to(:add_game)
29
+ db.should respond_to(:game_list)
30
+ end
31
+ end
32
+
33
+ describe "#players" do
34
+ it "returns a list of player types supported by the library" do
35
+ setup.players.should == ConfigOptions::HUMAN_READABLE_PLAYERS
36
+ end
37
+ end
38
+
39
+ describe "#boards" do
40
+ it "returns a list of board types supported by the library" do
41
+ setup.boards.should == ConfigOptions::HUMAN_READABLE_BOARDS
42
+ end
43
+ end
44
+
45
+ describe "#db" do
46
+ it "returns the db const specified in the config options file" do
47
+ setup.db.should == ConfigOptions::DB
48
+ end
49
+ end
50
+
51
+ describe "#interactor" do
52
+ it "returns the interactor const specified in the config options file" do
53
+ setup.interactor.should == ConfigOptions::INTERACTOR
54
+ end
55
+ end
56
+
57
+ describe "#new_interactor" do
58
+ it "returns an instance of a game interactor" do
59
+ setup.new_interactor.class.should == GameInteractor
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+
3
+ module TTT
4
+ describe ThreeByThreeByThree do
5
+ let(:board) { ThreeByThreeByThree.new }
6
+
7
+ describe "#initialize" do
8
+ it "board has length 27" do
9
+ board[].length.should == 27
10
+ end
11
+ end
12
+
13
+ describe "#update" do
14
+ it "updates the game board after move is received" do
15
+ board.update(1, "x")
16
+ board[].should == [" ", "x", " ", " ", " ", " ", " ", " ", " ",
17
+ " ", " ", " ", " ", " ", " ", " ", " ", " ",
18
+ " ", " ", " ", " ", " ", " ", " ", " ", " "]
19
+ end
20
+ end
21
+
22
+ describe "#empty?" do
23
+ it "returns true when board is empty" do
24
+ board.empty?.should == true
25
+ end
26
+
27
+ it "returns false when board is not empty" do
28
+ board.update(1, "x")
29
+ board.empty?.should == false
30
+ end
31
+ end
32
+
33
+ describe "#full?" do
34
+ it "returns true when board is full" do
35
+ 27.times do |n|
36
+ board.update(n, "o")
37
+ end
38
+ board.full?.should == true
39
+ end
40
+
41
+ it "returns false when board isn't full" do
42
+ board.update(1, "x")
43
+ board.full?.should == false
44
+ end
45
+ end
46
+
47
+ describe "#free?" do
48
+ it "returns false when board is occupied at a given cell" do
49
+ board.update(1, "x")
50
+ board.free?(1).should == false
51
+ end
52
+
53
+ it "returns true when board is not occupied at a given cell" do
54
+ board.free?(0).should == true
55
+ end
56
+ end
57
+
58
+ describe "#draw_game?" do
59
+ it "returns false when board is not full" do
60
+ board.draw_game?.should == false
61
+ end
62
+
63
+ it "returns true when board is full" do
64
+ board[] = ["a", "b", "c", "d", "e", "f", "g", "h", "i",
65
+ "j", "k", "l", "m", "n", "o", "p", "q", "r",
66
+ "s", "t", "u", "v", "w", "x", "y", "z", "a"]
67
+ board.draw_game?.should == true
68
+ end
69
+ end
70
+
71
+ describe "#winner?" do
72
+ it "returns false when the board has no winner" do
73
+ board.winner?.should == false
74
+ end
75
+
76
+ it "returns true when the board has a same-ply winner" do
77
+ board[] = ["x", "x", "x", "o", " ", "o", " ", " ", " ",
78
+ " ", " ", " ", " ", " ", " ", " ", " ", " ",
79
+ " ", " ", " ", " ", " ", " ", " ", " ", " "]
80
+ board.winner?.should == true
81
+ end
82
+
83
+ it "returns true when the board has a multi-ply regular winner" do
84
+ board[] = ["x", " ", " ", " ", " ", " ", " ", " ", " ",
85
+ "x", " ", " ", " ", " ", " ", " ", " ", " ",
86
+ "x", " ", " ", " ", " ", " ", " ", " ", " "]
87
+ board.winner?.should == true
88
+ end
89
+
90
+ it "returns true when the board has a multi-ply diagonal winner" do
91
+ board[] = ["x", " ", " ", " ", " ", " ", " ", " ", " ",
92
+ " ", " ", " ", " ", "x", " ", " ", " ", " ",
93
+ " ", " ", " ", " ", " ", " ", " ", " ", "x"]
94
+ board.winner?.should == true
95
+ end
96
+
97
+ it "returns true when the board has a multi-ply horizontal stacked winner" do
98
+ board[] = ["x", " ", " ", " ", " ", " ", " ", " ", " ",
99
+ " ", "x", " ", " ", " ", " ", " ", " ", " ",
100
+ " ", " ", "x", " ", " ", " ", " ", " ", " "]
101
+ board.winner?.should == true
102
+ end
103
+
104
+ it "returns true when the board has a multi-ply horizontal stacked winner" do
105
+ board[] = [" ", " ", " ", " ", " ", " ", "x", " ", " ",
106
+ " ", " ", " ", "x", " ", " ", " ", " ", " ",
107
+ "x", " ", " ", " ", " ", " ", " ", " ", " "]
108
+ board.winner?.should == true
109
+ end
110
+ end
111
+
112
+ describe "#finished?" do
113
+ it "returns false when board is not full, no win, or no draw" do
114
+ board.finished?.should == false
115
+ end
116
+
117
+ it "returns true when board has a win" do
118
+ board.update(0, 'x')
119
+ board.update(1, 'x')
120
+ board.update(2, 'x')
121
+ board.finished?.should == true
122
+ end
123
+
124
+ it "returns true when board has a draw" do
125
+ board[] = ["x", "o", "x", "x", "o", "o", "o", "x", "o"]
126
+ board.finished?.should == true
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+
3
+ module TTT
4
+ describe ThreeByThree do
5
+ let(:board) { ThreeByThree.new }
6
+
7
+ describe "#initialize" do
8
+ it "board has length 9" do
9
+ board[].length.should == 9
10
+ end
11
+ end
12
+
13
+ describe "#update" do
14
+ it "updates the game board after move is received" do
15
+ board.update(1, "x")
16
+ board[].should == [" ", "x", " ", " ", " ", " ", " ", " ", " "]
17
+ end
18
+ end
19
+
20
+ describe "#empty?" do
21
+ it "returns true when board is empty" do
22
+ board.empty?.should == true
23
+ end
24
+
25
+ it "returns false when board is not empty" do
26
+ board.update(1, "x")
27
+ board.empty?.should == false
28
+ end
29
+ end
30
+
31
+ describe "#full?" do
32
+ it "returns true when board is full" do
33
+ 9.times do |n|
34
+ board.update(n, "o")
35
+ end
36
+ board.full?.should == true
37
+ end
38
+
39
+ it "returns false when board isn't full" do
40
+ board.update(1, "x")
41
+ board.full?.should == false
42
+ end
43
+ end
44
+
45
+ describe "#free?" do
46
+ it "returns false when board is occupied at a given cell" do
47
+ board.update(1, "x")
48
+ board.free?(1).should == false
49
+ end
50
+
51
+ it "returns true when board is not occupied at a given cell" do
52
+ board.free?(0).should == true
53
+ end
54
+ end
55
+
56
+ describe "#draw_game?" do
57
+ it "returns false when board is not full" do
58
+ board.draw_game?.should == false
59
+ end
60
+
61
+ it "returns true when board is full" do
62
+ board[] = ["x", "o", "x", "x", "o", "o", "o", "x", "o"]
63
+ board.draw_game?.should == true
64
+ end
65
+ end
66
+
67
+ describe "#winner?" do
68
+ it "returns false when the board has no winner" do
69
+ board.winner?.should == false
70
+ end
71
+
72
+ it "returns true when the board has a winner" do
73
+ board[] = ["x", "x", "x", "o", " ", "o", " ", " ", " "]
74
+ board.winner?.should == true
75
+ end
76
+
77
+ it "returns true when the board has a block winner" do
78
+ board[] = ["x", "x", "o", "x", "x", "o", " ", " ", " "]
79
+ board.winner?.should == true
80
+ end
81
+ end
82
+
83
+ describe "#block_winner?" do
84
+ it "returns true when the board has a block winner" do
85
+ board[] = ["x", "x", "o", "x", "x", "o", " ", " ", " "]
86
+ end
87
+
88
+ it "returns false when the board has no block winner" do
89
+ board[] = ["x", "o", " ", " ", " ", " ", " ", " ", " "]
90
+ end
91
+ end
92
+ describe "#finished?" do
93
+ it "returns false when board is not full, no win, or no draw" do
94
+ board.finished?.should == false
95
+ end
96
+
97
+ it "returns true when board has a win" do
98
+ board.update(0, 'x')
99
+ board.update(1, 'x')
100
+ board.update(2, 'x')
101
+ board.finished?.should == true
102
+ end
103
+
104
+ it "returns true when board has a draw" do
105
+ board[] = ["x", "o", "x", "x", "o", "o", "o", "x", "o"]
106
+ board.finished?.should == true
107
+ end
108
+ end
109
+ end
110
+ end