1

My goal is to have the user input a number N and the size of the arrayList be 2N + 1.

Ultimately my arrayList for N=2 should be "OO XX".

public Board(int size)
    {
        tiles = new ArrayList<Tile>(size);

        for(int index = 0; index < size; index++)
        {
            tiles.add(new Tile('O')); 
            tiles.add(new Tile(' '));
            tiles.add(new Tile('X')); 

            System.out.print(tiles.get(index));
        }          

    }

The above code gives me "O XO". How can I modify it to show me OO XX ?

Thanks ahead!

Vladdy
  • 31
  • 3
  • If N=2, then size would be 2N+1 = 5. It will never be "OOO XXX" which is 7 tiles, but will terminate after 5 tiles "O XO " – hrv Sep 25 '13 at 19:27
  • your question does not match your example. For N=2, 2N+1 is 5, thus the result would be "OO XX" not "OOO XXX". – djb Sep 25 '13 at 19:29

4 Answers4

4

If you would like to do it in a single loop, you can do it like this:

for (int i = 0 ; i != 2*size+1 ; i++) {
    tiles.add(new Tile(i==size ? ' ' : (i<size ? 'O' : 'X')));
}

The idea is to compute the total size (that's 2*size+1) and then use conditionals to decide on which side of the midpoint we are.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 3
    Unusual use of `!=` instead of standard `<`. Will turn into an endless loop for negative size. – Marko Topolnik Sep 25 '13 at 19:31
  • 1
    ...Please don't actually do this? Cramming this into a single loop is nice in principle, but it's kind of unreadable this way. – Louis Wasserman Sep 25 '13 at 19:32
  • 1
    I think putting it in a single loop is quite nice, and doesn't hurt readability. Actually, I think it increases readability. – axiopisty Sep 25 '13 at 19:34
  • 1
    @MarkoTopolnik That's not a slightest bit unusual ([here is why I use it](http://stackoverflow.com/a/8884617/335858)); Making it an infinite loop is good for debugging: negative sizes have no place in production code, right? – Sergey Kalinichenko Sep 25 '13 at 19:35
  • @axiopisty: I don't know about you, but I needed 15 seconds or so to parse that nested ternary. (There's an alternate three-line solution in my post that takes a different approach...) – Louis Wasserman Sep 25 '13 at 19:35
  • 1
    @LouisWasserman it may take you so long to parse them, because you've been drilled into your head that ternary is bad, and never learned them. This is very readable, and immediately apparent to me. – Cruncher Sep 25 '13 at 19:37
  • 3
    @Cruncher: I'm a huge fan of ternaries. I use them all the time. But I have come to the conclusion that if you _are_ going to nest them, you should at least break up the formatting onto multiple lines. – Louis Wasserman Sep 25 '13 at 19:39
  • 1
    @LouisWasserman I posted this mostly to demonstrate a way to do that in a single loop, because two-loop solutions were "taken" by the time I saw the question. I liked your no-loop solution even better, though. – Sergey Kalinichenko Sep 25 '13 at 19:41
  • 1
    @dasblinkenlight That depends, actually. There are many real-world situations where a negative argument can arise and the desired semantics are to treat it gracefully. I for one hate it when I receive bug complaints and have to make a whole new application build and deployment because at some point a slightly different use case appears and my code is too brittle to handle it. – Marko Topolnik Sep 25 '13 at 19:42
  • @RohitJain I don't know where you see sarcasm. I feel I was pretty straight forward. I don't mean to be derogatory, I just know that a lot of people were taught to avoid the ternary operator(myself included). It's a self-fulfilling prophecy when you tell people not to use it, then they don't learn them and then never like them. – Cruncher Sep 25 '13 at 19:42
  • @Cruncher. Hmm. May be I mis-interpreted your comment. Sorry for that. :) – Rohit Jain Sep 25 '13 at 19:45
2

Parameter you pass in one-arg ArrayList(int) constructor is not the fixed size of the list. It's just the initial capacity. If your size is fix, then you can use an array:

Tile[] tiles = new Tile[2 * n + 1];

And then filling the array is pretty simple, by using Arrays#fill(Object[] a, int fromIndex, int toIndex, Object val) method:

Arrays.fill(tiles, 0, n, new Tile('O'));
tiles[n] = new Tile(' ');
Arrays.fill(tiles, (n + 1), (2 * n + 1), new Tile('X'));

Although, as noted in comments, this will fill the array indices with reference to same object. Might work fine with immutable Tile, but not with mutable one.

Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • What's the advantages of using an array over an arraylist with an initial capacity? The operations aren't any slower, there's already room in the array for what he needs – Cruncher Sep 25 '13 at 19:32
  • Wouldn't that fill the entire array with references to just three tile objects?.. On the other hand, if `Tile` is immutable, that would be the desired effect... – Sergey Kalinichenko Sep 25 '13 at 19:33
  • @dasblinkenlight. Umm. Actually right. Missed that part somehow. – Rohit Jain Sep 25 '13 at 19:33
  • @dasblinkenlight If `Tile` isn't immutable, it should be fixed to become immutable :) – Marko Topolnik Sep 25 '13 at 19:33
  • @Cruncher. Of course there is room for array. But since OP wants a fixed size array, I would go for an array instead. I don't say there is any particular advantage here. Another reason can be, I just wanted to use `Arrays#fill()` method. Actually, I didn't knew earlier that there is similar method for `Collections` before I saw it in @Louis's answer. :) – Rohit Jain Sep 25 '13 at 19:42
  • `Arrays.fill` is more efficient, though, because `Collections.nCopies` involves creating a temporary collection and then copying all the elements into the target collection. I would go with the array approach except if absolutely didn't care about performance. – Marko Topolnik Sep 25 '13 at 19:47
  • 1
    @MarkoTopolnik: The "temporary collection" has only O(1) memory consumption, so I'm inclined to call it a wash. – Louis Wasserman Sep 25 '13 at 19:52
1

Your initialization of tiles is just fine, but the rest of the logic needs some work.

for(int index = 0; index < size; index++) {
  tiles.add(new Tile('O')); 
}
tiles.add(new Tile(' ')); 
for (int index = 0; index < size; index++) {
  tiles.add(new Tile('X'));
}

Or, if you feel like being cute...

tiles.addAll(Collections.nCopies(size, new Tile('O')));
tiles.add(new Tile(' '));
tiles.addAll(Collections.nCopies(size, new Tile('X')));

...though that version might be a problem if you expect to modify the Tile objects later.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • 1
    use N people not size – hasan Sep 25 '13 at 19:29
  • add: tiles = new ArrayList(2*size + 1); and consider using Singleton patter (only create one Tile for each of 'O', ' ' and 'X' – djb Sep 25 '13 at 19:31
  • @djb: the first line was already in the OP's post, and the OP has provided no indication of whether `Tile` is mutable or safe to use as a singleton at all. I'm sticking to the OP's apparent expectations and requirements as much as I can, including using the OP's `size` variable, @hasan. – Louis Wasserman Sep 25 '13 at 19:33
  • 1
    I like the "no-loops" approach! – Sergey Kalinichenko Sep 25 '13 at 19:42
1

Try this:

// it's not necessary to specify the initial capacity,
// but this is the correct way to do it for this problem
tiles = new ArrayList<Tile>(2*size + 1);

// first add all the 'O'
for (int index = 0; index < size; index++)
    tiles.add(new Tile('O'));
// add the ' '
tiles.add(new Tile(' '));
// finally add all the 'X'
for (int index = 0; index < size; index++)
    tiles.add(new Tile('X'));

// verify the result, for size=2
System.out.println(tiles);
=> [O, O,  , X, X]
Óscar López
  • 232,561
  • 37
  • 312
  • 386