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.
- data/bin/play.rb +10 -0
- data/lib/ttt/ai.rb +33 -0
- data/lib/ttt/ai_easy.rb +17 -0
- data/lib/ttt/ai_hard.rb +21 -0
- data/lib/ttt/ai_medium.rb +21 -0
- data/lib/ttt/ai_medium_back.rb +58 -0
- data/lib/ttt/board.rb +37 -0
- data/lib/ttt/config_helper.rb +53 -0
- data/lib/ttt/config_options.rb +27 -0
- data/lib/ttt/context.rb +214 -0
- data/lib/ttt/four_by_four.rb +62 -0
- data/lib/ttt/game.rb +94 -0
- data/lib/ttt/game_history.rb +37 -0
- data/lib/ttt/game_interactor.rb +126 -0
- data/lib/ttt/human.rb +12 -0
- data/lib/ttt/interfaces/cli/lib/cli/board_selection.rb +34 -0
- data/lib/ttt/interfaces/cli/lib/cli/cli_game.rb +186 -0
- data/lib/ttt/interfaces/cli/lib/cli/cli_presenter.rb +216 -0
- data/lib/ttt/interfaces/cli/lib/cli/clio.rb +17 -0
- data/lib/ttt/interfaces/cli/lib/cli/play_again.rb +38 -0
- data/lib/ttt/interfaces/cli/lib/cli/player_selection.rb +43 -0
- data/lib/ttt/interfaces/cli/lib/cli/selection.rb +8 -0
- data/lib/ttt/interfaces/cli/lib/cli/walk_history.rb +48 -0
- data/lib/ttt/interfaces/cli/spec/cli/board_selection_spec.rb +29 -0
- data/lib/ttt/interfaces/cli/spec/cli/cli_game_spec.rb +376 -0
- data/lib/ttt/interfaces/cli/spec/cli/cli_presenter_spec.rb +147 -0
- data/lib/ttt/interfaces/cli/spec/cli/play_again_spec.rb +39 -0
- data/lib/ttt/interfaces/cli/spec/cli/player_selection_spec.rb +62 -0
- data/lib/ttt/interfaces/cli/spec/cli/walk_history_spec.rb +115 -0
- data/lib/ttt/interfaces/cli/spec/spec_helper.rb +14 -0
- data/lib/ttt/interfaces/limelight/four_by_four/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/four_by_four/styles.rb +74 -0
- data/lib/ttt/interfaces/limelight/four_by_four_finished/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/four_by_four_finished/styles.rb +74 -0
- data/lib/ttt/interfaces/limelight/game_list/players/load_button.rb +10 -0
- data/lib/ttt/interfaces/limelight/game_list/props.rb +17 -0
- data/lib/ttt/interfaces/limelight/game_list/styles.rb +8 -0
- data/lib/ttt/interfaces/limelight/main_menu/players/exit_ttt.rb +3 -0
- data/lib/ttt/interfaces/limelight/main_menu/players/load_game.rb +3 -0
- data/lib/ttt/interfaces/limelight/main_menu/players/new_game.rb +3 -0
- data/lib/ttt/interfaces/limelight/main_menu/props.rb +17 -0
- data/lib/ttt/interfaces/limelight/new_game/players/board_type.rb +1 -0
- data/lib/ttt/interfaces/limelight/new_game/players/new_game.rb +5 -0
- data/lib/ttt/interfaces/limelight/new_game/players/player_type.rb +1 -0
- data/lib/ttt/interfaces/limelight/new_game/players/setup_button.rb +21 -0
- data/lib/ttt/interfaces/limelight/new_game/props.rb +21 -0
- data/lib/ttt/interfaces/limelight/new_game/styles.rb +23 -0
- data/lib/ttt/interfaces/limelight/partials/board_partial.rb +14 -0
- data/lib/ttt/interfaces/limelight/partials/menu_button_partial.rb +5 -0
- data/lib/ttt/interfaces/limelight/partials/move_history_partial.rb +6 -0
- data/lib/ttt/interfaces/limelight/partials/title_history_partial.rb +10 -0
- data/lib/ttt/interfaces/limelight/players/board.rb +3 -0
- data/lib/ttt/interfaces/limelight/players/game.rb +4 -0
- data/lib/ttt/interfaces/limelight/players/generic_move_history.rb +5 -0
- data/lib/ttt/interfaces/limelight/players/generic_player.rb +8 -0
- data/lib/ttt/interfaces/limelight/players/left_button.rb +3 -0
- data/lib/ttt/interfaces/limelight/players/main_menu.rb +3 -0
- data/lib/ttt/interfaces/limelight/players/right_button.rb +3 -0
- data/lib/ttt/interfaces/limelight/playscripts/game_playscript.rb +169 -0
- data/lib/ttt/interfaces/limelight/production.rb +14 -0
- data/lib/ttt/interfaces/limelight/spec/game_playscript_spec.rb +218 -0
- data/lib/ttt/interfaces/limelight/spec/main_menu/main_menu_spec.rb +38 -0
- data/lib/ttt/interfaces/limelight/spec/new_game/new_game_spec.rb +45 -0
- data/lib/ttt/interfaces/limelight/spec/spec_helper.rb +8 -0
- data/lib/ttt/interfaces/limelight/stages.rb +6 -0
- data/lib/ttt/interfaces/limelight/styles.rb +119 -0
- data/lib/ttt/interfaces/limelight/three_by_three/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/three_by_three/styles.rb +39 -0
- data/lib/ttt/interfaces/limelight/three_by_three_by_three/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/three_by_three_by_three/styles.rb +119 -0
- data/lib/ttt/interfaces/limelight/three_by_three_by_three_finished/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/three_by_three_by_three_finished/styles.rb +119 -0
- data/lib/ttt/interfaces/limelight/three_by_three_finished/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/three_by_three_finished/styles.rb +39 -0
- data/lib/ttt/interfaces/rails/app/controllers/application_controller.rb +3 -0
- data/lib/ttt/interfaces/rails/app/controllers/ttt_games_controller.rb +86 -0
- data/lib/ttt/interfaces/rails/app/helpers/application_helper.rb +2 -0
- data/lib/ttt/interfaces/rails/app/models/ttt_game.rb +34 -0
- data/lib/ttt/interfaces/rails/app/presenters/web_game_presenter.rb +159 -0
- data/lib/ttt/interfaces/rails/autotest/discover.rb +1 -0
- data/lib/ttt/interfaces/rails/config/application.rb +67 -0
- data/lib/ttt/interfaces/rails/config/boot.rb +6 -0
- data/lib/ttt/interfaces/rails/config/environment.rb +5 -0
- data/lib/ttt/interfaces/rails/config/environments/development.rb +37 -0
- data/lib/ttt/interfaces/rails/config/environments/production.rb +67 -0
- data/lib/ttt/interfaces/rails/config/environments/test.rb +37 -0
- data/lib/ttt/interfaces/rails/config/initializers/backtrace_silencers.rb +7 -0
- data/lib/ttt/interfaces/rails/config/initializers/inflections.rb +15 -0
- data/lib/ttt/interfaces/rails/config/initializers/mime_types.rb +5 -0
- data/lib/ttt/interfaces/rails/config/initializers/secret_token.rb +7 -0
- data/lib/ttt/interfaces/rails/config/initializers/session_store.rb +8 -0
- data/lib/ttt/interfaces/rails/config/initializers/wrap_parameters.rb +14 -0
- data/lib/ttt/interfaces/rails/config/routes.rb +49 -0
- data/lib/ttt/interfaces/rails/db/schema.rb +28 -0
- data/lib/ttt/interfaces/rails/db/seeds.rb +7 -0
- data/lib/ttt/interfaces/rails/spec/controllers/ttt_games_controller_spec.rb +211 -0
- data/lib/ttt/interfaces/rails/spec/models/ttt_game_spec.rb +76 -0
- data/lib/ttt/interfaces/rails/spec/presenters/web_game_presenter_spec.rb +52 -0
- data/lib/ttt/interfaces/rails/spec/spec_helper.rb +13 -0
- data/lib/ttt/interfaces/web_interface/html_generator.rb +76 -0
- data/lib/ttt/interfaces/web_interface/web_game_presenter.rb +0 -0
- data/lib/ttt/minimax.rb +46 -0
- data/lib/ttt/move_history.rb +10 -0
- data/lib/ttt/move_traverser.rb +49 -0
- data/lib/ttt/player.rb +15 -0
- data/lib/ttt/riak_db.rb +53 -0
- data/lib/ttt/setup.rb +59 -0
- data/lib/ttt/three_by_three.rb +35 -0
- data/lib/ttt/three_by_three_by_three.rb +37 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/ttt/ai_easy_spec.rb +15 -0
- data/spec/ttt/ai_hard_spec.rb +76 -0
- data/spec/ttt/ai_medium_spec.rb +65 -0
- data/spec/ttt/ai_spec.rb +50 -0
- data/spec/ttt/board_spec.rb +96 -0
- data/spec/ttt/config_helper_spec.rb +54 -0
- data/spec/ttt/context_spec.rb +398 -0
- data/spec/ttt/four_by_four_spec.rb +112 -0
- data/spec/ttt/game_history_spec.rb +41 -0
- data/spec/ttt/game_interactor_spec.rb +197 -0
- data/spec/ttt/game_spec.rb +246 -0
- data/spec/ttt/human_spec.rb +18 -0
- data/spec/ttt/move_history_spec.rb +13 -0
- data/spec/ttt/move_traverser_spec.rb +75 -0
- data/spec/ttt/player_spec.rb +13 -0
- data/spec/ttt/riak_db_spec.rb +64 -0
- data/spec/ttt/setup_spec.rb +63 -0
- data/spec/ttt/three_by_three_by_three_spec.rb +130 -0
- data/spec/ttt/three_by_three_spec.rb +110 -0
- metadata +238 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Railsttt::Application.routes.draw do
|
|
2
|
+
root :to => 'ttt_games#welcome'
|
|
3
|
+
|
|
4
|
+
resources :ttt_games do
|
|
5
|
+
collection do
|
|
6
|
+
post 'create_game'
|
|
7
|
+
get 'show'
|
|
8
|
+
get 'game_list'
|
|
9
|
+
end
|
|
10
|
+
member do
|
|
11
|
+
post 'update_game'
|
|
12
|
+
get 'next_move'
|
|
13
|
+
get 'load_game'
|
|
14
|
+
get 'move_history'
|
|
15
|
+
get 'get_game'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
resources :game do
|
|
20
|
+
collection do
|
|
21
|
+
get 'game_index'
|
|
22
|
+
post 'create_game'
|
|
23
|
+
get 'show'
|
|
24
|
+
end
|
|
25
|
+
member do
|
|
26
|
+
post 'mark_move'
|
|
27
|
+
get 'computer_move'
|
|
28
|
+
get 'next_history_move'
|
|
29
|
+
get 'load_game'
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
resources :web_games do
|
|
34
|
+
collection do
|
|
35
|
+
put 'setup'
|
|
36
|
+
end
|
|
37
|
+
member do
|
|
38
|
+
put 'player1_setup'
|
|
39
|
+
put 'player2_setup'
|
|
40
|
+
put 'board_selection'
|
|
41
|
+
get 'test_show'
|
|
42
|
+
get 'determine_next_move'
|
|
43
|
+
get 'end_game'
|
|
44
|
+
get 'computer_move'
|
|
45
|
+
post 'mark_move'
|
|
46
|
+
post 'create'
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
# This file is auto-generated from the current state of the database. Instead
|
|
3
|
+
# of editing this file, please use the migrations feature of Active Record to
|
|
4
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
|
5
|
+
#
|
|
6
|
+
# Note that this schema.rb definition is the authoritative source for your
|
|
7
|
+
# database schema. If you need to create the application database on another
|
|
8
|
+
# system, you should be using db:schema:load, not running all the migrations
|
|
9
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
|
10
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
|
11
|
+
#
|
|
12
|
+
# It's strongly recommended to check this file into your version control system.
|
|
13
|
+
|
|
14
|
+
ActiveRecord::Schema.define(:version => 20121217183241) do
|
|
15
|
+
|
|
16
|
+
create_table "web_game_histories", :force => true do |t|
|
|
17
|
+
t.text "web_game"
|
|
18
|
+
t.string "player"
|
|
19
|
+
t.string "move"
|
|
20
|
+
t.integer "web_game_id"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
create_table "web_games", :force => true do |t|
|
|
24
|
+
t.text "game"
|
|
25
|
+
t.string "winner"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# This file should contain all the record creation needed to seed the database with its default values.
|
|
2
|
+
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
|
|
3
|
+
#
|
|
4
|
+
# Examples:
|
|
5
|
+
#
|
|
6
|
+
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
|
|
7
|
+
# Mayor.create(name: 'Emanuel', city: cities.first)
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe TttGamesController do
|
|
4
|
+
let(:context) { TTT::Context.instance }
|
|
5
|
+
let(:setup) { TTT::Setup.new }
|
|
6
|
+
let(:players) { setup.players }
|
|
7
|
+
let(:boards) { setup.boards }
|
|
8
|
+
let(:game) { setup.new_game(player1: players.first, player2: players.first, board: boards.first) }
|
|
9
|
+
|
|
10
|
+
describe "GET new" do
|
|
11
|
+
it "gets the player types defined by the TTT library" do
|
|
12
|
+
get :new
|
|
13
|
+
assigns[:players].should == players
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "gets the board types defined by the TTT library" do
|
|
17
|
+
get :new
|
|
18
|
+
assigns[:boards].should == boards
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "sets cookies to nil" do
|
|
22
|
+
get :new
|
|
23
|
+
@request.cookies[:game_id].should == nil
|
|
24
|
+
@request.cookies[:move_index].should == nil
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "POST create_game" do
|
|
29
|
+
before(:each) do
|
|
30
|
+
post :create_game, player1: "Human", player2: "Human", board: "3x3"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "sets the cookies[:game_id] to the new game stored in the db" do
|
|
34
|
+
response.cookies["game_id"].should_not be_nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "sets the flash[:notice] to 'Welcome to TTT!'" do
|
|
38
|
+
flash[:notice].should == "Welcome to Tic Tac Toe!"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "GET show" do
|
|
43
|
+
before(:each) do
|
|
44
|
+
@id = context.add_game(game)
|
|
45
|
+
request.cookies["game_id"] = @id
|
|
46
|
+
@game = context.get_game(@id)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "has the correct game_id in cookies" do
|
|
50
|
+
get :show
|
|
51
|
+
cookies["game_id"].should == @id
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "loads the game whose id is the id stored as cookies[:game_id] from the database" do
|
|
55
|
+
get :show
|
|
56
|
+
assigns[:game].eql? @game
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "creates a web game presenter responsible for displaying the game board" do
|
|
60
|
+
get :show
|
|
61
|
+
assigns[:web_game_presenter].should_not be_nil
|
|
62
|
+
assigns[:web_game_presenter].id.should == @id
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "POST update_game" do
|
|
67
|
+
before(:each) do
|
|
68
|
+
@id = context.add_game(game)
|
|
69
|
+
@game = context.get_game(@id)
|
|
70
|
+
post :update_game, :id => @id, :game_id => @id, :move => 0
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "updates cookies[:game_id] with the updated game's id" do
|
|
74
|
+
@response.cookies['game_id'].should == @id
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "saves the game to the db" do
|
|
78
|
+
updated_game = context.get_game(@id)
|
|
79
|
+
@game.board.should_not == updated_game.board
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
describe "GET game_list" do
|
|
85
|
+
it "returns all game ids for the queried bucket" do
|
|
86
|
+
@games = context.game_list()
|
|
87
|
+
@total_keys = @games.length
|
|
88
|
+
get :game_list
|
|
89
|
+
assigns[:games].length.should == @total_keys
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe "GET get_game" do
|
|
94
|
+
it "reassigns the cookies[:game_id] to the selected game" do
|
|
95
|
+
get :get_game, id: 1
|
|
96
|
+
cookies[:game_id].should == "1"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
describe "GET move_history" do
|
|
101
|
+
before(:each) do
|
|
102
|
+
post :create_game, player1: "Human", player2: "Human", board: "3x3"
|
|
103
|
+
@id = cookies[:game_id]
|
|
104
|
+
post :update_game, id: @id, move: 0 # x moves at square 0 ['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
105
|
+
post :update_game, id: @id, move: 1 # o moves at square 1 ['x', 'o', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
106
|
+
post :update_game, id: @id, move: 4 # x moves at square 2 ['x', 'o', ' ', ' ', 'x', ' ', ' ', ' ', ' ']
|
|
107
|
+
post :update_game, id: @id, move: 5 # x moves at square 2 ['x', 'o', ' ', ' ', 'x', 'o', ' ', ' ', ' ']
|
|
108
|
+
post :update_game, id: @id, move: 8 # x moves at square 2 ['x', 'o', ' ', ' ', 'x', 'o', ' ', ' ', 'x']
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
context "gets the board for a particular game's move history for a given place in history" do
|
|
112
|
+
it "returns the final game board state when index diff is 0 and it is the first time the game history is requested" do
|
|
113
|
+
get :move_history, id: @id, index_diff: 0
|
|
114
|
+
cookies[:game_id].should == @id
|
|
115
|
+
assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', 'o', ' ', ' ', 'x']
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "allows the user to traverse backwards through a game's history one step at a time" do
|
|
119
|
+
5.times do |n|
|
|
120
|
+
request.cookies[:move_index] = -(n)
|
|
121
|
+
request.cookies[:last_id] = @id
|
|
122
|
+
get :move_history, id: @id, index_diff: -1
|
|
123
|
+
cookies[:game_id].should == @id
|
|
124
|
+
case n
|
|
125
|
+
when 0 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', 'o', ' ', ' ', ' ']
|
|
126
|
+
when 1 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', ' ', ' ', ' ', ' ']
|
|
127
|
+
when 2 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
128
|
+
when 3 then assigns[:web_game_presenter].board.board.should == ['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
129
|
+
when 4 then assigns[:web_game_presenter].board.board.should == [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "allows the user to traverse forwards through a game's history one step at a time" do
|
|
135
|
+
5.times do |n|
|
|
136
|
+
request.cookies[:move_index] = n + -5
|
|
137
|
+
request.cookies[:last_id] = @id
|
|
138
|
+
get :move_history, id: @id, index_diff: 1
|
|
139
|
+
cookies[:game_id].should == @id
|
|
140
|
+
case n
|
|
141
|
+
when 0 then assigns[:web_game_presenter].board.board.should == ['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
142
|
+
when 1 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
143
|
+
when 2 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', ' ', ' ', ' ', ' ']
|
|
144
|
+
when 3 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', 'o', ' ', ' ', ' ']
|
|
145
|
+
when 4 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', 'o', ' ', ' ', 'x']
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "doesn't all the user to traverse backwards further than the start of the game" do
|
|
151
|
+
50.times do |n|
|
|
152
|
+
if n < 6
|
|
153
|
+
request.cookies[:move_index] = -(n)
|
|
154
|
+
else
|
|
155
|
+
request.cookies[:moe_index] = -5
|
|
156
|
+
end
|
|
157
|
+
request.cookies[:last_id] = @id
|
|
158
|
+
get :move_history, id: @id, index_diff: -1
|
|
159
|
+
cookies[:game_id].should == @id
|
|
160
|
+
case n
|
|
161
|
+
when 0 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', 'o', ' ', ' ', ' ']
|
|
162
|
+
when 1 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', ' ', ' ', ' ', ' ']
|
|
163
|
+
when 2 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
164
|
+
when 3 then assigns[:web_game_presenter].board.board.should == ['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
165
|
+
when 4 then assigns[:web_game_presenter].board.board.should == [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
166
|
+
else
|
|
167
|
+
assigns[:web_game_presenter].board.board.should == [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "doesn't allow the user to traverse forwards further than the final state of the game" do
|
|
173
|
+
50.times do |n|
|
|
174
|
+
if n < 6
|
|
175
|
+
request.cookies[:move_index] = n + -5
|
|
176
|
+
else
|
|
177
|
+
request.cookies[:move_index] = 0
|
|
178
|
+
end
|
|
179
|
+
request.cookies[:last_id] = @id
|
|
180
|
+
get :move_history, id: @id, index_diff: 1
|
|
181
|
+
cookies[:game_id].should == @id
|
|
182
|
+
case n
|
|
183
|
+
when 0 then assigns[:web_game_presenter].board.board.should == ['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
184
|
+
when 1 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
185
|
+
when 2 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', ' ', ' ', ' ', ' ']
|
|
186
|
+
when 3 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', 'o', ' ', ' ', ' ']
|
|
187
|
+
when 4 then assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', 'o', ' ', ' ', 'x']
|
|
188
|
+
else
|
|
189
|
+
assigns[:web_game_presenter].board.board.should == ['x', 'o', ' ', ' ', 'x', 'o', ' ', ' ', 'x']
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
describe "#next_move" do
|
|
196
|
+
before(:each) do
|
|
197
|
+
post :create_game, player1: "AI Easy", player2: "AI Easy", board: "3x3"
|
|
198
|
+
@id = cookies[:game_id]
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "correctly finds the current game and prompts the AI player for the next move" do
|
|
202
|
+
original_game = context.get_game(@id)
|
|
203
|
+
original_game.board.board.should == Array.new(9, " ")
|
|
204
|
+
request.cookies[:game_id] = @id
|
|
205
|
+
get :next_move, id: @id
|
|
206
|
+
next_game_state = context.get_game(@id)
|
|
207
|
+
next_game_state.board.board.should_not == original_game.board.board
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe TttGame do
|
|
4
|
+
let(:context) { TTT::Context.instance }
|
|
5
|
+
let(:setup) { TTT::Setup }
|
|
6
|
+
|
|
7
|
+
before(:each) do
|
|
8
|
+
context.setup = setup
|
|
9
|
+
@game_id = context.create_game(context.players.first, context.players.first, context.boards.first)
|
|
10
|
+
@game = context.get_game(@game_id)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "#evaluate_game" do
|
|
14
|
+
it "returns 'It's a draw' when the final result of a game is a draw" do
|
|
15
|
+
@game.board.board = %w(a b c d e f g h i)
|
|
16
|
+
context.save_game(@game_id, @game)
|
|
17
|
+
message, view = described_class.evaluate_game(@game_id, context)
|
|
18
|
+
message.should == "It's a draw"
|
|
19
|
+
view.should == "end_game"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "returns 'Player 1' is the winner when the final result is player 1 is the winner" do
|
|
23
|
+
@game.board.board = Array.new(9, 'x')
|
|
24
|
+
@game.switch_player
|
|
25
|
+
context.save_game(@game_id, @game)
|
|
26
|
+
message, view = described_class.evaluate_game(@game_id, context)
|
|
27
|
+
message.should == "Player 1 is the winner!"
|
|
28
|
+
view.should == "end_game"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "returns 'Player 2' is the winner when the final result is player 2 is the winner" do
|
|
32
|
+
@game.board.board = Array.new(9, 'o')
|
|
33
|
+
2.times { @game.switch_player }
|
|
34
|
+
context.save_game(@game_id, @game)
|
|
35
|
+
message, view = described_class.evaluate_game(@game_id, context)
|
|
36
|
+
message.should == "Player 2 is the winner!"
|
|
37
|
+
view.should == "end_game"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "returns 'Player 1's turn' when the game is not finished and it is player 1's turn" do
|
|
41
|
+
@game.board.board = Array.new(9, ' ')
|
|
42
|
+
message, view = described_class.evaluate_game(@game_id, context)
|
|
43
|
+
message.should == "Player 1's turn"
|
|
44
|
+
view.should == "show"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "returns 'Player 2's turn' when the game is not finished and it is player 2's turn" do
|
|
48
|
+
@game.board.board = Array.new(9, ' ')
|
|
49
|
+
@game.mark_move(1, 'x')
|
|
50
|
+
@game.switch_player
|
|
51
|
+
context.save_game(@game_id, @game)
|
|
52
|
+
message, view = described_class.evaluate_game(@game_id, context)
|
|
53
|
+
message.should == "Player 2's turn"
|
|
54
|
+
view.should == "show"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe "#get_history_length" do
|
|
59
|
+
it "returns the total number of moves for a game" do
|
|
60
|
+
@game.record_move(1, 'x')
|
|
61
|
+
@game.record_move(2, 'o')
|
|
62
|
+
context.save_game(@game_id, @game)
|
|
63
|
+
described_class.get_history_length(@game_id, context)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe "#get_history_board" do
|
|
68
|
+
it "returns a board array representing the move history board at a specified move index" do
|
|
69
|
+
@game.record_move(1, 'x')
|
|
70
|
+
@game.record_move(2, 'o')
|
|
71
|
+
context.save_game(@game_id, @game)
|
|
72
|
+
described_class.get_history_board(@game, -1).should == [' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
73
|
+
described_class.get_history_board(@game, -2).should == Array.new(9, " ")
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'web_game_presenter'
|
|
3
|
+
require 'ttt/three_by_three'
|
|
4
|
+
require 'ttt/four_by_four'
|
|
5
|
+
require 'ttt/three_by_three_by_three'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
describe WebGamePresenter do
|
|
9
|
+
def show_board(presenter)
|
|
10
|
+
string = presenter.show_board.scan(/<td|<tr|>[xo]+</).join
|
|
11
|
+
string.delete! "><"
|
|
12
|
+
string
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def presenter_for(options)
|
|
16
|
+
board = options[:klass].new
|
|
17
|
+
options[:updates].each { |index, marker| board.update index, marker }
|
|
18
|
+
described_class.for(board: board, id: 1)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'renders a three_by_three board' do
|
|
22
|
+
presenter = presenter_for klass: TTT::ThreeByThree, updates: { 0 => 'x', 1 => 'o' }
|
|
23
|
+
show_board(presenter).should == "tr" "tdx" "tdo" "td" \
|
|
24
|
+
"tr" "td" "td" "td" \
|
|
25
|
+
"tr" "td" "td" "td"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'renders a four_by_four board' do
|
|
29
|
+
presenter = presenter_for klass: TTT::FourByFour, updates: { 0 => 'x', 1 => 'o' }
|
|
30
|
+
show_board(presenter).should == "tr" "tdx" "tdo" "td" "td" \
|
|
31
|
+
"tr" "td" "td" "td" "td" \
|
|
32
|
+
"tr" "td" "td" "td" "td" \
|
|
33
|
+
"tr" "td" "td" "td" "td"
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'renders a three_by_three_by_three board' do
|
|
38
|
+
presenter = presenter_for klass: TTT::ThreeByThreeByThree, updates: { 0 => 'x', 1 => 'o' }
|
|
39
|
+
show_board(presenter).should == "tr" "tdx" "tdo" "td" \
|
|
40
|
+
"tr" "td" "td" "td" \
|
|
41
|
+
"tr" "td" "td" "td" \
|
|
42
|
+
\
|
|
43
|
+
"tr" "td" "td" "td" \
|
|
44
|
+
"tr" "td" "td" "td" \
|
|
45
|
+
"tr" "td" "td" "td" \
|
|
46
|
+
\
|
|
47
|
+
"tr" "td" "td" "td" \
|
|
48
|
+
"tr" "td" "td" "td" \
|
|
49
|
+
"tr" "td" "td" "td" \
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
ENV["RAILS_ENV"] ||= 'test'
|
|
2
|
+
#require 'simplecov'
|
|
3
|
+
#SimpleCov.start
|
|
4
|
+
require File.expand_path("../../config/environment", __FILE__)
|
|
5
|
+
$:.unshift File.expand_path("../../../../..", __FILE__)
|
|
6
|
+
#$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
|
|
7
|
+
|
|
8
|
+
require 'rspec/rails'
|
|
9
|
+
require 'rspec/autorun'
|
|
10
|
+
require 'ttt/context'
|
|
11
|
+
require 'ttt/setup'
|
|
12
|
+
|
|
13
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module TTT
|
|
2
|
+
class HtmlGenerator
|
|
3
|
+
def initialize
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def new_game
|
|
7
|
+
html_string = html_open
|
|
8
|
+
html_string += html_close
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def show_game(game, game_id, game_history)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def game_list(games)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def hidden_field(game, game_id)
|
|
18
|
+
html_string = ""
|
|
19
|
+
html_string += %q[<div id="current_player" game_id="#{game_id}">]
|
|
20
|
+
html_string += true if game.ai_move? && !game.board.finished?
|
|
21
|
+
html_string += "</div>"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def main_body(flash_message, web_game_presenter)
|
|
25
|
+
html_string = ""
|
|
26
|
+
html_string += %q[<div style="width: 1020px; margin: 100px auto 20px auto;">]
|
|
27
|
+
html_string += %q[<h4 class="notice">#{flash_message}</h4>] if flash_message
|
|
28
|
+
html_string += web_game_presenter.show_board
|
|
29
|
+
html_string += "</div>"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def move_history
|
|
33
|
+
html_string = ""
|
|
34
|
+
html_string += %q[<div id="buttons" style="width: 800px; margin: auto;">]
|
|
35
|
+
html_string += %q[<div id="button_left" style="float: left; margin-left: 200px;">]
|
|
36
|
+
html_string += %q[<img src="/images/button_left.png" class="pointer" /></div>]
|
|
37
|
+
html_string += %q[<div id="button_right" style="float: right; margin-right: 200px;">]
|
|
38
|
+
html_string += %q[<img src="/images/button_right.png" class="pointer" /></div></div>]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def move_index(web_game_history)
|
|
42
|
+
html_string = ""
|
|
43
|
+
html_string += %q[<div class="move_history" style="float: right; width: 170px; height: 800px; text-align: right;">]
|
|
44
|
+
html_string += %q[<h4 style="text-align: center;">Move History</h4>]
|
|
45
|
+
html_string += %q[<ul style="width: 215px;">]
|
|
46
|
+
game_history.each_with_index do |move, index|
|
|
47
|
+
move_list_class = index == 0 ? "move_list_first" : "move_list"
|
|
48
|
+
html_string += %q[<li class="#{move_list_class}"><span style="margin-right: 10px;">#{index + 1})</span>]
|
|
49
|
+
html_string += %q[<span style="margin-right: 10px;">#{move.side}</span> #{move.move}]
|
|
50
|
+
end
|
|
51
|
+
html_string += "</ul></div>"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def html_open
|
|
55
|
+
html_string = ""
|
|
56
|
+
html_string += %q[<!DOCTYPE html>]
|
|
57
|
+
html_string += %q[<html><head><title>Java Server TTT</title>]
|
|
58
|
+
html_string += %q[<link href="/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />]
|
|
59
|
+
html_string += %q[<link href="/css/application.css" media="all" rel="stylesheet" type="text/css" />]
|
|
60
|
+
html_string += %q[<link href="/css/tictactoe.css" media="all" rel="stylesheet" type="text/css" />]
|
|
61
|
+
html_string += %q[<link href="/css/web_game.css" media="all" rel="stylesheet" type="text/css" />]
|
|
62
|
+
html_string += %q[<script src="/js/jquery.js" type="text/javascript"></script>]
|
|
63
|
+
html_string += %q[<script src="/js/ttt.js" type="text/javascript"></script>]
|
|
64
|
+
html_string += %q[<script src="/js/application.js" type="text/javascript"></script></head>]
|
|
65
|
+
html_string += %q[<body><div class="main_buttons"><div class="new_game_btn_wrapper">]
|
|
66
|
+
html_string += %q[<a href="/new_game" class="button">New Game</a></div>]
|
|
67
|
+
html_string += %q[<div class="all_games_btn_wrapper">]
|
|
68
|
+
html_string += %q[<a href="/game_list" class="button">All Games</a></div>]
|
|
69
|
+
html_string += %q[</div>]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def html_close
|
|
73
|
+
"</body></html>"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|