def __init__(self, pin, length): self._effect = Effects.RGB self._thread = None self._thread_terminate = False self._thread_running = False self.pixels = neopixel.NeoPixel(pin, length) self._length = length self.pixels[0] = (0, 255, 0) self.colour = Colour(0, 0, 20) self.paused = False self._brightness = 1.0 for i in range(1, length): self.pixels[i] = (0, 0, 20) self._backup = [] self._temperature_pixels = [] self.save_period = Config.TIME_TO_SAVE self.restore_timer = MyTimer(self.save_period, self.restore) self.dim_timer = MyTimer(self.save_period, self._dim) for i in range(0, self._length): self._backup.append(self.pixels[i]) self._prepare_temperature_pixels() self.saved = False
def __init__(self, settings, stats, screen, *args): """初始化靶机并设置其起始位置""" TargetSample.__init__(self) Sprite.__init__(self) self.settings = settings self.screen = screen self.stats = stats self.screen_rect = screen.get_rect() self.args = args self.target_shield_image = pygame.image.load( dir_path + r'\images\target_shield.png') # 靶机初始位置 self.rect.x = self.settings.x_target_position + args[ 0] * self.rect.width * 2 self.rect.y = self.settings.y_target_boundary # 存储靶机准确位置 self.x = float(self.rect.x) self.y = float(self.rect.y) self.timer = MyTimer() self.shield_timer = MyTimer() self.moving = False self.delay = self.args[4] # 靶机延时启动时长 if self.args[3]: # 带盾 self.image = self.target_shield_image self.life = 2 else: # 无盾 self.life = 1
def __init__(self, settings, screen, target): super().__init__() self.settings = settings self.screen = screen self.rect = pygame.Rect(target.rect.left, target.rect.bottom, target.rect.width, 3) self.y = float(self.rect.y) self.color = (0, 0, 0) self.speed = 3 self.timer = MyTimer()
class NoticeBar(Sprite): """靶机启动提示条""" def __init__(self, settings, screen, target): super().__init__() self.settings = settings self.screen = screen self.rect = pygame.Rect(target.rect.left, target.rect.bottom, target.rect.width, 3) self.y = float(self.rect.y) self.color = (0, 0, 0) self.speed = 3 self.timer = MyTimer() def update(self): """向下移动提示条""" if self.speed != 0: if self.y >= self.screen.get_rect( ).bottom - self.settings.y_target_boundary: # 到达底端时停止移动 self.speed = 0 else: self.y += self.speed self.rect.y = self.y def draw_bar(self): """绘制提示条""" pygame.draw.rect(self.screen, self.color, self.rect) def start_timer(self): self.timer.begin() def stop_timer(self): self.timer.stop() def reset_timer(self): self.timer.reset()
class Indicator: def __init__(self, pin, length): self._effect = Effects.RGB self._thread = None self._thread_terminate = False self._thread_running = False self.pixels = neopixel.NeoPixel(pin, length) self._length = length self.pixels[0] = (0, 255, 0) self.colour = Colour(0, 0, 20) self.paused = False self._brightness = 1.0 for i in range(1, length): self.pixels[i] = (0, 0, 20) self._backup = [] self._temperature_pixels = [] self.save_period = Config.TIME_TO_SAVE self.restore_timer = MyTimer(self.save_period, self.restore) self.dim_timer = MyTimer(self.save_period, self._dim) for i in range(0, self._length): self._backup.append(self.pixels[i]) self._prepare_temperature_pixels() self.saved = False def set_mode(self, mode): self.stop_loop() print("Mode: ", format(mode.value)) if mode == Effects.FIRE: self._start_fire(55, 80, 0.01) if mode == Effects.METEOR: self._start_meteor(255, 0, 255, 6, 64, 0.01) if mode == Effects.CYLON: self._start_cylon(128, 0, 0, 5, 0.01, 0) if mode == Effects.RGB: if self.colour == None: self.restore() self.pixels.auto_write = False self._effect = mode def _set_pixel(self, pixel, r, g, b): if pixel > self._length - 1: return if pixel < 0: return red = min(int(r), 255) green = min(int(g), 255) blue = min(int(b), 255) self.pixels[pixel] = (red, green, blue) def set_colour(self, r, g, b, transient=True, display_time=0, dim_after=0): if not transient: self.saved = False self.colour.rgbcolour = (int(r), int(g), int(b)) if self._effect != Effects.RGB: return self.pixels.fill((int(r), int(g), int(b))) self.pixels.show() if dim_after != 0: self.set_brightness(1.0) self.dim_timer.restart(dim_after) if not transient: print("Saving RGB") self.save() else: if display_time == 0: self.restore_timer.restart(self.save_period) else: self.restore_timer.restart(display_time) def set_brightness(self, brightness, fade=False): if self._effect != Effects.RGB: self._brightness = brightness return print("New brightness: " + format(brightness)) if not fade: for i in range(0, self._length): colour = self.pixels[i] new_colour = [0] * 3 for j in range(0, 3): new_colour[j] = colour[j] * brightness / self._brightness self._set_pixel(i, new_colour[0], new_colour[1], new_colour[2]) else: self.colour *= 1 colour2 = self.colour * 0.1 self.fade(colour2, 100, 3) self._brightness = brightness def _dim(self): self.set_brightness(0.1) self.pixels.show() def save(self): for i in range(0, self._length): self._backup[i] = self.pixels[i] self.saved = True def restore(self): print("restoring") self.restore_timer.stop() if (self._effect != Effects.RGB): self.set_mode(self._effect) return if not self.saved: self.set_colour(self.colour.r, self.colour.g, self.colour.b, transient=False, dim_after=5) else: for i in range(0, self._length): self.pixels[i] = self._backup[i] self.pixels.show() self.saved = False def pause(self): self.paused = True self.save() self.pixels.fill((0, 0, 0)) self.pixels.show() def unpause(self): if self._effect == Effects.RGB: self.restore() self.paused = False def _prepare_temperature_pixels(self): self.pixels.fill((0, 0, 0)) multiplier = 255 / self._length for i in range(0, self._length): self._set_pixel(i, round(i * multiplier), 0, round(255 - (i * multiplier))) self._temperature_pixels.append(self.pixels[i]) self.pixels[i] = self._backup[i] def set_temperature(self, temperature): if (self._effect != Effects.RGB): self.stop_loop() self.restore_timer.restart(self.save_period) self.pixels.fill((0, 0, 0)) count = round((temperature / 100) * self._length) self.pixels[0:count] = self._temperature_pixels[0:count] self.pixels.show() def set_level(self, level, colour=None): self.pixels.fill((0, 0, 0)) if colour == None: colour = self.colour count = round((level / 100) * self._length) for i in range(0, count): self._set_pixel(i, colour.r, colour.g, colour.b) self.pixels.show() def shoot(self): for i in range(0, self._length): self.pixels[i] = (0, 20, 0) time.sleep(0.100) for i in range(0, self._length): self.pixels[i] = (0, 0, 10) time.sleep(0.100) for i in range(0, self._length): self.pixels[i] = (0, 0, 0) time.sleep(0.100) def fade_from_to(self, colour1, colour2, steps, interval): while (self._thread_running): pass self._thread = threading.Thread(target=self._fade, args=(colour1, colour2, steps, interval)) self._thread.daemon = True self._thread.start() def fade(self, colour2, steps, interval): self.fade_from_to(self.colour, colour2, steps, interval) def _fade(self, colour1, colour2, steps, interval): self._thread_running = True lastUpdate = time.time() - interval interval = interval / steps for i in range(1, steps + 1): r = round(((colour1.r * (steps - i)) + (colour2.r * i)) / steps) g = round(((colour1.g * (steps - i)) + (colour2.g * i)) / steps) b = round(((colour1.b * (steps - i)) + (colour2.b * i)) / steps) while ((time.time() - lastUpdate) < interval): pass colour = Colour(r, g, b) for j in range(0, self._length): if not self.paused: self._set_pixel(j, colour.r, colour.g, colour.b) lastUpdate = time.time() self._thread_running = False self.colour = colour2 def blink(self, r, g, b): self.set_colour(r, g, b, transient=True, display_time=0.5) ### Effects ### # Ported from: https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ ### Base ### def stop_loop(self): self._thread_terminate = True while self._thread_running: pass ### Cylon ### def _start_cylon(self, r, g, b, EyeSize, SpeedDelay, ReturnDelay): while (self._thread_running): pass self._thread = threading.Thread(target=self._cylon, args=(r, g, b, EyeSize, SpeedDelay, ReturnDelay)) self._thread.daemon = True self._thread.start() def _cylon(self, red, green, blue, EyeSize, SpeedDelay, ReturnDelay): self._thread_terminate = False self._thread_running = True while not self._thread_terminate: if not self.paused: for i in range(0 - EyeSize, self._length + EyeSize): if self._thread_terminate: self._thread_running = False return self.pixels.fill((0, 0, 0)) self._set_pixel(i, round(red / 10), round(green / 10), round(blue / 10)) for j in range(1, EyeSize): self._set_pixel(i + j, red, green, blue) self._set_pixel(i + EyeSize, round(red / 10), round(green / 10), round(blue / 10)) if not self.paused: self.pixels.show() time.sleep(SpeedDelay) time.sleep(ReturnDelay) for i in range(self._length + EyeSize, 0 - EyeSize, -1): if self._thread_terminate: self._thread_running = False return self.pixels.fill((0, 0, 0)) self._set_pixel(i, round(red / 10), round(green / 10), round(blue / 10)) for j in range(EyeSize, 0, -1): self._set_pixel(i - j, red, green, blue) self._set_pixel(i - EyeSize, round(red / 10), round(green / 10), round(blue / 10)) if not self.paused: self.pixels.show() time.sleep(SpeedDelay) time.sleep(ReturnDelay) self._thread_running = False ### Fire ### def _start_fire(self, cooling, sparking, speed_delay): self._thread_terminate = False while (self._thread_running): pass self._thread = threading.Thread(target=self._fire, args=(cooling, sparking, speed_delay)) self._thread.daemon = True print("Starting a fire") self._thread.start() def _fire(self, cooling, sparking, speed_delay): heat = [0] * self._length cooldown = 0 self._thread_running = True while not self._thread_terminate: if not self.paused: for i in range(0, self._length): cooldown = random.randint( 0, round(((cooling * 10) / self._length) + 20)) if cooldown > heat[i]: heat[i] = 0 else: heat[i] = heat[i] - cooldown for i in range(self._length - 1, 3, -1): heat[i] = (heat[i - 1] + heat[i - 2] + heat[i - 2]) / 3 if random.randint(0, 255) < sparking: y = random.randint(0, 7) heat[y] = heat[y] + random.randint(160, 255) for i in range(0, self._length): self._set_pixel_heat_colour(i, heat[i]) if not self.paused: self.pixels.show() time.sleep(speed_delay) self._thread_running = False def _set_pixel_heat_colour(self, pixel, temperature): t192 = round((temperature / 255.0) * 191) heatramp = t192 & 0x3F heatramp <<= 2 if (t192 > 0x80): self._set_pixel(pixel, 255, 255, heatramp) elif (t192 > 0x40): self._set_pixel(pixel, 255, heatramp, 0) else: self._set_pixel(pixel, heatramp, 0, 0) ### Meteor ### def _start_meteor(self, red, green, blue, size, trail_decay, speed): self._thread_terminate = False while (self._thread_running): pass self._thread = threading.Thread(target=self._meteor, args=(red, green, blue, size, trail_decay, speed)) self._thread.daemon = True print("Pew pew") self._thread.start() def _meteor(self, red, green, blue, size, trail_decay, speed): self.pixels.fill((0, 0, 0)) self._thread_running = True while not self._thread_terminate: if not self.paused: for i in range(0, self._length * 2): # fade for j in range(0, self._length): if (random.randint(0, 10) < 5): self.fade_to_black(j, trail_decay) for j in range(0, size): if ((i - j) < self._length): self._set_pixel(i - j, red, green, blue) if not self.paused: self.pixels.show() if self._thread_terminate: self._thread_running = False return time.sleep(speed) self._thread_running = False def fade_to_black(self, pixel, fade_value): old_colour = self.pixels[pixel] r = old_colour[0] g = old_colour[1] b = old_colour[2] if r <= 10: r = 0 else: r = r - (r * fade_value / 256) if g <= 10: g = 0 else: g = g - (g * fade_value / 256) if b <= 10: b = 0 else: b = b - (b * fade_value / 256) self._set_pixel(pixel, r, g, b)
def evaluate_one_py(py_name, all_func_info, stu_name, gold_funcs, verbose): if verbose > 0: print('\nStart evaluating %s %s' % (py_name, stu_name), flush=True, file=sys.stderr) try: with MyTimer(max_time_for_import_one_py): this_funcs = get_funcs_in_one_module(py_name, verbose) #将学生代码的函数提取出来 except Exception as e: print_a_thing_verbose_1( 'import module %s timeout: %s %s' % (py_name, type(e).__name__, e), verbose) total_score = 0. func_scores = [] func_names = [] for (func_name, score, time_ratio, test_case_file_name) in all_func_info: #批阅的函数名 分数 测试用例文件 时间? func_names.append(func_name) if this_funcs is None: #判断是否有函数 func_scores.append(0.) print_a_thing_verbose_1( 'module %s does not contain func: %s' % (py_name, func_name), verbose) continue correct_case_cnt = 0. lines = get_all_lines(test_case_file_name) #读文件,测试用例文件 total_case_cnt = len(lines) #测试用例个数 gold_func = gold_funcs.get(func_name) #返回gold文件里的特定的函数名(要评分的那些函数) assert gold_func is not None #检查函数名 if this_funcs.get(func_name) is None: lines = [] #如果没有相符合的函数名 测试用例文件也没有相符合的 for i_input, one_input in enumerate( lines ): #enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标 i是下标,one是数据 one_input_line = one_input.strip() #移除空格换行符 assert len(one_input_line) > 0 #检查长度 one_input = eval( one_input_line) #eval() 函数用来执行一个字符串表达式,并返回表达式的值(字符串转为列表) one_input_for_sys = eval(one_input_line) start_time = time.time() gold_result = gold_func(*one_input) #将测试用例放入函数里执行?(数组第一个元素?) end_time = time.time() time_gap_sec = end_time - start_time #执行时间 try: with MyTimer( max(time_gap_sec * time_ratio, min_time_for_run_one_func)): result = this_funcs[func_name]( *one_input_for_sys) #将测试用例放到学生函数里执行? except Exception as e: #发生异常执行这一块 print_msg_verbose_2(py_name, func_name, i_input, '%s : %s' % (type(e).__name__, e), verbose) continue if gold_result is None: print(*one_input, gold_result) if result == gold_result: #判断学生结果和答案结果是否相等 correct_case_cnt += 1 #通过的正确的测试用例个数+1 print_msg_verbose_2(py_name, func_name, i_input, 'passed', verbose) else: print_msg_verbose_2(py_name, func_name, i_input, 'failed', verbose) this_func_score = score * correct_case_cnt / total_case_cnt #分数就是通过的用例/总用例 func_scores.append(this_func_score) #函数的得分列表 total_score += this_func_score #总分数 print_func_score_verbose_1(py_name, stu_name, func_name, score, correct_case_cnt, total_case_cnt, verbose) print_score_summary(py_name, stu_name, total_score, func_names, func_scores)
class Target(TargetSample, Sprite): """靶机类""" def __init__(self, settings, stats, screen, *args): """初始化靶机并设置其起始位置""" TargetSample.__init__(self) Sprite.__init__(self) self.settings = settings self.screen = screen self.stats = stats self.screen_rect = screen.get_rect() self.args = args self.target_shield_image = pygame.image.load( dir_path + r'\images\target_shield.png') # 靶机初始位置 self.rect.x = self.settings.x_target_position + args[ 0] * self.rect.width * 2 self.rect.y = self.settings.y_target_boundary # 存储靶机准确位置 self.x = float(self.rect.x) self.y = float(self.rect.y) self.timer = MyTimer() self.shield_timer = MyTimer() self.moving = False self.delay = self.args[4] # 靶机延时启动时长 if self.args[3]: # 带盾 self.image = self.target_shield_image self.life = 2 else: # 无盾 self.life = 1 def update_shield(self): """更新护盾状态""" if self.args[3] and self.shield_timer.pass_time > 5: # 带盾靶机每5秒会重新生成护盾 self.shield_timer.reset() if self.life < 2: # 重新生成护盾,靶机变为蓝色 self.image = self.target_shield_image self.life = 2 def check_edges(self): """如果靶机位于活动范围边缘,就返回True""" if self.rect.bottom > self.screen_rect.bottom - self.settings.y_target_boundary: return True elif self.rect.top < self.settings.y_target_boundary: return True return False def blitme(self): """在指定位置绘制靶机""" self.screen.blit(self.image, self.rect) def kill(self): """重写kill(),响应靶机被击中""" if self.timer.pass_time > 0.5: # 0.5秒内的碰撞视为击中同一个靶机 if self.life > 1: # 击破护盾,靶机变为灰色 if self.stats.sound_state: shield_broken_sound.play() # 击破护盾音效 self.life -= 1 self.image = self.target_image self.timer.reset() else: # 击破靶机 if self.stats.sound_state: target_broken_sound.play() self.timer.stop() self.shield_timer.stop() super().kill() def start_timer(self): self.timer.begin() def stop_timer(self): self.timer.stop() def reset_timer(self): self.timer.reset() def start_shield_timer(self): self.shield_timer.begin() def stop_shield_timer(self): self.shield_timer.stop() def reset_shield_timer(self): self.shield_timer.reset()
def run_game(): pygame.init() # 设置窗口 os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (128, 60) settings = Settings() screen = pygame.display.set_mode( (settings.screen_width, settings.screen_height)) pygame.display.set_caption("Shooting Practice") # 背景图 dir_path = os.path.dirname(os.path.abspath(__file__)) background = pygame.image.load(dir_path + r'\images\background.jpg').convert() # 创建枪支、子弹编组 gun = Gun(settings, screen) bullets = Group() # 创建全局计时器 overall_timer = MyTimer() # 创建靶机编组、提示条编组 target_sample = TargetSample() targets = Group() notice_bars = Group() # 创建用于存储游戏统计信息的实例 stats = GameStats(settings, overall_timer) # 文件读写 io_helper = IOHelper(stats) # 创建信息显示板 running_info = RunningInfo(settings, screen, stats) win_info = WinInfo(settings, screen, stats, io_helper) failed_info = FailedInfo(screen, stats) # 创建输入框 pregame_info = PregameInfo(settings, screen, stats) # 开始游戏主循环 while True: # 检查事件 func.check_events(settings, screen, stats, running_info, win_info, failed_info, gun, targets, bullets, pregame_info, notice_bars) # 更新屏幕 func.common_update_screen(background, settings, screen, stats, running_info, gun, target_sample, targets, bullets, notice_bars) # 游戏进行中,更新枪支、子弹、靶机提示条、靶机位置 if stats.game_state == GameState.RUNNING: gun.update() func.update_bullets(settings, screen, stats, targets, bullets, notice_bars, win_info, io_helper) func.update_notice(notice_bars) func.update_targets(targets) elif stats.game_state == GameState.PREGAME: pregame_info.draw_pregame_info() elif stats.game_state == GameState.GAME_OVER: failed_info.show_info() elif stats.game_state == GameState.GAME_FINISH: win_info.show_info() # 让最近绘制的屏幕可见 pygame.display.flip()