-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpackman.rb
executable file
·153 lines (137 loc) · 3.51 KB
/
packman.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/ruby
# -*- mode: ruby; coding: utf-8-unix -*-
require "curses"
require 'character'
SPACE = ' '
DOT = '.'
WALL = '#'
def show(time, score, input_history, field)
clear
addstr "TIME: #{time}\tSCORE: #{score}\n"
addstr "INPUT: #{input_history.join}\n"
addstr "PRESS 'q' to quit, 'u' to undo\n"
addstr field.map { |row| row.join }.join("\n")
refresh
end
if ARGV.size == 0
puts "USAGE: ruby #{__FILE__} input_file"
exit
end
input = nil
open(ARGV[0], 'r') { |f| input = f.read.lines.map { |l| l.chomp } }
TIME_LIMIT = input.shift.to_i
WIDTH, HEIGHT = input.shift.split(/\s/).map { |x| x.to_i }
field = input.map { |l| l.split(//) }
dot_map = field.map { |row|
row.map { |x| if x == DOT or x == WALL then x else SPACE end }
}
packman = nil
enemies = []
HEIGHT.times { |y|
WIDTH.times { |x|
case field[y][x]
when '@'
packman = Packman.new(x, y, field)
when 'V', 'H'
enemies << "#{field[y][x]}.new(#{x}, #{y}, field, packman)"
when 'L', 'R', 'J'
enemies << "#{field[y][x]}.new(#{x}, #{y}, field)"
end
}
}
enemies.map! { |x| eval x }
score = 0
time = TIME_LIMIT
include Curses
# init_screen
history_suffix = '_history'
input_history = []
packman_history = []
enemies_history = []
score_history = []
field_history = []
dot_map_history = []
gameover = false
begin
show(time, score, input_history, field)
while !gameover
# 入力を受け取って
c = getch.chr
dx, dy = 0, 0
case c
when 'h'
dx = -1
when 'j'
dy = 1
when 'k'
dy = -1
when 'l'
dx = 1
when '.'
when 'u'
unless time == TIME_LIMIT
input_history.pop
%w(score packman enemies field dot_map).each { |obj_name|
eval("#{obj_name} = #{obj_name}#{history_suffix}.pop")
}
time += 1
end
show(time, score, input_history, field)
next
when 'q'
break
else
show(time, score, input_history, field)
next
end
# 指定された方向に行けなかったら無効
unless (0...WIDTH).include?(packman.x + dx) and
(0...HEIGHT).include?(packman.y + dy) and
field[packman.y + dy][packman.x + dx] != WALL
next
end
input_history << c
packman_history << packman.dup
enemies_history << Marshal.load(Marshal.dump(enemies))
score_history << score
field_history << Marshal.load(Marshal.dump(field))
dot_map_history << Marshal.load(Marshal.dump(dot_map))
# 敵動かして
enemies.each { |c|
if field[c.y][c.x] == packman.symbol
field[c.y][c.x] = packman.symbol
else
field[c.y][c.x] = dot_map[c.y][c.x]
end
c.move
field[c.y][c.x] = c.symbol
}
# パックマン動かして
field[packman.y][packman.x] = SPACE if field[packman.y][packman.x] == packman.symbol
packman.move_to(packman.x + dx, packman.y + dy)
field[packman.y][packman.x] = packman.symbol
# 衝突判定して
enemies.each { |c|
if (c.x == packman.x and c.y == packman.y) or
(c.x == packman.prev_x and c.y == packman.prev_y and
c.prev_x == packman.x and c.prev_y == packman.y)
gameover = true
break
end
}
# ポイント加算っと
if dot_map[packman.y][packman.x] == DOT
score += 1
dot_map[packman.y][packman.x] = SPACE
end
time -= 1
show(time, score, input_history, field)
gameover = true if time <= 0
end
addstr "\n"
addstr "GAMEOVER\n" if gameover
addstr "PRESS ANY KEY...\n"
getch
ensure
close_screen
end