pacmanrb 0.1.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +46 -0
- data/app/components/board_component.rb +100 -0
- data/app/components/hud_component.rb +15 -0
- data/app/controllers/application_controller.rb +24 -0
- data/app/controllers/game_controller.rb +68 -0
- data/app/controllers/game_over_controller.rb +26 -0
- data/app/controllers/home_controller.rb +22 -0
- data/app/models/application_record.rb +7 -0
- data/app/models/high_score.rb +7 -0
- data/app/state/application_state.rb +6 -0
- data/app/state/game_over_state.rb +9 -0
- data/app/state/game_state.rb +9 -0
- data/app/state/home_state.rb +7 -0
- data/app/views/game/show_view.rb +32 -0
- data/app/views/game_over/show_view.rb +40 -0
- data/app/views/home/show_view.rb +42 -0
- data/app/views/layouts/application_layout.rb +34 -0
- data/config/database.rb +14 -0
- data/config/routes.rb +7 -0
- data/db/development.sqlite3 +0 -0
- data/db/migrate/20260719010011_create_high_scores.rb +11 -0
- data/db/schema.rb +20 -0
- data/db/seeds.rb +1 -0
- data/db/test.sqlite3 +0 -0
- data/exe/pacmanrb +7 -0
- data/lib/pacman/application.rb +13 -0
- data/lib/pacman/arcade/brains.rb +46 -0
- data/lib/pacman/arcade/direction.rb +19 -0
- data/lib/pacman/arcade/ghost.rb +72 -0
- data/lib/pacman/arcade/layouts.rb +28 -0
- data/lib/pacman/arcade/maze.rb +67 -0
- data/lib/pacman/arcade/mode_schedule.rb +52 -0
- data/lib/pacman/arcade/navigator.rb +36 -0
- data/lib/pacman/arcade/pellet_field.rb +39 -0
- data/lib/pacman/arcade/player.rb +42 -0
- data/lib/pacman/arcade/position.rb +15 -0
- data/lib/pacman/arcade/scoreboard.rb +43 -0
- data/lib/pacman/arcade/spawn.rb +8 -0
- data/lib/pacman/arcade/world.rb +169 -0
- data/lib/pacman/board_scale.rb +42 -0
- data/lib/pacman/sprites.rb +145 -0
- data/lib/pacman/version.rb +5 -0
- data/lib/pacman.rb +22 -0
- metadata +127 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pacman
|
|
4
|
+
# Procedurally drawn actor sprites. A board cell is `scale` character rows by
|
|
5
|
+
# `scale * 2` columns; half-block characters double the vertical resolution,
|
|
6
|
+
# giving a square 2k x 2k pixel grid to draw circles and skirts on.
|
|
7
|
+
class Sprites
|
|
8
|
+
MOUTH_COSINE = 0.75
|
|
9
|
+
|
|
10
|
+
def self.player(scale:, direction:)
|
|
11
|
+
return ["██"] if scale == 1
|
|
12
|
+
|
|
13
|
+
sprite = new(scale)
|
|
14
|
+
sprite.draw { |y, x| sprite.pacman?(y, x, direction) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.ghost(scale:)
|
|
18
|
+
return ["██"] if scale == 1
|
|
19
|
+
|
|
20
|
+
sprite = new(scale)
|
|
21
|
+
sprite.draw { |y, x| sprite.ghost_body?(y, x) && !sprite.eye?(y, x) }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.frightened(scale:)
|
|
25
|
+
return ["▒▒"] if scale == 1
|
|
26
|
+
|
|
27
|
+
sprite = new(scale)
|
|
28
|
+
sprite.draw(texture: "▒") { |y, x| sprite.ghost_body?(y, x) && !sprite.eye?(y, x) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.cherry(scale:)
|
|
32
|
+
return ["● "] if scale == 1
|
|
33
|
+
|
|
34
|
+
new(scale).cherry
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.eaten(scale:)
|
|
38
|
+
return ["▀▀"] if scale == 1
|
|
39
|
+
|
|
40
|
+
sprite = new(scale)
|
|
41
|
+
sprite.draw { |y, x| sprite.eye?(y, x) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def initialize(scale)
|
|
45
|
+
@scale = scale
|
|
46
|
+
@pixels = scale * 2
|
|
47
|
+
@center = (@pixels - 1) / 2.0
|
|
48
|
+
@radius = scale - 0.15
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def draw(texture: nil)
|
|
52
|
+
(0...scale).map do |row|
|
|
53
|
+
(0...pixels).map do |col|
|
|
54
|
+
cell_char(yield(row * 2, col), yield(row * 2 + 1, col), texture)
|
|
55
|
+
end.join
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def cherry
|
|
60
|
+
body = draw { |y, x| berry?(y, x) }
|
|
61
|
+
add_stems(body)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def pacman?(y, x, direction)
|
|
65
|
+
circle?(y, x) && !mouth?(y, x, direction)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def ghost_body?(y, x)
|
|
69
|
+
return skirt?(x) && (x - center).abs <= radius if y == pixels - 1
|
|
70
|
+
return circle?(y, x) if y < scale
|
|
71
|
+
|
|
72
|
+
(x - center).abs <= radius
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def eye?(y, x)
|
|
76
|
+
return false if scale < 2
|
|
77
|
+
|
|
78
|
+
size = [scale / 2, 1].max
|
|
79
|
+
row = (pixels * 0.35).floor
|
|
80
|
+
return false unless (row...(row + size)).cover?(y)
|
|
81
|
+
|
|
82
|
+
left = (pixels * 0.3).floor
|
|
83
|
+
right = (pixels * 0.65).floor
|
|
84
|
+
(left...(left + size)).cover?(x) || (right...(right + size)).cover?(x)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
attr_reader :scale, :pixels, :center, :radius
|
|
90
|
+
|
|
91
|
+
BERRY_RADIUS = 0.42
|
|
92
|
+
BERRY_ROW = 1.4
|
|
93
|
+
BERRY_COLS = [0.55, 1.45].freeze
|
|
94
|
+
|
|
95
|
+
def berry?(y, x)
|
|
96
|
+
r = scale * BERRY_RADIUS
|
|
97
|
+
BERRY_COLS.any? do |col|
|
|
98
|
+
((y - (scale * BERRY_ROW))**2) + ((x - (scale * col))**2) <= r**2
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def add_stems(lines)
|
|
103
|
+
stem_rows = lines.take_while { |line| line.strip.empty? }.length
|
|
104
|
+
(0...stem_rows).each do |row|
|
|
105
|
+
t = (row + 1).to_f / (stem_rows + 1)
|
|
106
|
+
stem_columns(t).each { |col| lines[row][col] = "│" }
|
|
107
|
+
end
|
|
108
|
+
lines
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def stem_columns(t)
|
|
112
|
+
BERRY_COLS.map { |col| (scale + (((scale * col) - scale) * t)).round }.uniq
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def cell_char(top, bottom, texture)
|
|
116
|
+
return texture_char(top, bottom, texture) if texture
|
|
117
|
+
return "█" if top && bottom
|
|
118
|
+
return "▀" if top
|
|
119
|
+
return "▄" if bottom
|
|
120
|
+
|
|
121
|
+
" "
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def texture_char(top, bottom, texture)
|
|
125
|
+
(top || bottom) ? texture : " "
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def circle?(y, x)
|
|
129
|
+
((y - center)**2) + ((x - center)**2) <= radius**2
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def mouth?(y, x, direction)
|
|
133
|
+
vy = y - center
|
|
134
|
+
vx = x - center
|
|
135
|
+
length = Math.sqrt((vy**2) + (vx**2))
|
|
136
|
+
return false if length < radius * 0.15
|
|
137
|
+
|
|
138
|
+
((vy * direction.dy) + (vx * direction.dx)) / length > MOUTH_COSINE
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def skirt?(x)
|
|
142
|
+
((x * 4) / pixels).even?
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
data/lib/pacman.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "charming"
|
|
4
|
+
require "zeitwerk"
|
|
5
|
+
require_relative "../config/database"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
module Pacman
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
loader = Zeitwerk::Loader.new
|
|
12
|
+
loader.tag = "pacman"
|
|
13
|
+
loader.inflector.inflect("version" => "VERSION")
|
|
14
|
+
loader.push_dir(File.expand_path("pacman", __dir__), namespace: Pacman)
|
|
15
|
+
loader.push_dir(File.expand_path("../app/models", __dir__), namespace: Pacman)
|
|
16
|
+
loader.push_dir(File.expand_path("../app/state", __dir__), namespace: Pacman)
|
|
17
|
+
loader.push_dir(File.expand_path("../app/components", __dir__), namespace: Pacman)
|
|
18
|
+
loader.push_dir(File.expand_path("../app/views", __dir__), namespace: Pacman)
|
|
19
|
+
loader.push_dir(File.expand_path("../app/controllers", __dir__), namespace: Pacman)
|
|
20
|
+
loader.setup
|
|
21
|
+
|
|
22
|
+
require_relative "../config/routes"
|
metadata
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: pacmanrb
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Pando
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: charming
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: sqlite3
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '2.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: activerecord
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '8.1'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '8.1'
|
|
54
|
+
email:
|
|
55
|
+
- pandorocks@proton.me
|
|
56
|
+
executables:
|
|
57
|
+
- pacmanrb
|
|
58
|
+
extensions: []
|
|
59
|
+
extra_rdoc_files: []
|
|
60
|
+
files:
|
|
61
|
+
- LICENSE.txt
|
|
62
|
+
- README.md
|
|
63
|
+
- app/components/board_component.rb
|
|
64
|
+
- app/components/hud_component.rb
|
|
65
|
+
- app/controllers/application_controller.rb
|
|
66
|
+
- app/controllers/game_controller.rb
|
|
67
|
+
- app/controllers/game_over_controller.rb
|
|
68
|
+
- app/controllers/home_controller.rb
|
|
69
|
+
- app/models/application_record.rb
|
|
70
|
+
- app/models/high_score.rb
|
|
71
|
+
- app/state/application_state.rb
|
|
72
|
+
- app/state/game_over_state.rb
|
|
73
|
+
- app/state/game_state.rb
|
|
74
|
+
- app/state/home_state.rb
|
|
75
|
+
- app/views/game/show_view.rb
|
|
76
|
+
- app/views/game_over/show_view.rb
|
|
77
|
+
- app/views/home/show_view.rb
|
|
78
|
+
- app/views/layouts/application_layout.rb
|
|
79
|
+
- config/database.rb
|
|
80
|
+
- config/routes.rb
|
|
81
|
+
- db/development.sqlite3
|
|
82
|
+
- db/migrate/20260719010011_create_high_scores.rb
|
|
83
|
+
- db/schema.rb
|
|
84
|
+
- db/seeds.rb
|
|
85
|
+
- db/test.sqlite3
|
|
86
|
+
- exe/pacmanrb
|
|
87
|
+
- lib/pacman.rb
|
|
88
|
+
- lib/pacman/application.rb
|
|
89
|
+
- lib/pacman/arcade/brains.rb
|
|
90
|
+
- lib/pacman/arcade/direction.rb
|
|
91
|
+
- lib/pacman/arcade/ghost.rb
|
|
92
|
+
- lib/pacman/arcade/layouts.rb
|
|
93
|
+
- lib/pacman/arcade/maze.rb
|
|
94
|
+
- lib/pacman/arcade/mode_schedule.rb
|
|
95
|
+
- lib/pacman/arcade/navigator.rb
|
|
96
|
+
- lib/pacman/arcade/pellet_field.rb
|
|
97
|
+
- lib/pacman/arcade/player.rb
|
|
98
|
+
- lib/pacman/arcade/position.rb
|
|
99
|
+
- lib/pacman/arcade/scoreboard.rb
|
|
100
|
+
- lib/pacman/arcade/spawn.rb
|
|
101
|
+
- lib/pacman/arcade/world.rb
|
|
102
|
+
- lib/pacman/board_scale.rb
|
|
103
|
+
- lib/pacman/sprites.rb
|
|
104
|
+
- lib/pacman/version.rb
|
|
105
|
+
homepage: https://charming.sh/docs/examples/pacman/
|
|
106
|
+
licenses:
|
|
107
|
+
- MIT
|
|
108
|
+
metadata:
|
|
109
|
+
rubygems_mfa_required: 'true'
|
|
110
|
+
rdoc_options: []
|
|
111
|
+
require_paths:
|
|
112
|
+
- lib
|
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: 4.0.0
|
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
|
+
requirements:
|
|
120
|
+
- - ">="
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: '0'
|
|
123
|
+
requirements: []
|
|
124
|
+
rubygems_version: 4.0.16
|
|
125
|
+
specification_version: 4
|
|
126
|
+
summary: A Charming terminal user interface.
|
|
127
|
+
test_files: []
|