I just saw this post:
http://www.iteye.com/topic/1112383
titled as OO 还是 procedural 小程序的设计.
It's kind of interesting. First, I love bowling (though just average player), secondly, it's a good design question for interviews.
Here is a picture from google for the score board.
For each round, there is a score section called frame. In each round we have a chance to play at most twice. If we get a strike, meaning we hit all 10 pins, then this round is over. Otherwise, we can roll twice.
Check wiki pages for more detail.
The first class we create is the frame:
public class BowlingFrame
{
private static final int STRIKE = 2;
private static final int SPARE = 1;
private static final int OPEN = 0;
private int[] rolls = new int[3];
private int bonus = OPEN;
public int score = 0;
public BowlingFrame(int firstRoll)
{
rolls[0] = firstRoll;
score = firstRoll;
if (firstRoll == 10)
bonus = STRIKE;
}
public BowlingFrame(int firstRoll, int secondRoll)
{
rolls[0] = firstRoll;
rolls[1] = secondRoll;
score = firstRoll + secondRoll;
if (firstRoll == 10)
bonus = STRIKE;
if (firstRoll + secondRoll == 10)
bonus = SPARE;
}
// This is for last frame, so we leave bonus as OPEN
public BowlingFrame(int firstRoll, int secondRoll, int thirdRoll)
{
rolls[0] = firstRoll;
rolls[1] = secondRoll;
rolls[2] = thirdRoll;
score = firstRoll + secondRoll + thirdRoll;
}
public int get1stScore()
{
return rolls[0];
}
public int get2ndScore()
{
return rolls[1];
}
public boolean isStrike()
{
return bonus == STRIKE;
}
public boolean isSpare()
{
return bonus == SPARE;
}
}
The behaviors (methods) are defined by another class, the score board class. There are 3 constructors corresponding to cases like strike, spare/open, and last round. It should be self explained.
The actual board class is like this:
public class BowlingScoreBoard
{
private BowlingFrame[] frames = new BowlingFrame[10];
private int index = 0;
public void addFrame(BowlingFrame bowlingFrame)
{
if (index >= 10)
throw new RuntimeException("can't go beyond 10 frames");
frames[index] = bowlingFrame;
// try to set bonus for two frames back in case of a strike there.
int p2 = index - 2;
if (p2 >= 0)
{
BowlingFrame bf = frames[p2];
if (bf.isStrike())
{
BowlingFrame previous = frames[index - 1];
if (previous.isStrike())
{
bf.score += previous.get1stScore() + bowlingFrame.get1stScore();
// previous.get1stScore() is just 10 since it's a strike
}
}
}
// try to set bonus for previous frame in case of a spare there.
int p1 = index - 1;
if (p1 >= 0)
{
BowlingFrame bf = frames[p1];
if (bf.isSpare())
{
bf.score += bowlingFrame.get1stScore();
}
else if (bf.isStrike() && !bowlingFrame.isStrike())
{
bf.score += bowlingFrame.get1stScore() + bowlingFrame.get2ndScore();
}
}
index++;
}
public int totalScore()
{
int ret = 0;
for (int i=0; i<index; i++)
{
ret += frames[i].score;
}
return ret;
}
}
As a game goes, we keep adding new frames. As we add new frames, we need to figure out the scores of previous 1 or 2 frames, depend on the bonus status, strike/spare/open. So at the end of the game, scores in each frame should be calculated correctly (This is also helpful for debugging).
The testcase is like this:
import junit.framework.TestCase;
public class BowlingScoreBoardTest extends TestCase
{
private static final BowlingFrame EMPTY_FRAME = new BowlingFrame(0);
public void testStrike()
{
BowlingScoreBoard bsb = new BowlingScoreBoard();
bsb.addFrame(new BowlingFrame(10)); // strike
bsb.addFrame(new BowlingFrame(3, 6)); // open
System.out.println(bsb.totalScore());
assertTrue(bsb.totalScore() == 28); // 1st frame: 10 + (3 + 6), 2nd frame: 3 + 6
}
public void testDouble() // two strikes in a row
{
BowlingScoreBoard bsb = new BowlingScoreBoard();
bsb.addFrame(new BowlingFrame(10)); // strike
bsb.addFrame(new BowlingFrame(10)); // strike
bsb.addFrame(new BowlingFrame(3, 6)); // open
System.out.println(bsb.totalScore());
assertTrue(bsb.totalScore() == 51);
// 1st: 10 + 10 + 3; 2nd: 10 + 3 + 6; 3rd: 3 + 6.
}
public void testTurkey() // 3 consecutive strikes
{
BowlingScoreBoard bsb = new BowlingScoreBoard();
bsb.addFrame(new BowlingFrame(10)); // strike
bsb.addFrame(new BowlingFrame(10)); // strike
bsb.addFrame(new BowlingFrame(10)); // strike
System.out.println(bsb.totalScore());
// first frame should have score 30 = 10 + (2nd frame) 10 + (3rd frame) 10
// second frame bonus is not set yet since 3rd frame is a strike and thus
// it needs the forth frame, similar to the 3rd frame, just 10.
assertTrue(bsb.totalScore() == 50);
}
public void testTailTurkey()
{
BowlingScoreBoard bsb = new BowlingScoreBoard();
bsb.addFrame(EMPTY_FRAME); // we dont care the first few frames, so just empty
bsb.addFrame(EMPTY_FRAME);
bsb.addFrame(EMPTY_FRAME);
bsb.addFrame(EMPTY_FRAME);
bsb.addFrame(EMPTY_FRAME);
bsb.addFrame(EMPTY_FRAME);
bsb.addFrame(EMPTY_FRAME);
bsb.addFrame(new BowlingFrame(10));
bsb.addFrame(new BowlingFrame(10));
bsb.addFrame(new BowlingFrame(10, 10, 10));
System.out.println(bsb.totalScore());
assertTrue(bsb.totalScore() == 90); // 30 for each in the last 3 frames.
}
public void testSpare()
{
BowlingScoreBoard bsb = new BowlingScoreBoard();
bsb.addFrame(new BowlingFrame(4, 6));
bsb.addFrame(new BowlingFrame(3, 7));
System.out.println(bsb.totalScore());
assertTrue(bsb.totalScore() == 23);
// 1st: 4+6 + 3(bonus from 2nd frame); 2nd: 3 + 7 (it's also a spare, but no 3rd frame yet).
}
public void testPerfectScore()
{
BowlingScoreBoard bsb = new BowlingScoreBoard();
for (int i=0; i<9; i++)
bsb.addFrame(new BowlingFrame(10));
bsb.addFrame(new BowlingFrame(10, 10, 10));
System.out.println(bsb.totalScore());
assertTrue(bsb.totalScore() == 300); // 30 for each frame.
}
}
These cases should cover most of the code.
Several notes:
1. The frame class just maintains the current states. The bonus logic should be somewhere else, in the score board class, where we handle the logic between frames.
2. The requirement is to design a score calculator, so we shouldn't get the game playing logic here because it's a separate concern.
3. I played a lot bowling so I know fairly well about the game. If you don't, you may start coding the logic is one big static method and then refactor out the frame portion. The logic is explained well in the wiki page: http://en.wikipedia.org/wiki/Ten-pin_bowling.
- 大小: 97.4 KB
分享到:
相关推荐
北大POJ3176-Cow Bowling
北京大学的在线判题系统POJ(Problem Online Judge)中有一道颇受欢迎的题目——"Cow Bowling",编号为3176。这是一道涉及动态规划和概率计算的编程题目,旨在考察参赛者的算法设计和实现能力。 题目描述: 在本题...
Haghshenas-Jaryani 和 Bowling - 2013 - A new switching strategy for addressing Euler para.pdf.zipHaghshenas-Jaryani 和 Bowling - 2013 - A new switching strategy for addressing Euler para.pdf....
《基于OGRE实现的小游戏Wii_Bowling(保龄球)》 在这个项目中,我们探讨了如何利用OGRE(Object-Oriented Graphics Rendering Engine)游戏引擎来开发一款类似于Wii上的保龄球小游戏。OGRE是一款强大的、开源的3D...
Opengl 制作的保龄球Demo 带碰撞处理
在我们面前的是一个名为"bowling.rar"的压缩包,里面包含了一个由用户制作的简单保龄球游戏。这个项目不仅展示了作者的编程技能,还揭示了图形学在游戏开发中的应用。通过分析这个游戏,我们可以学习到多个关键的IT...
bowling_outline
Bowling Run 3D 保龄球冲刺3D Unity休闲体育游戏项目源码C# 支持Unity版本2021.3.16f1及以上 打一场精彩的保龄球! 您操控保龄球瓶并引导它们到达球门! 这不是普通的保龄球游戏! 你必须一边走一边毁掉随处可见的...
精品运动PPT模板bowling_outline011
【标题】"baolingqiu.rar_baolingqiu_bowling_保龄球" 提供的是一个关于保龄球游戏的源代码项目。保龄球游戏是一种模拟真实保龄球运动的电子游戏,通常包括投球、追踪球路、计算得分等核心功能。 【描述】"保龄球源...
保龄球记分程序_bowling-score
保龄球计分程序_bowling_score
一个保龄球计分程序_Bowling
保龄球计分,C语言实现1、bai 全中:当每一个格的第一次投球击倒全du部竖立的十个瓶zhi子时,称为全中。用(X)符号记录在记分表上dao该格上方右边的小方格中。全中的记分是10分加该运动员下两次投球击倒的瓶数。...
保龄球的计分规则_bowling_game
我重构了 XP Bowling 一集中 Bob 大叔的代码。 我在 Unlce Bob 的代码中看到的一个问题是,一个对象既要聚合帧分数,又要对每一帧进行评分。 我尝试了很多设计,但我发现使用状态模式的设计是唯一令人满意的设计。...
保龄球活动(react版本)_bowling-active
营销策划 -D-BOWLING潮流运动服饰品牌手册.pdf
本篇文章将深入探讨一个基于Unity引擎开发的3D保龄球游戏,即"(5-2019)3d保龄球游戏(单人多人)3D-bowling-game.rar",通过分析其项目结构和关键技术,来揭示3D游戏开发中的核心知识点。 一、Unity引擎基础 ...
Real Bowling Experience 真正的保龄球体验 – 高级源代码 描述 真正的保龄球体验 – 优质源代码 – 广告集成 这是Android手机上最好、最真实的3D保龄球游戏。这是唯一完全拥抱的保龄球游戏。 保龄球世界俱乐部的...