VimGolf源码解析:Challenge模型中的分数计算逻辑与数据库设计
【免费下载链接】vimgolfReal Vim ninjas count every keystroke - do you?项目地址: https://gitcode.com/gh_mirrors/vi/vimgolf
VimGolf是一个让开发者通过计算按键次数来比拼Vim技巧的平台,其核心功能围绕挑战(Challenge)和提交(Entry)展开。本文将深入解析Challenge模型中的分数计算逻辑与数据库设计,帮助开发者理解如何通过代码实现高效的分数管理系统。
Challenge模型的核心功能与关联关系
在VimGolf系统中,Challenge模型是核心数据结构,定义在app/models/challenge.rb文件中。该模型继承自ActiveRecord::Base,通过ORM映射与数据库表关联,主要功能包括管理挑战的基本信息、处理用户提交的解决方案以及计算分数排名。
Challenge模型与其他模型的关联关系如下:
belongs_to :user:每个挑战属于一个创建者has_many :entries, dependent: :destroy:一个挑战可以有多个用户提交的解决方案,当挑战被删除时,相关提交也会被级联删除
分数计算的核心逻辑
VimGolf的核心竞争力在于精确的分数计算和排名系统。Challenge模型中实现了多种分数相关的方法,这些方法共同构成了完整的分数管理体系。
1. 顶级提交筛选(top_entries)
def top_entries Entry.from( entries.select( '*', 'row_number() OVER (PARTITION BY user_id ORDER BY score, created_at) as user_ranked_entry' ), :entries ) .where(user_ranked_entry: 1) .order([:score, :created_at]) end这个方法使用SQL窗口函数(window function)实现了关键功能:
- 按用户ID分区(PARTITION BY user_id)
- 对每个用户的提交按分数(升序)和创建时间(升序)排序
- 为每个用户的最佳提交(分数最低且最早提交)分配排名1
- 最终返回所有用户的最佳提交,并按分数和时间排序
2. 分数统计方法
基于top_entries方法,Challenge模型提供了多种分数统计功能:
# 获取最佳分数 def best_score result = top_entries.first result&.score end # 获取最差分数 def worst_score result = top_entries.last result&.score end # 获取特定用户的最佳分数 def best_player_score(player_id) result = top_entries .where(user_id: player_id) .first result&.score end这些方法为前端展示和排行榜功能提供了数据支持,确保用户能够实时了解挑战的分数分布情况。
3. 解决方案可见性控制
为了平衡竞争性和学习性,VimGolf实现了基于用户角色的解决方案可见性控制:
def allowed_entries(current_user) top = top_entries # 挑战创建者和管理员可以查看所有提交 return [top, 0] if owner?(current_user) # 参与挑战的用户可以查看自己及排名低于自己的提交 if competitor?(current_user) # 用户的最佳提交 user_top = top.detect { |e| e.user_id == current_user.id } # 相同分数的提交索引 index = top.index { |e| e.score == user_top.score } solution_offset = [index - 5, 0].max [top[solution_offset, top.size], solution_offset] # 未参与挑战的用户只能查看最差的20%提交 else solution_offset = (top.size * 0.2).ceil [top.last(solution_offset), top.size - solution_offset] end end这个功能通过app/models/challenge.rb中的allowed_entries方法实现,确保了平台的公平性和学习价值。
数据库设计与性能优化
VimGolf的数据库设计围绕Challenge和Entry两个核心表展开,通过精心设计的字段和索引确保了系统的高效运行。
1. 核心表结构
根据db/schema.rb文件定义,主要表结构如下:
challenges表:存储挑战基本信息
create_table "challenges", force: :cascade do |t| t.string "title", null: false t.text "description" t.text "diff" t.text "input", null: false t.string "input_type", null: false t.text "output", null: false t.string "output_type", null: false t.string "legacy_urlkey", limit: 24 t.integer "user_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false # 索引定义... endentries表:存储用户提交的解决方案
create_table "entries", force: :cascade do |t| t.binary "script", null: false # 存储Vim脚本 t.integer "score", null: false # 存储计算出的分数 t.integer "user_id", null: false t.integer "challenge_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false # 索引定义... end2. 索引优化
为了提高查询性能,系统在关键字段上创建了索引:
# entries表索引 t.index ["challenge_id", "score", "created_at"], name: "index_entries_on_challenge_id_and_score_and_created_at" t.index ["challenge_id"], name: "index_entries_on_challenge_id" t.index ["user_id"], name: "index_entries_on_user_id"复合索引index_entries_on_challenge_id_and_score_and_created_at对分数查询性能至关重要,它支持了top_entries方法中的排序和筛选操作,使得即使在大量提交的情况下也能快速获取排名数据。
3. 数据迁移
数据库结构的变更通过迁移文件管理,如db/migrate/20210425154000_create_tables.rb定义了初始表结构,包括score字段的创建:
create_table :entries do |t| t.binary :script, null: false t.integer :score, null: false # 其他字段... t.index [:challenge_id, :score, :created_at] end分数计算的扩展实现
除了Challenge模型中的方法外,系统还在其他模块中实现了分数相关功能:
1. 仓库层封装
app/repositories/repository_challenge.rb提供了仓库层封装,进一步抽象了分数查询逻辑:
# 获取特定挑战的最差分数 def self.worst_score(challenge_urlkey) Challenge.find_by_urlkey(challenge_urlkey).worst_score end # 获取特定分数以下的解决方案 def self.bellow_score(challenge_urlkey, score) Challenge.find_by_urlkey(challenge_urlkey) .remaining_solutions(score) .order(score: :asc) .first&.score || 0 end2. 测试用例中的分数验证
在测试代码中也可以看到分数逻辑的验证,如spec/requests/submit_entry_spec.rb:
expect(entries.first.score).to eq(2)这些测试确保了分数计算逻辑的正确性和稳定性。
总结
VimGolf的分数计算系统通过Challenge模型、数据库设计和查询优化三个层面实现了高效、公平的分数管理。核心亮点包括:
- 使用SQL窗口函数实现每个用户最佳提交的筛选
- 基于角色的解决方案可见性控制,平衡竞争性和学习性
- 精心设计的数据库索引优化查询性能
- 清晰的代码组织结构,将业务逻辑封装在模型和仓库层
通过深入理解这些实现细节,开发者可以学习如何构建高性能的评分系统,以及如何在Ruby on Rails应用中优化复杂查询。VimGolf的源码为我们展示了如何将数据库设计、ORM使用和业务逻辑有机结合,创造出既高效又易于维护的应用系统。
要开始使用VimGolf,你可以克隆仓库:git clone https://gitcode.com/gh_mirrors/vi/vimgolf,然后按照项目文档进行安装和配置,体验这个充满乐趣的Vim技巧比拼平台。
【免费下载链接】vimgolfReal Vim ninjas count every keystroke - do you?项目地址: https://gitcode.com/gh_mirrors/vi/vimgolf
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考