I am trying to make a connect four game in scala. Currently i have it so it prints the board everytime and switches between players asking them to enter which column they want. The problem is I dont know how to change the rows. All 64 moves stay in row 7 (the 1st row). I was thinking of somehow doing a check that will check if there is already an X or O in the spot the user wants to play and just bump up the row. Would i use a if else for this? So if x or o is there move up a row else make move.
// Initialize the grid
val table = Array.fill(9,8)('.')
var i = 0;
while(i < 8){
table(8)(i) = (i+'0').toChar
i = i+1;
}
/* printGrid: Print out the grid provided */
def printGrid(table: Array[Array[Char]]) {
table.foreach( x => println(x.mkString(" ")))
}
var allowedMoves = 64
var spotsLeft = 8
//Player One
def player1(){
printGrid(table)
println("Player 1 it is your turn. Choose a column 0-7")
val move = readInt
table(7)(move) = ('X')
}
//Player Two
def player2(){
printGrid(table)
println("Player 1 it is your turn. Choose a column 0-7")
val move = readInt
table(7)(move) = ('O')
for (turn <- 1 to 32) {
player 1
player 2
}
I am not sure if you're still baffled by my comments, but let me try to give you a more in-depth explanation here.
The code in question is:
//Player One
def player1(){
printGrid(table)
println("Player 1 it is your turn. Choose a column 0-7")
val move = readInt
table(7)(move) = ('X')
}
//Player Two
def player2(){
printGrid(table)
println("Player 1 it is your turn. Choose a column 0-7")
val move = readInt
table(7)(move) = ('O')
}
for (turn <- 1 to 32) {
player1
player2
}
where the players take turns. But before going straight to the answer, let us refactor this code a bit by removing the duplication we have here. player1 and player2 are almost the same implementation. So let us pass the distinct parts as a parameter. The distinct part is the name of the player and the symbol that represents this player in the table. So let us define a class Player:
case class Player(name: String, symbol: Char)
and contract the two functions into one:
def player(player: Player): Unit ={
printGrid(table)
println(s"${player.name} it is your turn. Choose a column 0-7")
val move = readInt
table(7)(move) = player.symbol
}
for (turn <- 1 to 32) {
player(Player("Player 1", 'X'))
player(Player("Player 2", 'O'))
}
Now, we don't have to do everything twice, but the problem is still the same.
Okay, let's say, we are going to use conditionals: If table(7)(move) is occupied, then we choose table(6)(move). However, if this is also occupied, we choose table(5)(move). This goes on, until we find the column is completely full, in which case we may for example want to throw an exception. In code, this would look as follows:
def player(player: Player): Unit = {
printGrid(table)
println(s"${player.name} it is your turn. Choose a column 0-7")
val move = readInt
if (table(7)(move) != '.') {
if (table(6)(move) != '.') {
if (table(5)(move) != '.') {
if (table(4)(move) != '.') {
if (table(3)(move) != '.') {
if (table(2)(move) != '.') {
if (table(1)(move) != '.') {
if (table(0)(move) != '.') {
throw new IllegalArgumentException(s"Column $move is already full")
} else table(0)(move) = player.symbol
} else table(1)(move) = player.symbol
} else table(2)(move) = player.symbol
} else table(3)(move) = player.symbol
} else table(4)(move) = player.symbol
} else table(5)(move) = player.symbol
} else table(6)(move) = player.symbol
} else table(7)(move) = player.symbol
}
Let's run the code and... yay, it works!. But it is terrible code. There is an awful lot of duplication and we couldn't easily make the table bigger.
Okay, what problem do we really want to solve? We want to find the highest index of the row that has a free space at move, i.e., contains a '.' at move.
How could we find this index? There exists a function indexOf that takes an argument x and returns the index of the first occurrence of x in the array. But our array table is a two-dimensional array, and we care only about the value at move in each inner array. Fortunately, every collection in Scala provides a function map to map each element, so we could do: table map (_(move)).
Say that we receive the following array: . . O X O O 2, so the index of the last occurrence of . is 1. But indexOf will return the first index, so indexOf('.') would return 0. We could reverse the array, because finding the first index in the reversed array is equivalent to finding the last index in the array, but this is a bit tricky, as we also need to inverse the index, because the the index in the reversed array is generally not the same as the index in the original array.
Let's apply a little trick: Instead of finding the last index of ., let's find the index of the first element that is not . and subtract one. But the function indexOf does not allow us to pass a not x. However, we can solve this problem by modifying our map function slightly: Instead of table map (_(move)), let's map to table map (_(move) == '.'). Now, we need to find the index of the first false value and subtract one.
The whole solution would look as follows:
def player(player: Player): Unit = {
printGrid(table)
println(s"${player.name} it is your turn. Choose a column 0-7")
val move = readInt
val freeRows = table map (_(move) == '.')
val indexOfLastFreeRow = (freeRows indexOf false) - 1
if (indexOfLastFreeRow == -1) throw new IllegalArgumentException(s"Column $move is already full")
else table(indexOfLastFreeRow)(move) = player.symbol
}
for (turn <- 1 to 32) {
player(Player("Player 1", 'X'))
player(Player("Player 2", 'O'))
}
case class Player(name: String, symbol: Char)
I hope this answer helps. As a final note: I would still not work with plain arrays, but instead define a class Table and Column and let them provide the functionality to add elements, and an appropriate toString to print the table.
case class Table(columns: List[Column]) {
override def toString = (for (i <- 0 until columns.head.values.length) yield {
columns map (_.values(i).toString) reduceLeft (_ + " " + _)
}) reduceLeft (_ + System.lineSeparator + _)
def add(entry: Char, columnIndex: Int): Table = {
val (prefix, column :: suffix) = columns.splitAt(columnIndex)
Table(prefix ++ (column.add(entry) :: suffix))
}
}
object Table {
val EmptyEntry = '.'
def empty(numberOfColumns: Int, numberOfRows: Int): Table =
Table(List.fill(numberOfColumns)(Column.empty(numberOfRows)))
}
case class Column(values: List[Char]) {
def isFull: Boolean = !values.contains(Table.EmptyEntry)
def add(entry: Char): Column = {
if (isFull) this
else {
val (empty, filled) = values.partition(_ == Table.EmptyEntry)
Column(empty.dropRight(1) ++ (entry :: filled))
}
}
}
object Column {
def empty(numberOfRows: Int): Column =
Column(List.fill(numberOfRows)(Table.EmptyEntry))
}
Related
I want to extract a word from a String in Scala
val text = "This ball is from Rock. He is good boy"
I want to extract "Rock" from the string.
I tried:
val op = text.subString(4)
text is not a fixed length string. I just want to pick first word after "From".
This doesnt give the right word. can anyone suggest.
This does what you want:
text.drop(text.indexOfSlice("from ")+5).takeWhile(_.isLetter)
or more generally
val delim = "from "
text.drop(text.indexOfSlice(delim)+delim.length).takeWhile(_.isLetter)
The indexOfSlice finds the position of the delimiter and the drop removes everything up to the end of the delimiter. The takeWhile takes all the letters for the word and stops at the first non-letter character (in this case ".").
Note that this is case sensitive so it will not find "From ", it will only work with "from ". If more complex testing is required then use split to convert to separate words and check each word in turn.
This is because you are telling scala to print everything from 4th index to end of string.
In your case you first want to split the string into words which can be done using split function and then access the word you want.
Note: split gives you an array of string and array index begin from 0 in scala so rock would be at the 4th index
This piece of code should work for you. Basically I am using a function to the processing of index of the word that immediately follows a substring (in this case from)
val text = "This ball is from Rock. He is good boy"
val splitText = text.split("\\W+")
println(splitText(4))
Based on your comment below, I would create a code something like this
import scala.util.control.Breaks.{break, breakable}
object Question extends App {
val text = "This ball is from Rock. He is from good boy"
val splitText = text.split("\\W+")
val index = getIndex(splitText, "from")
println(index)
if (index != -1) {
println(splitText(index))
}
def getIndex(arrSplit: Array[String], subString: String): Int = {
var output = -1
var index = 0
breakable {
for(item <- arrSplit) {
if(item.equalsIgnoreCase(subString)) {
output = index + 1
break
}
index = index + 1
}
}
output
}
}
I hope this is what you are expecting:
object Test2 extends App {
val text = "This ball is from Rock. He is good boy"
private val words = text.split(" ")
private val wordToTrack = "from"
val indexOfFrom = words.indexOf(wordToTrack);
val expectedText = words.filterNot{
case word if indexOfFrom < words.size & words.contains(wordToTrack) =>
word == words(indexOfFrom + 1)
case _ => false
}.mkString(" ")
print(expectedText)
}
words.contains(wordToTrack) guards the scenario if the from word(i.e tracking word for this example) is missing in the input text string.
I have used the partial function along with the filter to get the desired result.
You probably want something more general so that you can extract a word from a sentence if that word is present in the input, without having to hard-code offsets:
def extractWordFromString(input: String, word: String): Option[String] = {
val wordLength = word.length
val start = input.indexOfSlice(word)
if (start == -1) None else Some(input.slice(start, start + wordLength))
}
Executing extractWordFromString(text, "Rock") will give you an option containing the target word from input if it was found, and an empty option otherwise. That way you can handle the case where the word you were searching for was not found.
I have a textfile like so
NameOne,2,3,3
NameTwo,1,0,2
I want to find the indices of the max value in each line in Scala. So the output of this would be
NameOne,1,2
NameTwo,2
I'm currently using the function below to do this but I can't seem to find a simple way to do this without a for loop and I'm wondering if there is a better method out there.
def findIndices(movieRatings: String): (String) = {
val tokens = movieRatings.split(",", -1)
val movie = tokens(0)
val ratings = tokens.slice(1, tokens.size)
val max = ratings.max
var indices = ArrayBuffer[Int]()
for (i<-0 until ratings.length) {
if (ratings(i) == max) {
indices += (i+1)
}
}
return movie + "," + indices.mkString(",")
}
This function is called as so:
val output = textFile.map(findIndices).saveAsTextFile(args(1))
Just starting to learn Scala so any advice would help!
You can zipWithIndex and use filter:
ratings.zipWithIndex
.filter { case(_, value) => value == max }
.map { case(index, _) => index }
I noticed that your code doesn't actually produce the expected result from your example input. I'm going to assume that the example given is the correct result.
def findIndices(movieRatings :String) :String = {
val Array(movie, ratings #_*) = movieRatings.split(",", -1)
val mx = ratings.maxOption //Scala 2.13.x
ratings.indices
.filter(x => mx.contains(ratings(x)))
.mkString(s"$movie,",",","")
}
Note that this doesn't address some of the shortcomings of your algorithm:
No comma allowed in movie name.
Only works for ratings from 0 to 9. No spaces allowed.
testing:
List("AA"
,"BB,"
,"CC,5"
,"DD,2,5"
,"EE,2,5, 9,11,5"
,"a,b,2,7").map(findIndices)
//res0: List[String] = List(AA, <-no ratings
// , BB,0 <-comma, no ratings
// , CC,0 <-one rating
// , DD,1 <-two ratings
// , EE,1,4 <-" 9" and "11" under valued
// , a,0 <-comma in name error
// )
I have been trying to code some scalacheck property to verify the Codility TapeEquilibrium problem. For those who do not know the problem, see the following link: https://app.codility.com/programmers/lessons/3-time_complexity/tape_equilibrium/.
I coded the following yet incomplete code.
test("Lesson 3 property"){
val left = Gen.choose(-1000, 1000).sample.get
val right = Gen.choose(-1000, 1000).sample.get
val expectedSum = Math.abs(left - right)
val leftArray = Gen.listOfN(???, left) retryUntil (_.sum == left)
val rightArray = Gen.listOfN(???, right) retryUntil (_.sum == right)
val property = forAll(leftArray, rightArray){ (r: List[Int], l: List[Int]) =>
val array = (r ++ l).toArray
Lesson3.solution3(array) == expectedSum
}
property.check()
}
The idea is as follows. I choose two random numbers (values left and right) and calculate its absolute difference. Then, my idea is to generate two arrays. Each array will be random numbers whose sum will be either "left" or "right". Then by concatenating these array, I should be able to verify this property.
My issue is then generating the leftArray and rightArray. This itself is a complex problem and I would have to code a solution for this. Therefore, writing this property seems over-complicated.
Is there any way to code this? Is coding this property an overkill?
Best.
My issue is then generating the leftArray and rightArray
One way to generate these arrays or (lists), is to provide a generator of nonEmptyList whose elements sum is equal to a given number, in other word, something defined by method like this:
import org.scalacheck.{Gen, Properties}
import org.scalacheck.Prop.forAll
def listOfSumGen(expectedSum: Int): Gen[List[Int]] = ???
That verifies the property:
forAll(Gen.choose(-1000, 1000)){ sum: Int =>
forAll(listOfSumGen(sum)){ listOfSum: List[Int] =>
(listOfSum.sum == sum) && listOfSum.nonEmpty
}
}
To build such a list only poses a constraint on one element of the list, so basically here is a way to generate:
Generate list
The extra constrained element, will be given by the expectedSum - the sum of list
Insert the constrained element into a random index of the list (because obviously any permutation of the list would work)
So we get:
def listOfSumGen(expectedSum: Int): Gen[List[Int]] =
for {
list <- Gen.listOf(Gen.choose(-1000,1000))
constrainedElement = expectedSum - list.sum
index <- Gen.oneOf(0 to list.length)
} yield list.patch(index, List(constrainedElement), 0)
Now we the above generator, leftArray and rightArray could be define as follows:
val leftArray = listOfSumGen(left)
val rightArray = listOfSumGen(right)
However, I think that the overall approach of the property described is incorrect, as it builds an array where a specific partition of the array equals the expectedSum but this doesn't ensure that another partition of the array would produce a smaller sum.
Here is a counter-example run-through:
val left = Gen.choose(-1000, 1000).sample.get // --> 4
val right = Gen.choose(-1000, 1000).sample.get // --> 9
val expectedSum = Math.abs(left - right) // --> |4 - 9| = 5
val leftArray = listOfSumGen(left) // Let's assume one of its sample would provide List(3,1) (whose sum equals 4)
val rightArray = listOfSumGen(right)// Let's assume one of its sample would provide List(2,4,3) (whose sum equals 9)
val property = forAll(leftArray, rightArray){ (l: List[Int], r: List[Int]) =>
// l = List(3,1)
// r = List(2,4,3)
val array = (l ++ r).toArray // --> Array(3,1,2,4,3) which is the array from the given example in the exercise
Lesson3.solution3(array) == expectedSum
// According to the example Lesson3.solution3(array) equals 1 which is different from 5
}
Here is an example of a correct property that essentially applies the definition:
def tapeDifference(index: Int, array: Array[Int]): Int = {
val (left, right) = array.splitAt(index)
Math.abs(left.sum - right.sum)
}
forAll(Gen.nonEmptyListOf(Gen.choose(-1000,1000))) { list: List[Int] =>
val array = list.toArray
forAll(Gen.oneOf(array.indices)) { index =>
Lesson3.solution3(array) <= tapeDifference(index, array)
}
}
This property definition might collides with the way the actual solution has been implemented (which is one of the potential pitfall of scalacheck), however, that would be a slow / inefficient solution hence this would be more a way to check an optimized and fast implementation against slow and correct implementation (see this presentation)
Try this with c# :
using System;
using System.Collections.Generic;
using System.Linq;
private static int TapeEquilibrium(int[] A)
{
var sumA = A.Sum();
var size = A.Length;
var take = 0;
var res = new List<int>();
for (int i = 1; i < size; i++)
{
take = take + A[i-1];
var resp = Math.Abs((sumA - take) - take);
res.Add(resp);
if (resp == 0) return resp;
}
return res.Min();
}
I want to write a for loop in scala, but the counter should get incremented by more than one (the amount is variable) in some special cases.
You can do this with a combination of a filter and an external var. Here is an example:
var nextValidVal = 0
for (i <- 0 to 99; if i >= nextValidVal) {
var amountToSkip = 0
// Whatever this loop is for
nextValidVal = if (amountToSkip > 0) i + amountToSkip + 1 else nextValidVal
}
So in the main body of your loop, you can set amountToSkip to n according to your conditions. The next n values of i´s sequence will be skipped.
If your sequence is pulled from some other kind of sequence, you could do it like this
var skip = 0
for (o <- someCollection if { val res = skip == 0; skip = if (!res) skip - 1 else 0; res } ) {
// Do stuff
}
If you set skip to a positive value in the body of the loop, the next n elements of the sequence will be skipped.
Of course, this is terribly imperative and side-effecty. I would look for other ways to to this where ever possible, by mapping or filtering or folding the original sequence.
You could implement your own stream to reflect step, for example:
import scala.collection.immutable.Stream
import ForStream._
object Test {
def main(args: Array[String]): Unit = {
val range = 0 to 20 by 1 withVariableStep; // in case you like definition through range
//val range = ForStream(0,20,1) // direct definition
for (i<- range) {
println(s"i=$i")
range.step = range.step + 1
}
}
}
object ForStream{
implicit def toForStream(range: Range): ForStream = new ForStreamMaster(range.start, range.end,range.step)
def apply(head:Int, end:Int, step:Int) = new ForStreamMaster(head, end,step)
}
abstract class ForStream(override val head: Int, val end: Int, var step: Int) extends Stream[Int] {
override val tailDefined = false
override val isEmpty = head > end
def withVariableStep = this
}
class ForStreamMaster(_head: Int, _end: Int, _Step: Int) extends ForStream(_head, _end,_Step){
override def tail = if (isEmpty) Stream.Empty else new ForStreamSlave(head + step, end, step, this)
}
class ForStreamSlave(_head: Int, _end: Int, _step: Int, val master: ForStream) extends ForStream(_head, _end,_step){
override def tail = if (isEmpty) Stream.Empty else new ForStreamSlave(head + master.step, end, master.step, master)
}
This prints:
i=0
i=2
i=5
i=9
i=14
i=20
You can define ForStream from Range with implicits, or define it directly. But be carefull:
You are not iterating Range anymore!
Stream should be immutable, but step is mutable!
Also as #om-nom-nom noted, this might be better implemented with recursion
Why not use the do-while loop?
var x = 0;
do{
...something
if(condition){change x to something else}
else{something else}
x+=1
}while(some condition for x)
Much like this question:
Functional code for looping with early exit
Say the code is
def findFirst[T](objects: List[T]):T = {
for (obj <- objects) {
if (expensiveFunc(obj) != null) return /*???*/ Some(obj)
}
None
}
How to yield a single element from a for loop like this in scala?
I do not want to use find, as proposed in the original question, i am curious about if and how it could be implemented using the for loop.
* UPDATE *
First, thanks for all the comments, but i guess i was not clear in the question. I am shooting for something like this:
val seven = for {
x <- 1 to 10
if x == 7
} return x
And that does not compile. The two errors are:
- return outside method definition
- method main has return statement; needs result type
I know find() would be better in this case, i am just learning and exploring the language. And in a more complex case with several iterators, i think finding with for can actually be usefull.
Thanks commenters, i'll start a bounty to make up for the bad posing of the question :)
If you want to use a for loop, which uses a nicer syntax than chained invocations of .find, .filter, etc., there is a neat trick. Instead of iterating over strict collections like list, iterate over lazy ones like iterators or streams. If you're starting with a strict collection, make it lazy with, e.g. .toIterator.
Let's see an example.
First let's define a "noisy" int, that will show us when it is invoked
def noisyInt(i : Int) = () => { println("Getting %d!".format(i)); i }
Now let's fill a list with some of these:
val l = List(1, 2, 3, 4).map(noisyInt)
We want to look for the first element which is even.
val r1 = for(e <- l; val v = e() ; if v % 2 == 0) yield v
The above line results in:
Getting 1!
Getting 2!
Getting 3!
Getting 4!
r1: List[Int] = List(2, 4)
...meaning that all elements were accessed. That makes sense, given that the resulting list contains all even numbers. Let's iterate over an iterator this time:
val r2 = (for(e <- l.toIterator; val v = e() ; if v % 2 == 0) yield v)
This results in:
Getting 1!
Getting 2!
r2: Iterator[Int] = non-empty iterator
Notice that the loop was executed only up to the point were it could figure out whether the result was an empty or non-empty iterator.
To get the first result, you can now simply call r2.next.
If you want a result of an Option type, use:
if(r2.hasNext) Some(r2.next) else None
Edit Your second example in this encoding is just:
val seven = (for {
x <- (1 to 10).toIterator
if x == 7
} yield x).next
...of course, you should be sure that there is always at least a solution if you're going to use .next. Alternatively, use headOption, defined for all Traversables, to get an Option[Int].
You can turn your list into a stream, so that any filters that the for-loop contains are only evaluated on-demand. However, yielding from the stream will always return a stream, and what you want is I suppose an option, so, as a final step you can check whether the resulting stream has at least one element, and return its head as a option. The headOption function does exactly that.
def findFirst[T](objects: List[T], expensiveFunc: T => Boolean): Option[T] =
(for (obj <- objects.toStream if expensiveFunc(obj)) yield obj).headOption
Why not do exactly what you sketched above, that is, return from the loop early? If you are interested in what Scala actually does under the hood, run your code with -print. Scala desugares the loop into a foreach and then uses an exception to leave the foreach prematurely.
So what you are trying to do is to break out a loop after your condition is satisfied. Answer here might be what you are looking for. How do I break out of a loop in Scala?.
Overall, for comprehension in Scala is translated into map, flatmap and filter operations. So it will not be possible to break out of these functions unless you throw an exception.
If you are wondering, this is how find is implemented in LineerSeqOptimized.scala; which List inherits
override /*IterableLike*/
def find(p: A => Boolean): Option[A] = {
var these = this
while (!these.isEmpty) {
if (p(these.head)) return Some(these.head)
these = these.tail
}
None
}
This is a horrible hack. But it would get you the result you wished for.
Idiomatically you'd use a Stream or View and just compute the parts you need.
def findFirst[T](objects: List[T]): T = {
def expensiveFunc(o : T) = // unclear what should be returned here
case class MissusedException(val data: T) extends Exception
try {
(for (obj <- objects) {
if (expensiveFunc(obj) != null) throw new MissusedException(obj)
})
objects.head // T must be returned from loop, dummy
} catch {
case MissusedException(obj) => obj
}
}
Why not something like
object Main {
def main(args: Array[String]): Unit = {
val seven = (for (
x <- 1 to 10
if x == 7
) yield x).headOption
}
}
Variable seven will be an Option holding Some(value) if value satisfies condition
I hope to help you.
I think ... no 'return' impl.
object TakeWhileLoop extends App {
println("first non-null: " + func(Seq(null, null, "x", "y", "z")))
def func[T](seq: Seq[T]): T = if (seq.isEmpty) null.asInstanceOf[T] else
seq(seq.takeWhile(_ == null).size)
}
object OptionLoop extends App {
println("first non-null: " + func(Seq(null, null, "x", "y", "z")))
def func[T](seq: Seq[T], index: Int = 0): T = if (seq.isEmpty) null.asInstanceOf[T] else
Option(seq(index)) getOrElse func(seq, index + 1)
}
object WhileLoop extends App {
println("first non-null: " + func(Seq(null, null, "x", "y", "z")))
def func[T](seq: Seq[T]): T = if (seq.isEmpty) null.asInstanceOf[T] else {
var i = 0
def obj = seq(i)
while (obj == null)
i += 1
obj
}
}
objects iterator filter { obj => (expensiveFunc(obj) != null } next
The trick is to get some lazy evaluated view on the colelction, either an iterator or a Stream, or objects.view. The filter will only execute as far as needed.