मैं एक स्कैला एन 00 बी (लेकिन अन्य भाषाओं के साथ अनुभव कर रहा हूं) और भाषा सीख रहा हूं क्योंकि मुझे समय लगता है - अब तक इसका आनंद ले रहे हैं!क्रिटिक मेरे स्कैला कोड
आमतौर पर जब कोई नई भाषा सीखती है तो पहली बात यह है कि मैं Conway's Game of Life लागू करता हूं, क्योंकि यह भाषा की अच्छी समझ देने के लिए पर्याप्त जटिल है, लेकिन कुछ घंटों में चाबुक करने में सक्षम होने के लिए पर्याप्त छोटा है (जिनमें से अधिकांश वाक्यविन्यास के साथ कुश्ती बिताई जाती है)।
कोई भी, स्कैला I के साथ इस अभ्यास के माध्यम से जाने के बाद, उम्मीद कर रहा था कि स्कैला गुरु वहां मौजूद कोड को देख सकते हैं और उस पर प्रतिक्रिया प्रदान कर सकते हैं। मैं कुछ भी बाद में हूं - एल्गोरिदमिक सुधार (विशेष रूप से समवर्ती समाधान!), स्टाइलिस्टिक सुधार, वैकल्पिक एपीआई या भाषा संरचनाएं, मेरे फ़ंक्शन नामों की लंबाई पर घृणा - जो भी फीडबैक आपको मिला है, मैं इसे सुनना चाहता हूं!
आपको scala GameOfLife.scala
के माध्यम से निम्न स्क्रिप्ट चलाने में सक्षम होना चाहिए - डिफ़ॉल्ट रूप से यह 20x20 बोर्ड को एक ग्लाइडर के साथ चलाएगा - कृपया प्रयोग करने में संकोच न करें।
// CONWAY'S GAME OF LIFE (SCALA)
abstract class GameOfLifeBoard(val aliveCells : Set[Tuple2[Int, Int]])
{
// Executes a "time tick" - returns a new board containing the next generation
def tick : GameOfLifeBoard
// Is the board empty?
def empty : Boolean = aliveCells.size == 0
// Is the given cell alive?
protected def alive(cell : Tuple2[Int, Int]) : Boolean = aliveCells contains cell
// Is the given cell dead?
protected def dead(cell : Tuple2[Int, Int]) : Boolean = !alive(cell)
}
class InfiniteGameOfLifeBoard(aliveCells : Set[Tuple2[Int, Int]])
extends GameOfLifeBoard(aliveCells)
{
// Executes a "time tick" - returns a new board containing the next generation
override def tick : GameOfLifeBoard = new InfiniteGameOfLifeBoard(nextGeneration)
// The next generation of this board
protected def nextGeneration : Set[Tuple2[Int, Int]] = aliveCells flatMap neighbours filter shouldCellLiveInNextGeneration
// Should the given cell should live in the next generation?
protected def shouldCellLiveInNextGeneration(cell : Tuple2[Int, Int]) : Boolean = (alive(cell) && (numberOfAliveNeighbours(cell) == 2 || numberOfAliveNeighbours(cell) == 3)) ||
(dead(cell) && numberOfAliveNeighbours(cell) == 3)
// The number of alive neighbours for the given cell
protected def numberOfAliveNeighbours(cell : Tuple2[Int, Int]) : Int = aliveNeighbours(cell) size
// Returns the alive neighbours for the given cell
protected def aliveNeighbours(cell : Tuple2[Int, Int]) : Set[Tuple2[Int, Int]] = aliveCells intersect neighbours(cell)
// Returns the coordinates of all of the neighbouring cells of the given cell
protected def neighbours(cell : Tuple2[Int, Int]) : Set[Tuple2[Int, Int]] = Set((cell._1-1, cell._2-1), (cell._1, cell._2-1), (cell._1+1, cell._2-1),
(cell._1-1, cell._2), (cell._1+1, cell._2),
(cell._1-1, cell._2+1), (cell._1, cell._2+1), (cell._1+1, cell._2+1))
// Information on where the currently live cells are
protected def xVals = aliveCells map { cell => cell._1 }
protected def xMin = (xVals reduceLeft (_ min _)) - 1
protected def xMax = (xVals reduceLeft (_ max _)) + 1
protected def xRange = xMin until xMax + 1
protected def yVals = aliveCells map { cell => cell._2 }
protected def yMin = (yVals reduceLeft (_ min _)) - 1
protected def yMax = (yVals reduceLeft (_ max _)) + 1
protected def yRange = yMin until yMax + 1
// Returns a simple graphical representation of this board
override def toString : String =
{
var result = ""
for (y <- yRange)
{
for (x <- xRange)
{
if (alive (x,y)) result += "# "
else result += ". "
}
result += "\n"
}
result
}
// Equality stuff
override def equals(other : Any) : Boolean =
{
other match
{
case that : InfiniteGameOfLifeBoard => (that canEqual this) &&
that.aliveCells == this.aliveCells
case _ => false
}
}
def canEqual(other : Any) : Boolean = other.isInstanceOf[InfiniteGameOfLifeBoard]
override def hashCode = aliveCells.hashCode
}
class FiniteGameOfLifeBoard(val boardWidth : Int, val boardHeight : Int, aliveCells : Set[Tuple2[Int, Int]])
extends InfiniteGameOfLifeBoard(aliveCells)
{
override def tick : GameOfLifeBoard = new FiniteGameOfLifeBoard(boardWidth, boardHeight, nextGeneration)
// Returns the coordinates of all of the neighbouring cells of the given cell
override protected def neighbours(cell : Tuple2[Int, Int]) : Set[Tuple2[Int, Int]] = super.neighbours(cell) filter { cell => cell._1 >= 0 && cell._1 < boardWidth &&
cell._2 >= 0 && cell._2 < boardHeight }
// Information on where the currently live cells are
override protected def xRange = 0 until boardWidth
override protected def yRange = 0 until boardHeight
// Equality stuff
override def equals(other : Any) : Boolean =
{
other match
{
case that : FiniteGameOfLifeBoard => (that canEqual this) &&
that.boardWidth == this.boardWidth &&
that.boardHeight == this.boardHeight &&
that.aliveCells == this.aliveCells
case _ => false
}
}
override def canEqual(other : Any) : Boolean = other.isInstanceOf[FiniteGameOfLifeBoard]
override def hashCode : Int =
{
41 * (
41 * (
41 + super.hashCode
) + boardHeight.hashCode
) + boardWidth.hashCode
}
}
class GameOfLife(initialBoard: GameOfLifeBoard)
{
// Run the game of life until the board is empty or the exact same board is seen twice
// Important note: this method does NOT necessarily terminate!!
def go : Unit =
{
var currentBoard = initialBoard
var previousBoards = List[GameOfLifeBoard]()
while (!currentBoard.empty && !(previousBoards contains currentBoard))
{
print(27.toChar + "[2J") // ANSI: clear screen
print(27.toChar + "[;H") // ANSI: move cursor to top left corner of screen
println(currentBoard.toString)
Thread.sleep(75)
// Warning: unbounded list concatenation can result in OutOfMemoryExceptions ####TODO: replace with LRU bounded list
previousBoards = List(currentBoard) ::: previousBoards
currentBoard = currentBoard tick
}
// Print the final board
print(27.toChar + "[2J") // ANSI: clear screen
print(27.toChar + "[;H") // ANSI: move cursor to top left corner of screen
println(currentBoard.toString)
}
}
// Script starts here
val simple = Set((1,1))
val square = Set((4,4), (4,5), (5,4), (5,5))
val glider = Set((2,1), (3,2), (1,3), (2,3), (3,3))
val initialBoard = glider
(new GameOfLife(new FiniteGameOfLifeBoard(20, 20, initialBoard))).go
//(new GameOfLife(new InfiniteGameOfLifeBoard(initialBoard))).go
// COPYRIGHT PETER MONKS 2010
एक विशिष्ट प्रश्न: मैं एक बिंदु (! स्काला प्रकार निष्कर्ष FTW) पर काम करता है सब की तरफ से वापसी प्रकार हटा दिया, लेकिन पाया कोड वास्तव में पढ़ने के लिए कठिन हो गया। क्या स्काला को उन्हें बाहर निकालने के लिए रिटर्न प्रकार छोड़ने के बारे में कोई सम्मेलन है (उन मामलों से परे जहां वे आवश्यक हैं)?
रखें एक ही पंक्ति में ब्रेस खोलने। यदि आप जावा में कोड करते हैं तो वही करते हैं। – OscarRyz
धन्यवाद, लेकिन मैं एक पुरानी स्कूल एएनएसआई-सी शैली लड़का हूं, इसलिए जल्द ही मेरी ब्रेस/इंडेंटेशन शैली को बदलने की संभावना नहीं है। ;-) – Peter
यही वही है जो मैंने माना :) लेकिन, आपने कहा: * मेरे कोड की आलोचना करें * :) मुझे लगता है कि यह एक प्राकृतिक भाषा सीखने जैसा है, आपके पास हमेशा एक विदेशी उच्चारण होगा। – OscarRyz