stzjb_server 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1a5a39c936a6d498c4a683d88a6efdb6aa6734f1
4
+ data.tar.gz: 57f4d24d1c468109e186b02610dde4f26466ec79
5
+ SHA512:
6
+ metadata.gz: 19a27b121f10421f5302c2c5581a590f529fa6c674bad37e4d13a151943e9c0a7317b12239c1b19d12d161813d0abb5e95cf067318289db1bde70a86389b237b
7
+ data.tar.gz: 39e8a0b4b86171e23f698fd9e04d8eb8e10c28139dc03d8b08f346e1a5dce569e6feb3a34e85dcb062dd019ee49a5243757ac94f9366285524e743eb405d0a14
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ application.yml
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://ruby.taobao.org'
2
+
3
+ # Specify your gem's dependencies in stzjb_server.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,15 @@
1
+ # StjzbServer
2
+
3
+ 石头剪子布服务端
4
+
5
+ ## Installation
6
+
7
+ $ gem install stjzb_server
8
+
9
+ ## Run
10
+
11
+ $ cd stjzb_server && ruby application.rb
12
+
13
+ ## Play
14
+
15
+ see https://github.com/takafan/stjzb
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,40 @@
1
+ # 1. 简易登录
2
+ # 2. 随机对战 pvp1
3
+ # 3. 好友对战 pvp2
4
+ # 4. 对电脑 pve
5
+
6
+ require File.expand_path('../lib/stjzb_server', __FILE__)
7
+
8
+ players = {} # login: websocket
9
+
10
+ EM::WebSocket.start(host: Settings.host, port: Settings.port) do |ws|
11
+ ws.onopen { |handshake|
12
+ ws.send_message_welcome
13
+ puts "#{ws.object_id} opened"
14
+ }
15
+
16
+ ws.onclose {
17
+ ws.logout(players)
18
+ puts "#{ws.object_id} closed"
19
+ }
20
+
21
+ ws.onmessage { |msg|
22
+ act, val = Oj.load(msg)
23
+ case act
24
+ when 'simple-login' # 简易登录
25
+ ws.simple_login(val, players)
26
+ when 'logout' # 登出
27
+ ws.logout(players)
28
+ when 'pvp1' # 随机对战
29
+ ws.pvp1(players)
30
+ when 'pvp2'
31
+ ws.pvp2(val, players)
32
+ when 'cancel-matching'
33
+ ws.cancel_matching
34
+ when 'escape-pvp'
35
+ ws.escape_pvp
36
+ when 'stjzb'
37
+ ws.stjzb(val)
38
+ end
39
+ }
40
+ end
@@ -0,0 +1,2 @@
1
+ host: 0.0.0.0
2
+ port: 8080
@@ -0,0 +1,215 @@
1
+ module EventMachine
2
+ module WebSocket
3
+ class Connection
4
+ attr_accessor :loginname, :current_opponent, :current_friend_loginname, :pvp_state, :pvp1_wins, :matching_retry_times,
5
+ :current_battle, :current_win_rounds, :current_action
6
+
7
+ IDLE = 1
8
+ MATCHING = 2
9
+ BATTLING = 3
10
+
11
+ def simple_login(loginname, players)
12
+ if loginname.nil? || loginname.empty?
13
+ loginname = players['takafan'] ? 'ayumi' : 'takafan'
14
+ end
15
+
16
+ old_ws = players[loginname]
17
+ if old_ws && old_ws != self
18
+ old_ws.logout players, '你在别的地方登录了'
19
+ end
20
+ players[loginname] = self
21
+ @loginname = loginname
22
+ @current_opponent = nil
23
+ @pvp_state = IDLE
24
+ @pvp1_wins = 0
25
+ send_message_simple_logined
26
+ puts "#{loginname} logined, players.size: #{players.size}"
27
+ end
28
+
29
+ def logout(players, reason = nil)
30
+ if @loginname
31
+ loginname = @loginname
32
+ escape_pvp
33
+ cancel_matching
34
+
35
+ @loginname = nil
36
+ @pvp1_wins = 0
37
+ send_message_loggedout(reason)
38
+
39
+ players.delete loginname
40
+ puts "#{loginname} logged out, players.size: #{players.size}"
41
+
42
+ loginname
43
+ end
44
+ end
45
+
46
+ # 随机对战
47
+ def pvp1(players)
48
+ if @loginname && players[@loginname]
49
+ @pvp_state = MATCHING
50
+ @matching_retry_times = 0
51
+ send_message_pvp1_ready
52
+ puts "#{@loginname} random battle ready, state: #{@pvp_state}"
53
+
54
+ matching1(players)
55
+ end
56
+ end
57
+
58
+ # 好友对战
59
+ def pvp2(friend_loginname, players)
60
+ if @loginname && players[@loginname] && friend_loginname && !friend_loginname.empty? && @loginname != friend_loginname
61
+ @pvp_state = MATCHING
62
+ @matching_retry_times = 0
63
+ @current_friend_loginname = friend_loginname
64
+ send_message_pvp2_ready friend_loginname
65
+ puts "#{@loginname} friend battle ready, state: #{@pvp_state}"
66
+
67
+ matching2(players)
68
+ end
69
+ end
70
+
71
+ def cancel_matching(reason = nil)
72
+ if @pvp_state == MATCHING
73
+ friend_loginname = @current_friend_loginname
74
+ @pvp_state = IDLE
75
+ @current_friend_loginname = nil
76
+ send_message_matching_canceled(reason)
77
+
78
+ friend_loginname
79
+ end
80
+ end
81
+
82
+ def escape_pvp
83
+ if @pvp_state == BATTLING && @current_opponent
84
+ @current_opponent.win("#{@loginname} 逃跑了")
85
+ end
86
+ end
87
+
88
+ def win(reason = nil)
89
+ @current_battle = nil
90
+ @pvp_state = IDLE
91
+ if @current_friend_loginname
92
+ @current_friend_loginname = nil
93
+ else
94
+ @pvp1_wins += 1
95
+ end
96
+ send_message_won(reason)
97
+ @current_opponent.current_battle = nil
98
+ @current_opponent.pvp_state = IDLE
99
+ @current_opponent.current_friend_loginname = nil
100
+ @current_opponent.send_message_lost
101
+ end
102
+
103
+ def stjzb(action)
104
+ @current_battle.act(self, action) if @current_battle
105
+ end
106
+
107
+ def battling!
108
+ @pvp_state = BATTLING
109
+ end
110
+
111
+ def send_message_welcome
112
+ send_message 'msg1', "欢迎来到 石头剪子布 大战!"
113
+ end
114
+
115
+ def send_message_simple_logined
116
+ send_message 'simple-logined', @loginname
117
+ end
118
+
119
+ def send_message_loggedout(reason = nil)
120
+ send_message 'loggedout', reason || '已退出'
121
+ end
122
+
123
+ def send_message_pvp1_ready
124
+ send_message 'pvp-ready', '匹配对手中'
125
+ end
126
+
127
+ def send_message_pvp2_ready(friend_loginname)
128
+ send_message 'pvp-ready', "匹配 #{friend_loginname} 中"
129
+ end
130
+
131
+ def send_message_matching
132
+ send_message 'matching', '.'
133
+ end
134
+
135
+ def send_message_matching_canceled(reason = nil)
136
+ part = '匹配被取消'
137
+ send_message 'matching-canceled',
138
+ reason ? [ reason, part ].join(', ') : part
139
+ end
140
+
141
+ def send_message_matched(instruction)
142
+ send_message 'matched', "#{@loginname} 对 #{@current_opponent.loginname}, #{instruction}"
143
+ end
144
+
145
+ def send_message_won(reason = nil)
146
+ word = '赢了!'
147
+ send_message 'won',
148
+ [
149
+ reason ? [ reason, word ].join(', ') : word,
150
+ @pvp1_wins
151
+ ]
152
+ end
153
+
154
+ def send_message_lost
155
+ send_message 'lost', '输了。'
156
+ end
157
+
158
+ def send_message_round_finished(round, compare)
159
+ send_message 'round-finished',
160
+ [ round, compare, @loginname, @current_action, @current_win_rounds, @current_opponent.loginname, @current_opponent.current_action, @current_opponent.current_win_rounds ]
161
+ end
162
+
163
+ private
164
+
165
+ # pvp1匹配,隔3秒主动匹配1次,重试10次,不成功cancel
166
+ def matching1(players)
167
+ EM.add_timer(3) {
168
+ if @loginname && @pvp_state == MATCHING
169
+ puts "#{@loginname} matching, retry: #{@matching_retry_times}"
170
+ opponent = players.values.select{|_ws| _ws != self and _ws.pvp_state == MATCHING and _ws.current_friend_loginname.nil? }.sample
171
+ if opponent
172
+ StjzbServer::Stjzb.new(self, opponent)
173
+ elsif @matching_retry_times < 10
174
+ send_message_matching
175
+ @matching_retry_times += 1
176
+ matching1(players)
177
+ else
178
+ cancel_matching('没有找到对手')
179
+ puts "no opponent, matching canceled, state: #{@pvp_state}"
180
+ end
181
+ else
182
+ puts "ignore matching"
183
+ end
184
+ }
185
+ end
186
+
187
+ # pvp2匹配
188
+ def matching2(players)
189
+ puts "#{@loginname} matching #{@current_friend_loginname}, retry: #{@matching_retry_times}"
190
+ if @pvp_state == MATCHING
191
+ opponent = players[@current_friend_loginname]
192
+ if opponent && opponent.pvp_state == MATCHING && opponent.current_friend_loginname == @loginname
193
+ StjzbServer::Stjzb.new(self, opponent)
194
+ elsif @matching_retry_times < 10
195
+ send_message_matching
196
+ @matching_retry_times += 1
197
+ EM.add_timer(3) {
198
+ matching2(players)
199
+ }
200
+ else
201
+ friend_loginname = cancel_matching("#{@current_friend_loginname} 没有反应")
202
+ puts "#{friend_loginname} not pong, matching canceled, state: #{@pvp_state}"
203
+ end
204
+ else
205
+ puts "ignore, state: #{@pvp_state}"
206
+ end
207
+ end
208
+
209
+ def send_message(act, msg)
210
+ send Oj.dump([ act, msg ])
211
+ end
212
+
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,3 @@
1
+ class Settings < Settingslogic
2
+ source File.expand_path('../../../application.yml', __FILE__)
3
+ end
@@ -0,0 +1,65 @@
1
+ module StjzbServer
2
+ class Stjzb
3
+ attr_accessor :players, :round
4
+
5
+ SHI_TOU = 1
6
+ JIAN_ZI = 2
7
+ BU = 3
8
+
9
+ # 5局3胜
10
+ def initialize(player1, player2)
11
+ player1.current_win_rounds = 0
12
+ player2.current_win_rounds = 0
13
+ player1.current_action = nil
14
+ player2.current_action = nil
15
+ @players = [ player1, player2 ]
16
+ @round = 1
17
+ @target = 3
18
+
19
+ player1.current_battle = player2.current_battle = self
20
+ player1.current_opponent, player2.current_opponent = player2, player1
21
+ player1.battling!
22
+ player2.battling!
23
+
24
+ instruction = "#{@target * 2 - 1}局#{@target}胜"
25
+ player2.send_message_matched(instruction)
26
+ player1.send_message_matched(instruction)
27
+ puts "#{player1.loginname} vs #{player2.loginname}, #{@target}/#{@target * 2 - 1}"
28
+ end
29
+
30
+ def act(player, action)
31
+ player.current_action = action.to_i
32
+ if player.current_opponent.current_action
33
+ act1, act2 = player.current_action, player.current_opponent.current_action
34
+ case act1 <=> act2
35
+ when -1
36
+ act1 - act2 == -1 ? bigger(player, player.current_opponent) : bigger(player.current_opponent, player)
37
+ when 0
38
+ draw(player, player.current_opponent)
39
+ when 1
40
+ act1 - act2 == 2 ? bigger(player, player.current_opponent) : bigger(player.current_opponent, player)
41
+ end
42
+
43
+ player.current_action = player.current_opponent.current_action = nil
44
+ @round += 1
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def draw(player1, player2)
51
+ player1.send_message_round_finished(@round, '=')
52
+ player2.send_message_round_finished(@round, '=')
53
+ end
54
+
55
+ def bigger(player1, player2)
56
+ player1.current_win_rounds += 1
57
+ player1.send_message_round_finished(@round, '>')
58
+ player2.send_message_round_finished(@round, '<')
59
+ if player1.current_win_rounds >= @target
60
+ player1.win
61
+ end
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module StjzbServer
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,12 @@
1
+ require 'em-websocket'
2
+ require 'oj'
3
+ require 'settingslogic'
4
+
5
+ %w[
6
+ version
7
+ connection
8
+ settings
9
+ stjzb
10
+ ].each do |file|
11
+ require File.expand_path("../ss/#{file}", __FILE__)
12
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ss/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "stzjb_server"
8
+ spec.version = StjzbServer::VERSION
9
+ spec.authors = ["takafan"]
10
+ spec.email = ["takafan@163.com"]
11
+ spec.summary = %q{石头剪子布服务端}
12
+ spec.description = nil
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_dependency "em-websocket"
24
+ spec.add_dependency "oj"
25
+ spec.add_dependency "settingslogic"
26
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stzjb_server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - takafan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: em-websocket
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: oj
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: settingslogic
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: ''
84
+ email:
85
+ - takafan@163.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - Gemfile
92
+ - LICENSE.txt
93
+ - README.md
94
+ - Rakefile
95
+ - application.rb
96
+ - application.yml.example
97
+ - lib/ss/connection.rb
98
+ - lib/ss/settings.rb
99
+ - lib/ss/stjzb.rb
100
+ - lib/ss/version.rb
101
+ - lib/stjzb_server.rb
102
+ - stjzb_server.gemspec
103
+ homepage: ''
104
+ licenses:
105
+ - MIT
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.2.1
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: "石头剪子布服务端"
127
+ test_files: []