Skip to content

Instantly share code, notes, and snippets.

@obelisk68
Last active October 23, 2020 02:04
Show Gist options
  • Save obelisk68/6c9869c0802366cafd614f3ed62be557 to your computer and use it in GitHub Desktop.
Save obelisk68/6c9869c0802366cafd614f3ed62be557 to your computer and use it in GitHub Desktop.
StarTrek Game (Ruby)
require "curses"
class StarTrek
class DisplayIO
Width = Curses.cols
UpperH = 10
def initialize
Curses.init_screen
Curses.noraw
Curses.echo
Curses.curs_set(1) #カーソルを表示する
@upper = Curses::Window.new(UpperH, Width, 0, 0)
@lower = Curses::Window.new(Curses.lines - UpperH, Width, UpperH, 0)
@lower.scrollok(true)
end
attr_reader :lower
def refresh
@upper.refresh
end
def long_range_sensor(ary, ship)
w = Quadrant::W
w.times do |y|
@upper.setpos(y, 0)
@upper << " "
w.times do |x|
@upper.setpos(y, x * 4 + 1)
@upper << ary[y * w + x]
end
end
x, y = ship.qx, ship.qy
@upper.setpos(y, x * 4)
@upper << "["
@upper.setpos(y, x * 4 + 4)
@upper << "]"
end
def short_range_sensor(ship)
left = 4 * Quadrant::W + 2
Sector::H.times do |y|
@upper.setpos(y, left)
@upper << ship.sector.field[y].join
end
@upper.setpos(ship.y, left + ship.x)
@upper << "E"
end
def disp_status(ary)
left = 4 * Quadrant::W + 2 + Sector::W + 2
ary.each_with_index do |(name, value), y|
@upper.setpos(y, left)
@upper << name
@upper.setpos(y, left + 11)
@upper << value.to_s
end
end
def input(str)
@lower << str
@lower.getstr
end
def puts(str)
@lower << str.to_s + "\n"
end
def input_int(message, max)
begin
i = input(message).to_i
end until 1 <= i && i <= max
i
end
def finish
Curses.close_screen
end
end #-----
class Quadrant
#field, visible
W = 8
Num = W * W
def initialize
enemy = generate(EnemiesNum, 5)
base = generate(BaseNum, 1)
star = [StarNum] * Num
@field = enemy.zip(base, star)
lrs_clear
end
attr_reader :field
def generate(num, max)
f = Array.new(Num, 0)
num.times do
begin
idx = rand(Num)
end until f[idx] <= max
f[idx] += 1
end
f
end
def probe(i)
@visible[i] = true
end
def status
@field.zip(@visible).map {|sector, v|
if v
sector.join + " "
else
"*** "
end
}
end
def lrs_clear
@visible = Array.new(Num, false)
end
def enemy_num() @field.map(&:first).sum end
end #-----
class Sector
#ship, field
W = H = 8
def initialize(ship)
@ship = ship
@field = Array.new(H) {Array.new(W) {"."}}
@field[@ship.y][@ship.x] = "E"
data = @ship.q.field[@ship.q_pos]
data.zip(%W(K B *)).each {|n, char| generate(n, char)}
end
attr_reader :field
def generate(n, char)
n.times do
begin
x = rand(W)
y = rand(H)
end until @field[y][x] == "."
@field[y][x] = char
end
end
def enemy_num
@ship.q.field[@ship.q_pos].first
end
end #-----
class Ship
#q, q_pos, x, y, io, energy, shield, photons, sector
include Math
Energy = 4000
PhotonMax = 10
def initialize(quadrant, io)
@q = quadrant
@io = io
@energy = Energy
@shield = 0
@photons = PhotonMax
random_pos
end
attr_reader :q, :q_pos, :energy, :shield, :photons, :x, :y, :sector
def short_move
θ, dist = input_move(0)
#TODO
end
def long_move
#TODO: 宇宙嵐
θ, dist = input_move(1)
x0 = qx * Sector::W + @x + dist * sin(θ)
y0 = qy * Sector::H + @y - dist * cos(θ)
x0 = (x0 / Sector::W).div(1)
y0 = (y0 / Sector::H).div(1)
return if x0 == qx && y0 == qy
@io.puts("Outer Sector Move")
if x0 < 0 || x0 >= Quadrant::W || y0 < 0 || y0 >= Quadrant::W
@io.puts(" Out of Range!")
random_pos
else
calc_pos(x0, y0)
end
end
def input_move(i)
str = %W(Short Long)[i]
@io.puts("\n#{str} Warp")
dir = @io.input_int(" direction(1-360):", 360).to_f
dist = @io.input_int(" distance(1-100):", 100)
[dir / 180 * PI, dist]
end
def random_pos
@q_pos = rand(Quadrant::Num)
@q.lrs_clear
jump_ship
end
def calc_pos(x0, y0)
@q_pos = y0 * Quadrant::W + x0
jump_ship
end
def jump_ship
@x = rand(Sector::W)
@y = rand(Sector::H)
@sector = Sector.new(self)
probe
end
def probe
[0, -1, 1].repeated_permutation(2) do |dx, dy|
x0 = qx + dx
y0 = qy + dy
next if x0 < 0 || x0 >= Quadrant::W
next if y0 < 0 || y0 >= Quadrant::W
@q.probe(y0 * Quadrant::W + x0)
end
end
def qx() @q_pos % Quadrant::W end
def qy() @q_pos / Quadrant::W end
end #-----
end
class StarTrek
EnemiesNum = 25
StarNum = 7
BaseNum = 4
def initialize
@io = DisplayIO.new
@star_date = 3500
@years_left = EnemiesNum.to_f
@quadrant = Quadrant.new
@ship = Ship.new(@quadrant, @io)
end
def main_loop
loop do
screen_update
input_command
#enemy_attack
#break_down
#event(日にちの処理など)
#break if end?
end
finish
end
def screen_update
@io.long_range_sensor(@quadrant.status, @ship)
@io.short_range_sensor(@ship)
disp_status
@io.refresh
end
def disp_status
names = ["STAR DATE", "YEARS LEFT", "QUADRANT", "SECTOR", "ENERGY",
"SHIELD", "PHOTONS", "KLINGONS"]
values = [@star_date, @years_left, "#{@ship.qx + 1} - #{@ship.qy + 1}",
"#{@ship.x + 1} - #{@ship.y + 1}", @ship.energy, @ship.shield,
@ship.photons, @quadrant.enemy_num]
@io.disp_status(names.zip(values))
end
def input_command
#TODO: シールド、フェイザー砲、光子魚雷
case @io.input_int("\nCommand?(1:Short Warp, 2:Long Warp) ", 2)
when 1
@ship.short_move
when 2
@ship.long_move
end
end
def finish() @io.finish end
def self.sortie
new.main_loop
end
end
StarTrek.sortie
#故障:ロングレンジセンサー、ショートレンジセンサー、エンジン(インパルス、ワープ)、シールド、フェイザー砲、光子魚雷
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment