/test/pending/shootout/meteor.scala-4.scala

https://github.com/gkossakowski/scala-dev · Scala · 587 lines · 410 code · 118 blank · 59 comment · 84 complexity · bc171aeabef21916ca0d1a6354993ac4 MD5 · raw file

  1. /* The Computer Language Shootout
  2. http://shootout.alioth.debian.org/
  3. contributed by Isaac Gouy
  4. */
  5. // Most for-comprehension replaced by while loops
  6. // BoardCells occupied by each Piece orientation are cached
  7. // Piece orientations are cached
  8. import scala.collection.mutable._
  9. object meteor {
  10. def main(args: Array[String]) = {
  11. val solver = new Solver( Integer.parseInt(args(0)) )
  12. solver.findSolutions
  13. solver.printSolutions
  14. }
  15. }
  16. // Solver.scala
  17. // import scala.collection.mutable._
  18. final class Solver (n: Int) {
  19. private var countdown = n
  20. private var first: String = _
  21. private var last: String = _
  22. private val board = new Board()
  23. val pieces = Array(
  24. new Piece(0), new Piece(1), new Piece(2), new Piece(3), new Piece(4),
  25. new Piece(5), new Piece(6), new Piece(7), new Piece(8), new Piece(9) )
  26. val unplaced = new BitSet(pieces.length)
  27. { unplaced ++= (0 until pieces.length) }
  28. def findSolutions(): Unit = {
  29. if (countdown == 0) return
  30. if (unplaced.size > 0){
  31. val emptyCellIndex = board.firstEmptyCellIndex
  32. var k = 0
  33. while (k < pieces.length){
  34. if (unplaced.contains(k)){
  35. unplaced -= k
  36. var i = 0
  37. while (i < Piece.orientations){
  38. val piece = pieces(k).nextOrientation
  39. var j = 0
  40. while (j < Piece.size){
  41. if (board.add(j,emptyCellIndex,piece)) {
  42. if (!shouldPrune) findSolutions
  43. board.remove(piece)
  44. }
  45. j = j + 1
  46. }
  47. i = i + 1
  48. }
  49. unplaced += k
  50. }
  51. k = k + 1
  52. }
  53. }
  54. else {
  55. puzzleSolved
  56. }
  57. }
  58. private def puzzleSolved() = {
  59. val b = board.asString
  60. if (first == null){
  61. first = b; last = b
  62. } else {
  63. if (b < first){ first = b } else { if (b > last){ last = b } }
  64. }
  65. countdown = countdown - 1
  66. }
  67. private def shouldPrune(): Boolean = {
  68. board.unmark
  69. var i = 0
  70. while (i < board.cells.length){
  71. if (board.cells(i).contiguousEmptyCells % Piece.size != 0) return true
  72. i = i + 1
  73. }
  74. false
  75. }
  76. def printSolutions() = {
  77. def printBoard(s: String) = {
  78. var indent = false
  79. var i = 0
  80. while (i < s.length){
  81. if (indent) Console.print(' ')
  82. var j = 0
  83. while (j < Board.cols){
  84. Console.print(s.charAt(i)); Console.print(' ')
  85. j = j + 1
  86. i = i + 1
  87. }
  88. Console.print('\n')
  89. indent = !indent
  90. }
  91. Console.print('\n')
  92. }
  93. Console.print(n + " solutions found\n\n")
  94. printBoard(first)
  95. printBoard(last)
  96. }
  97. /*
  98. def printPieces() =
  99. for (i <- Iterator.range(0,Board.pieces)) pieces(i).print
  100. */
  101. }
  102. // Board.scala
  103. // import scala.collection.mutable._
  104. object Board {
  105. val cols = 5
  106. val rows = 10
  107. val size = rows * cols
  108. val pieces = 10
  109. val noFit = new Array[BoardCell](0)
  110. }
  111. final class Board {
  112. val cells = boardCells()
  113. val cellsPieceWillFill = new Array[BoardCell](Piece.size)
  114. var cellCount = 0
  115. def unmark() = {
  116. var i = 0
  117. while (i < cells.length){
  118. cells(i).unmark
  119. i = i + 1
  120. }
  121. }
  122. def asString() =
  123. new String( cells map(
  124. c => if (c.piece == null) '-'.toByte
  125. else (c.piece.number + 48).toByte ))
  126. def firstEmptyCellIndex() = cells.findIndexOf(c => c.isEmpty)
  127. private val cache: Array[Array[Array[Array[ Array[BoardCell] ]]]] =
  128. for (i <- Array.range(0,Board.pieces))
  129. yield
  130. for (j <- Array.range(0,Piece.orientations))
  131. yield
  132. for (k <- Array.range(0,Piece.size)) // piece cell index
  133. yield
  134. for (m <- Array.range(0,Board.size)) // board cell index
  135. yield (null: BoardCell)
  136. def add(pieceIndex: Int, boardIndex: Int, p: Piece): Boolean = {
  137. var a = cache(p.number)(p.orientation)(pieceIndex)(boardIndex)
  138. cellCount = 0
  139. p.unmark
  140. if (a == null){
  141. find(p.cells(pieceIndex), cells(boardIndex))
  142. if (cellCount != Piece.size){
  143. cache(p.number)(p.orientation)(pieceIndex)(boardIndex) = Board.noFit
  144. return false
  145. }
  146. a = cellsPieceWillFill .filter(c => true)
  147. cache(p.number)(p.orientation)(pieceIndex)(boardIndex) = a
  148. }
  149. else {
  150. if (a == Board.noFit) return false
  151. }
  152. var i = 0
  153. while (i < a.length){
  154. if (!a(i).isEmpty) return false
  155. i = i + 1
  156. }
  157. i = 0
  158. while (i < a.length){
  159. a(i).piece = p
  160. i = i + 1
  161. }
  162. true
  163. }
  164. def remove(piece: Piece) = {
  165. var i = 0
  166. while (i < cells.length){
  167. if (cells(i).piece == piece) cells(i).empty
  168. i = i + 1
  169. }
  170. }
  171. private def find(p: PieceCell, b: BoardCell): Unit = {
  172. if (p != null && !p.marked && b != null){
  173. cellsPieceWillFill(cellCount) = b
  174. cellCount = cellCount + 1
  175. p.mark
  176. var i = 0
  177. while (i < Cell.sides){
  178. find(p.next(i), b.next(i))
  179. i = i + 1
  180. }
  181. }
  182. }
  183. private def boardCells() = {
  184. val a = for (i <- Array.range(0,Board.size)) yield new BoardCell(i)
  185. val m = (Board.size / Board.cols) - 1
  186. for (i <- Iterator.range(0,a.length)){
  187. val row = i / Board.cols
  188. val isFirst = i % Board.cols == 0
  189. val isLast = (i+1) % Board.cols == 0
  190. val c = a(i)
  191. if (row % 2 == 1) {
  192. if (!isLast) c.next(Cell.NE) = a(i-(Board.cols-1))
  193. c.next(Cell.NW) = a(i-Board.cols)
  194. if (row != m) {
  195. if (!isLast) c.next(Cell.SE) = a(i+(Board.cols+1))
  196. c.next(Cell.SW) = a(i+Board.cols)
  197. }
  198. } else {
  199. if (row != 0) {
  200. if (!isFirst) c.next(Cell.NW) = a(i-(Board.cols+1))
  201. c.next(Cell.NE) = a(i-Board.cols)
  202. }
  203. if (row != m) {
  204. if (!isFirst) c.next(Cell.SW) = a(i+(Board.cols-1))
  205. c.next(Cell.SE) = a(i+Board.cols)
  206. }
  207. }
  208. if (!isFirst) c.next(Cell.W) = a(i-1)
  209. if (!isLast) c.next(Cell.E) = a(i+1)
  210. }
  211. a
  212. }
  213. /*
  214. // Printing all the board cells and their neighbours
  215. // helps check that they are connected properly
  216. def printBoardCellsAndNeighbours() = {
  217. Console.println("cell\tNW NE W E SW SE")
  218. for (i <- Iterator.range(0,Board.size)){
  219. Console.print(i + "\t")
  220. for (j <- Iterator.range(0,Cell.sides)){
  221. val c = cells(i).next(j)
  222. if (c == null)
  223. Console.print("-- ")
  224. else
  225. Console.printf("{0,number,00} ")(c.number)
  226. }
  227. Console.println("")
  228. }
  229. Console.println("")
  230. }
  231. */
  232. }
  233. // Piece.scala
  234. object Piece {
  235. val size = 5
  236. val rotations = Cell.sides
  237. val flips = 2
  238. val orientations = rotations * flips
  239. }
  240. final class Piece(_number: Int) {
  241. val number = _number
  242. def unmark() = {
  243. val c = cache(orientation)
  244. var i = 0
  245. while (i < c.length){
  246. c(i).unmark
  247. i = i + 1
  248. }
  249. }
  250. def cells = cache(orientation)
  251. private val cache =
  252. for (i <- Array.range(0,Piece.orientations))
  253. yield pieceOrientation(i)
  254. var orientation = 0
  255. def nextOrientation() = {
  256. orientation = (orientation + 1) % Piece.orientations
  257. this
  258. }
  259. private def pieceOrientation(k: Int) = {
  260. val cells = for (i <- Array.range(0,Piece.size)) yield new PieceCell()
  261. makePiece(number,cells)
  262. var i = 0
  263. while (i < k){
  264. if (i % Piece.rotations == 0)
  265. for (c <- cells) c.flip
  266. else
  267. for (c <- cells) c.rotate
  268. i = i + 1
  269. }
  270. cells
  271. }
  272. private def makePiece(number: Int, cells: Array[PieceCell]) = {
  273. number match {
  274. case 0 => make0(cells)
  275. case 1 => make1(cells)
  276. case 2 => make2(cells)
  277. case 3 => make3(cells)
  278. case 4 => make4(cells)
  279. case 5 => make5(cells)
  280. case 6 => make6(cells)
  281. case 7 => make7(cells)
  282. case 8 => make8(cells)
  283. case 9 => make9(cells)
  284. }
  285. }
  286. private def make0(a: Array[PieceCell]) = {
  287. a(0).next(Cell.E) = a(1)
  288. a(1).next(Cell.W) = a(0)
  289. a(1).next(Cell.E) = a(2)
  290. a(2).next(Cell.W) = a(1)
  291. a(2).next(Cell.E) = a(3)
  292. a(3).next(Cell.W) = a(2)
  293. a(3).next(Cell.SE) = a(4)
  294. a(4).next(Cell.NW) = a(3)
  295. }
  296. private def make1(a: Array[PieceCell]) = {
  297. a(0).next(Cell.SE) = a(1)
  298. a(1).next(Cell.NW) = a(0)
  299. a(1).next(Cell.SW) = a(2)
  300. a(2).next(Cell.NE) = a(1)
  301. a(2).next(Cell.W) = a(3)
  302. a(3).next(Cell.E) = a(2)
  303. a(3).next(Cell.SW) = a(4)
  304. a(4).next(Cell.NE) = a(3)
  305. }
  306. private def make2(a: Array[PieceCell]) = {
  307. a(0).next(Cell.W) = a(1)
  308. a(1).next(Cell.E) = a(0)
  309. a(1).next(Cell.SW) = a(2)
  310. a(2).next(Cell.NE) = a(1)
  311. a(2).next(Cell.SE) = a(3)
  312. a(3).next(Cell.NW) = a(2)
  313. a(3).next(Cell.SE) = a(4)
  314. a(4).next(Cell.NW) = a(3)
  315. }
  316. private def make3(a: Array[PieceCell]) = {
  317. a(0).next(Cell.SW) = a(1)
  318. a(1).next(Cell.NE) = a(0)
  319. a(1).next(Cell.W) = a(2)
  320. a(2).next(Cell.E) = a(1)
  321. a(1).next(Cell.SW) = a(3)
  322. a(3).next(Cell.NE) = a(1)
  323. a(2).next(Cell.SE) = a(3)
  324. a(3).next(Cell.NW) = a(2)
  325. a(3).next(Cell.SE) = a(4)
  326. a(4).next(Cell.NW) = a(3)
  327. }
  328. private def make4(a: Array[PieceCell]) = {
  329. a(0).next(Cell.SE) = a(1)
  330. a(1).next(Cell.NW) = a(0)
  331. a(1).next(Cell.SW) = a(2)
  332. a(2).next(Cell.NE) = a(1)
  333. a(1).next(Cell.E) = a(3)
  334. a(3).next(Cell.W) = a(1)
  335. a(3).next(Cell.SE) = a(4)
  336. a(4).next(Cell.NW) = a(3)
  337. }
  338. private def make5(a: Array[PieceCell]) = {
  339. a(0).next(Cell.SW) = a(1)
  340. a(1).next(Cell.NE) = a(0)
  341. a(0).next(Cell.SE) = a(2)
  342. a(2).next(Cell.NW) = a(0)
  343. a(1).next(Cell.SE) = a(3)
  344. a(3).next(Cell.NW) = a(1)
  345. a(2).next(Cell.SW) = a(3)
  346. a(3).next(Cell.NE) = a(2)
  347. a(3).next(Cell.SW) = a(4)
  348. a(4).next(Cell.NE) = a(3)
  349. }
  350. private def make6(a: Array[PieceCell]) = {
  351. a(0).next(Cell.SW) = a(1)
  352. a(1).next(Cell.NE) = a(0)
  353. a(2).next(Cell.SE) = a(1)
  354. a(1).next(Cell.NW) = a(2)
  355. a(1).next(Cell.SE) = a(3)
  356. a(3).next(Cell.NW) = a(1)
  357. a(3).next(Cell.SW) = a(4)
  358. a(4).next(Cell.NE) = a(3)
  359. }
  360. private def make7(a: Array[PieceCell]) = {
  361. a(0).next(Cell.SE) = a(1)
  362. a(1).next(Cell.NW) = a(0)
  363. a(0).next(Cell.SW) = a(2)
  364. a(2).next(Cell.NE) = a(0)
  365. a(2).next(Cell.SW) = a(3)
  366. a(3).next(Cell.NE) = a(2)
  367. a(3).next(Cell.SE) = a(4)
  368. a(4).next(Cell.NW) = a(3)
  369. }
  370. private def make8(a: Array[PieceCell]) = {
  371. a(0).next(Cell.E) = a(1)
  372. a(1).next(Cell.W) = a(0)
  373. a(1).next(Cell.E) = a(2)
  374. a(2).next(Cell.W) = a(1)
  375. a(2).next(Cell.NE) = a(3)
  376. a(3).next(Cell.SW) = a(2)
  377. a(3).next(Cell.E) = a(4)
  378. a(4).next(Cell.W) = a(3)
  379. }
  380. private def make9(a: Array[PieceCell]) = {
  381. a(0).next(Cell.E) = a(1)
  382. a(1).next(Cell.W) = a(0)
  383. a(1).next(Cell.E) = a(2)
  384. a(2).next(Cell.W) = a(1)
  385. a(2).next(Cell.NE) = a(3)
  386. a(3).next(Cell.SW) = a(2)
  387. a(2).next(Cell.E) = a(4)
  388. a(4).next(Cell.W) = a(2)
  389. a(4).next(Cell.NW) = a(3)
  390. a(3).next(Cell.SE) = a(4)
  391. }
  392. /*
  393. def print() = {
  394. Console.println("Piece # " + number)
  395. Console.println("cell\tNW NE W E SW SE")
  396. for (i <- Iterator.range(0,Piece.size)){
  397. Console.print(i + "\t")
  398. for (j <- Iterator.range(0,Cell.sides)){
  399. val c = cells(i).next(j)
  400. if (c == null)
  401. Console.print("-- ")
  402. else
  403. for (k <- Iterator.range(0,Piece.size)){
  404. if (cells(k) == c) Console.printf(" {0,number,0} ")(k)
  405. }
  406. }
  407. Console.println("")
  408. }
  409. Console.println("")
  410. }
  411. */
  412. }
  413. // Cell.scala
  414. object Cell {
  415. val NW = 0; val NE = 1
  416. val W = 2; val E = 3
  417. val SW = 4; val SE = 5
  418. val sides = 6
  419. }
  420. abstract class Cell {
  421. var marked = false
  422. def mark() = marked = true
  423. def unmark() = marked = false
  424. }
  425. // BoardCell.scala
  426. final class BoardCell(_number: Int) extends Cell {
  427. val next = new Array[BoardCell](Cell.sides)
  428. val number = _number
  429. var piece: Piece = _
  430. def isEmpty() = piece == null
  431. def empty() = piece = null
  432. def contiguousEmptyCells(): Int = {
  433. if (!marked && isEmpty){
  434. mark
  435. var count = 1
  436. var i = 0
  437. while (i < next.length){
  438. if (next(i) != null && next(i).isEmpty)
  439. count = count + next(i).contiguousEmptyCells
  440. i = i + 1
  441. }
  442. count } else { 0 }
  443. }
  444. }
  445. // PieceCell.scala
  446. final class PieceCell extends Cell {
  447. val next = new Array[PieceCell](Cell.sides)
  448. def flip = {
  449. var swap = next(Cell.NE)
  450. next(Cell.NE) = next(Cell.NW)
  451. next(Cell.NW) = swap
  452. swap = next(Cell.E)
  453. next(Cell.E) = next(Cell.W)
  454. next(Cell.W) = swap
  455. swap = next(Cell.SE)
  456. next(Cell.SE) = next(Cell.SW)
  457. next(Cell.SW) = swap
  458. }
  459. def rotate = {
  460. var swap = next(Cell.E)
  461. next(Cell.E) = next(Cell.NE)
  462. next(Cell.NE) = next(Cell.NW)
  463. next(Cell.NW) = next(Cell.W)
  464. next(Cell.W) = next(Cell.SW)
  465. next(Cell.SW) = next(Cell.SE)
  466. next(Cell.SE) = swap
  467. }
  468. }