- 浏览: 80116 次
文章分类
最新评论
-
wodentt:
....为什么楼主都英文的博客
用java解决百度之星移动火柴的问题 part 1 -
wensonzhou86:
思路明确,代码清晰,通俗易懂
visit 淘宝面试题:如何充分利用多核CPU,计算很大的List中所有整数的和 -
carydeepbreathing:
代码比较干净
visit 淘宝面试题:如何充分利用多核CPU,计算很大的List中所有整数的和 -
meiowei:
yangguo 写道i don't think it is a ...
用java解决百度之星移动火柴的问题 part 2 -
yangguo:
i don't think it is a good way ...
用java解决百度之星移动火柴的问题 part 2
Recently, I saw a post:
http://www.iteye.com/topic/399628
Though I am too busy at work, can't help to spare some time on this subject because
- It is a small enough topic to talk about how to design a better component give a (business) requirement, and it is complicated enough to talk about what I want to say(Sometimes, trivial examples just don't help much).
- Most of the readers can understand the domain problem easily so there is no communication problem
- to share a view on domain driven design since I am not satisfied with the code presented in that post. No offending, but I would say it is really a spaghetti code because it has so many embeded if-else and for loops. I have no intention to blame the writer, but to solve the problem I see in an effort.
Now let us look at the problem itself, we are given an expression consisting of numbers, operators and =. We can change the numbers somehow, i.e., by moving the matches only once. After the moving, the equality should hold.
The solution is just a brutal force search, move all matches to all possible places to check the equality. So the domain driven logic should be something like this
for all digits for all matches take this match and move it to somewhere so that we have two new valid numbers check whether the equality holds if it holds, send out results.
Since there are "transformations" on the numbers, it would be better if we model the numbers first. A simple way is to code the digit like this:
TOP - UPPERLEFT | | UPPERRIGHT MIDDLE - LOWERLEFT | | LOWERRIGHT BOTTOM -
So clearly we need an enum to represent these positions:
public enum MatchPosition { TOP, UPPERLEFT, UPPERRIGHT, MIDDLE, LOWERLEFT, LOWERRIGHT, BOTTOM; }
Since at each match position, there either has a match or not, so we could encode the presence of a match in a binary format, 0 for no match, 1 for match. So the data representation of the digits are:
int[] digitEncodings = { Integer.valueOf("1110111", 2), //119 Integer.valueOf("0010010", 2), //18 Integer.valueOf("1011101", 2), //93 Integer.valueOf("1011011", 2), //91 Integer.valueOf("0111010", 2), //58 Integer.valueOf("1101011", 2), //107 Integer.valueOf("1101111", 2), //111 Integer.valueOf("1010010", 2), //82 Integer.valueOf("1111111", 2), //127 Integer.valueOf("1111011", 2), //123 };
Here the string binary sequence follows the order in the enum class MatchPosition. For example, 0 is represented as:
-
| |
| |
-
only the middle match is not there, so the string 1110111 has 0 in the middle. The number 8 has all matches, so the string is all 1's.
In order to save space, we convert the string representation to integers.
Now let's turns to the behaviors of the digits. From the pseudo code, we need several methods from the digits:
- get all matches from a digit to loop through
- take a match from a digit to form a new digit
- set a match to a particular position to form a new digit
The final implementation is as follows. There are a few decisions on the implementation, but they don't affect the overall interface design, such as:
- when taking a match off a digit, we may not have a valid digit anymore, e.g., take a match off the number one, we end up something not a number. In this case, we return a null object. Then later on the caller side we check whether it is null in order to know whether we can take a match out.
- Internally, we maintain a hashmap to map number values to the digit, this hashmap is used in several places.
- For convenience, we add a method hasMatch(MatchPosition p) to check whether there is a match at a particular position for this digit.
The full class is here:
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A match digit is like this: * _ * |_| * |_| * * we are going to use a binary bit array to represent this. */ public class MatchDigit { private static final int[] digitEncodings = { Integer.valueOf("1110111", 2), //119 Integer.valueOf("0010010", 2), //18 Integer.valueOf("1011101", 2), //93 Integer.valueOf("1011011", 2), //91 Integer.valueOf("0111010", 2), //58 Integer.valueOf("1101011", 2), //107 Integer.valueOf("1101111", 2), //111 Integer.valueOf("1010010", 2), //82 Integer.valueOf("1111111", 2), //127 Integer.valueOf("1111011", 2), //123 }; public static final MatchDigit ZERO = new MatchDigit(0); public static final MatchDigit ONE = new MatchDigit(1); public static final MatchDigit TWO = new MatchDigit(2); public static final MatchDigit THREE = new MatchDigit(3); public static final MatchDigit FOUR = new MatchDigit(4); public static final MatchDigit FIVE = new MatchDigit(5); public static final MatchDigit SIX = new MatchDigit(6); public static final MatchDigit SEVEN = new MatchDigit(7); public static final MatchDigit EIGHT = new MatchDigit(8); public static final MatchDigit NINE = new MatchDigit(9); private static Map<Integer, MatchDigit> digits = new HashMap<Integer, MatchDigit>(); static { digits.put(digitEncodings[0], ZERO); digits.put(digitEncodings[1], ONE); digits.put(digitEncodings[2], TWO); digits.put(digitEncodings[3], THREE); digits.put(digitEncodings[4], FOUR); digits.put(digitEncodings[5], FIVE); digits.put(digitEncodings[6], SIX); digits.put(digitEncodings[7], SEVEN); digits.put(digitEncodings[8], EIGHT); digits.put(digitEncodings[9], NINE); } private int encodedDigit; public MatchDigit(int digit) { encodedDigit = digitEncodings[digit]; } public MatchDigit setMatch(MatchPosition position) { // if there is already a match at this position, return null if (hasMatch(position)) return null; int x = (int)Math.pow(2.0, 6 - position.ordinal()); int value = encodedDigit + x; return digits.get(value); } public MatchDigit takeMatch(MatchPosition position) { // if there is no match at this position, return null if (!hasMatch(position)) return null; int x = (int)Math.pow(2.0, 6 - position.ordinal()); int value = encodedDigit - x; return digits.get(value); } public boolean hasMatch(MatchPosition position) { return ((encodedDigit >> (6 - position.ordinal())) & 1)== 1; } public MatchPosition[] getAllMatches() { List<MatchPosition> ret = new ArrayList<MatchPosition>(); for (MatchPosition position : MatchPosition.values()) { if (hasMatch(position)) ret.add(position); } return ret.toArray(new MatchPosition[0]); } public int value() { for (int i=0; i<digitEncodings.length; i++) { if (encodedDigit == digitEncodings[i]) return i; } throw new RuntimeException("can't find the value for encoded digit: " + encodedDigit); } public String toString() { String s = Integer.toBinaryString(encodedDigit); String zeros = "0000000"; s = zeros.substring(0, 7 - s.length()) + s; String ret = " " + rep(s.charAt(0), "-") + "\n"; ret += rep(s.charAt(1), "|") + " " + rep(s.charAt(2), "|") + "\n"; ret += " " + rep(s.charAt(3), "-") + "\n"; ret += rep(s.charAt(4), "|") + " " + rep(s.charAt(5), "|") + "\n"; ret += " " + rep(s.charAt(6), "-") + "\n"; return ret; } private String rep(char c, String d) { if (c == '1') return d; else return " "; } }
The toString() method is just to print out the digit.
A simple testcase is as follows:
import junit.framework.TestCase; public class MatchDigitTest extends TestCase { public void testToString() { for (int i=0; i<=9; i++) { MatchDigit md = new MatchDigit(i); System.out.println(md.toString()); System.out.println("value=" + md.value()); assertTrue(md.value() == i); } } public void testHasMatch() { MatchDigit md = new MatchDigit(9); for (MatchPosition p : MatchPosition.values()) { System.out.println(md.hasMatch(p)); if (p == MatchPosition.LOWERLEFT) assertTrue(!md.hasMatch(p)); else assertTrue(md.hasMatch(p)); } System.out.println("-----------------------------------------"); md = new MatchDigit(8); for (MatchPosition p : MatchPosition.values()) { System.out.println(md.hasMatch(p)); assertTrue(md.hasMatch(p)); } System.out.println("-----------------------------------------"); md = new MatchDigit(7); for (MatchPosition p : MatchPosition.values()) { System.out.println(md.hasMatch(p)); if (p == MatchPosition.TOP || p == MatchPosition.UPPERRIGHT || p == MatchPosition.LOWERRIGHT) assertTrue(md.hasMatch(p)); else assertTrue(!md.hasMatch(p)); } System.out.println("-----------------------------------------"); md = new MatchDigit(6); for (MatchPosition p : MatchPosition.values()) { System.out.println(md.hasMatch(p)); if (p == MatchPosition.UPPERRIGHT) assertTrue(!md.hasMatch(p)); else assertTrue(md.hasMatch(p)); } System.out.println("-----------------------------------------"); md = new MatchDigit(5); for (MatchPosition p : MatchPosition.values()) { System.out.println(md.hasMatch(p)); if (p == MatchPosition.UPPERRIGHT || p == MatchPosition.LOWERLEFT) assertTrue(!md.hasMatch(p)); else assertTrue(md.hasMatch(p)); } System.out.println("-----------------------------------------"); md = new MatchDigit(4); for (MatchPosition p : MatchPosition.values()) { System.out.println(md.hasMatch(p)); if (p == MatchPosition.TOP || p == MatchPosition.LOWERLEFT || p == MatchPosition.BOTTOM) assertTrue(!md.hasMatch(p)); else assertTrue(md.hasMatch(p)); } System.out.println("-----------------------------------------"); md = new MatchDigit(3); for (MatchPosition p : MatchPosition.values()) { System.out.println(md.hasMatch(p)); if (p == MatchPosition.UPPERLEFT || p == MatchPosition.LOWERLEFT) assertTrue(!md.hasMatch(p)); else assertTrue(md.hasMatch(p)); } System.out.println("-----------------------------------------"); md = new MatchDigit(2); for (MatchPosition p : MatchPosition.values()) { System.out.println(md.hasMatch(p)); if (p == MatchPosition.UPPERLEFT || p == MatchPosition.LOWERRIGHT) assertTrue(!md.hasMatch(p)); else assertTrue(md.hasMatch(p)); } System.out.println("-----------------------------------------"); md = new MatchDigit(1); for (MatchPosition p : MatchPosition.values()) { System.out.println(md.hasMatch(p)); if (p == MatchPosition.UPPERRIGHT || p == MatchPosition.LOWERRIGHT) assertTrue(md.hasMatch(p)); else assertTrue(!md.hasMatch(p)); } System.out.println("-----------------------------------------"); md = new MatchDigit(0); for (MatchPosition p : MatchPosition.values()) { System.out.println(md.hasMatch(p)); if (p == MatchPosition.MIDDLE) assertTrue(!md.hasMatch(p)); else assertTrue(md.hasMatch(p)); } } public void testSetMatch() { MatchDigit md = new MatchDigit(5); md = md.setMatch(MatchPosition.LOWERLEFT); System.out.println(md); } public void testTakeMatch() { MatchDigit md = new MatchDigit(9); md = md.takeMatch(MatchPosition.UPPERLEFT); System.out.println(md); } }
As they shows, these classes are no more than 200 lines. An average developer can digest them without much headache.
评论
发表评论
-
Spreadsheet Dependency graph
2010-11-19 03:00 2186In spreadsheets, such as Excel, ... -
Composition
2010-07-03 03:56 0I saw a post in the forum some ... -
Revisit again: 一道应聘智力题的编程求解, Einstein puzzle
2010-06-30 04:30 1661Continue on: http://jellyfish.i ... -
Domain Driven Design
2010-01-16 02:42 1259Having read a lot of discussion ... -
用java解决百度之星移动火柴的问题 part 2
2009-06-09 02:07 1650The next task is to evaluate a ... -
CEP
2007-07-11 02:54 1315http://www.eventstreamprocessin ...
相关推荐
Java 拿火柴游戏实验报告 一、 程序功能介绍 拿火柴游戏是一种与计算机相互对拿火柴的游戏程序,旨在训练人脑的逻辑思维能力。游戏的玩法是用系统产生的随机函数产生火柴数量(大约在 20—50 之间),每次每一方...
通过以上步骤,我们可以成功地用Java实现一个火柴游戏。这个过程不仅可以提升编程技能,也能锻炼逻辑思维和问题解决能力。无论你是初学者还是有一定经验的开发者,这样的课程设计都能提供宝贵的实践机会。
首先,游戏的核心是使用Java的`Math.random()`函数来生成随机的火柴数量。`Math.random()`函数返回一个0.0到1.0之间的随机浮点数,通过乘以(50-20)并加上20,可以得到20到50之间的随机整数,代表火柴堆的初始数量。...
Java课程设计是一个重要的实践环节,旨在让学生通过实际编程项目来巩固和深化理论知识。在这个“拿火柴游戏”项目中,我们将深入...通过这个项目,学生不仅可以加深对Java语言的理解,还能提高实际编程和问题解决能力。
在这款基于C++Builder开发的小游戏中,玩家需要通过移动火柴棍来解决一系列的谜题,目标是达到预设的目标形状或数字组合。游戏的核心在于观察、分析和创新,激发玩家的空间想象能力和逻辑推理能力。 C++Builder是一...
JAVA拿火柴的小游戏,使用JDK编写,JAVA初学者的范例程序,有出错循环,
这种类型的问题不仅考验逻辑思维能力,还能培养解决问题的能力。 ### 实现思路 该程序的主要实现思路可以概括为以下几点: 1. **定义数字变化规则**:首先定义了每个数字在添加、移动或减少一根火柴棍后可能变成的...
次程序是用JAVA编写的火柴游戏。电脑有一定的智能。
例如,在第一个问题中,要求用12根火柴棒组成4个正方形,通过移动3根火柴棒变成3个正方形。这是一个典型的图形变换问题,需要孩子们观察并思考如何通过移动火柴棒来减少正方形的数量。 第二个问题涉及等式的平衡,...
### 移动一根火柴令等式成立(递归)详解 #### 一、问题背景与目标 在解决“移动一根火柴令等式成立”的...这种方法不仅能够处理简单的等式变换,还能够应对更复杂的情况,为解决问题提供了一种灵活而强大的工具。
巧移火柴棒是一种经典的数学智力游戏,适合于低年级学生锻炼思维灵活性和逻辑推理能力。...通过这些题目,孩子们能够更好地理解数字的结构、运算规则以及图形的变化规律,同时培养了解决问题的策略和技巧。
这是一个使用Java Swing框架开发的简单数火柴游戏。游戏的目标是通过移除一定数量的火柴来击败对手。游戏采用图形用户界面(GUI),使得玩家能够直观地看到当前游戏的状态,并进行操作。 ### 二、主要类和组件介绍 #...
人机对拿火柴的游戏程序 游戏过程要显示火柴总数 选择谁先拿
巧移火柴棒是一种锻炼逻辑思维和数学技巧的趣味题型,主要针对低年级学生,旨在提高他们的数学理解和创新思维。...通过解决这类问题,孩子们不仅可以提升数学技能,还能培养解决问题的策略和思维方式。
Java课程设计是大学计算机科学教育中的重要组成部分,它旨在帮助学生深入理解面向对象编程思想,增强实际编程能力和软件...如果你在使用过程中遇到任何问题,记得寻求帮助,共同探讨和解决问题是学习过程中的重要环节。
1. **谜题生成**:程序需要能随机生成或预定义一系列的火柴等式,这些等式需要有至少一种解决方案,即通过移动一根火柴使等式成立。 2. **图形界面**:Unity3D的图形渲染能力可以创建逼真的3D火柴模型,用户可以...
【作品名称】:基于JAVA实现的控制台火柴棍游戏 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】:项目简介 Match-game...
6.思考题:通过移动火柴棒,学生可以学习解决问题的方法和策略。 四、教学目标 * 培养学生动手能力和空间想象能力 * 通过火柴棒摆出数字图形和巧移火柴棒等活动,提高学生的逻辑思维和问题解决能力 * 培养学生的...
本篇文章将详细介绍巧移火柴棒游戏的训练方法,并深入探讨训练题库的运用,旨在帮助玩家在娱乐中提高他们的思维灵活性和解决问题的技巧。 ### 巧移火柴棒游戏的训练方法 #### 第一阶段:入门练习 初学者首先需要...
《基于JaVA实现的控制台火柴棍游戏》...总之,《基于JAVA实现的控制台火柴棍游戏》是一个高质量的学习资源,能够帮助学习者巩固编程基础,提升逻辑思维和问题解决能力。请注意,该项目仅供学习参考,切勿用于商业用途。