Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
smackfu
Jun 7, 2004

Why would you roll your own DAOs?

Adbot
ADBOT LOVES YOU

ToxicSlurpee
Nov 5, 2003

-=SEND HELP=-


Pillbug

Data Graham posted:

Such as not using java?

I actually don't mean that to sound snarky. I'm really wondering: what are the benefits of using Java for web dev, when there are plenty of other stacks available that don't require you to muck around with IDEs or roll your own DAOs? Is the performance benefit that significant? Or is it all about scale, for maintainability of large codebases?

Java is still among the most popular languages. It also has a bunch of cool tools being written for it; there is an absolute poo poo load of stuff out there. In particular Spring is fantastic.

Of course some of it is just inertia; why bother rewriting your entire stack all in one go? That takes a lot of effort. A lot of the old code still works so just add on to the mud blob.

As for DAOs you don't have to write them yourself anymore. Spring has some goodies and JPA exists. So does Hibernate.

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.

Data Graham posted:

don't require you to muck around with IDEs
What's wrong with using an IDE?

TheresaJayne
Jul 1, 2011

Data Graham posted:

Such as not using java?

I actually don't mean that to sound snarky. I'm really wondering: what are the benefits of using Java for web dev, when there are plenty of other stacks available that don't require you to muck around with IDEs or roll your own DAOs? Is the performance benefit that significant? Or is it all about scale, for maintainability of large codebases?

The only drawback is hosting is more expensive as unless the hosting company has set up correctly apache/tomcat you cannot have multiple websites on the same ip address.

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

Data Graham posted:

don't require you to muck around with IDEs

Are you one of those awful "I'll just keep everything in my head and use a plain text editor" people?

Data Graham
Dec 28, 2009

📈📊🍪😋



For web it's always seemed way more straightforward :shrug: For editing code on remote servers and all.

I'm happy to use an IDE for stuff like iOS, where it's clearly necessary, but it seems like huge overkill for webdev.

Carbon dioxide
Oct 9, 2012

Data Graham posted:

For web it's always seemed way more straightforward :shrug: For editing code on remote servers and all.

I'm happy to use an IDE for stuff like iOS, where it's clearly necessary, but it seems like huge overkill for webdev.

Really? It would be utterly infeasible to edit our entire codebase for the websites remotely. We got things set up like most java webdev projects seem to be: running a copy of the site locally, add what we need and test, then commit the changes, use Jenkins to automatically deploy to a test server, then every release we deploy a branch to a few more layers of testing, and only when everything works we deploy to production during quiet hours so not many people have to deal with downtime. For security reasons no dev can log in to production directly, only some sysadmins have that right.

I wouldn't even know where to start considering dependencies and stuff without an IDE that keeps track of things.

Data Graham
Dec 28, 2009

📈📊🍪😋



Well yes, that's how I normally work for any project with significant size. I've just never seemed to need anything more than basic syntax coloring for most stuff, and dependencies don't tend to be much of an issue with sandboxed environments and such.

My happy place these days is Django, but I've built JSP sites and lots of other stuff back to the days of Catalyst and raw Perl and poo poo. At the very least I can agree that JSP's idea of template/scriptlet separation is a horrorshow, but I'm glad there are better ways nowadays that don't mean "you have to write three big boilerplatey class files for every model".

Gravity Pike
Feb 8, 2009

I find this discussion incredibly bland and disinteresting.

smackfu posted:

Why would you roll your own DAOs?

We use JOOQ, which means that a pre-build (generate-sources) step generates Table and Record objects, and we write our own DAOs using the JOOQ DSL. We end up with things like:

code:
final UUID tokenId = using(configuration)
    .select(TOKEN.ID)
    .from(TOKEN)
    .innerJoin(PERSON).on(PERSON.ID.eq(TOKEN.PERSON_ID)
    .where(TOKEN.KEY.eq("mykey"))
    .and(TOKEN.SECRET.eq("hunter2"))
    .and(PERSON.ACTIVE.isTrue())
    .fetchOptional()
    .orElseThrow(() -> new UnauthorizedException());
Anything trivial like that is, well, trivial to write into the DAO, and we've got support for things like Postgresql's Common Table Expressions for when we need them.

Defenestrategy
Oct 24, 2010

So I'm making a program that takes in a text document, input.txt, and then copies it to a new file it creates called output.txt. I believe my below program should work, the exception handling will work, and it will create a text file called "output", but it won't write anything to it. I think the problem is with the Writer, because the loop will print to console if I just use System.out.print(line)

code:
import java.io.*;

public class filereadwrite {


	
	public static void main(String[] args)throws IOException {
		
		File file2 = new File("output.txt");
		 if (file2.exists()){
			 System.out.println("This file exists already");
			 System.exit(0);
		 }
		 
		  FileWriter fw = new FileWriter(file2);
		
		 
		File file = new File("fileInput.txt");

        BufferedReader br = null;

        try {
            FileReader fr = new FileReader(file);
            br = new BufferedReader(fr);
            String line;
            while( (line = br.readLine()) != null ) {
         		  fw.write(line);
            }

        } catch (FileNotFoundException e) {
            System.out.println("File not found");
            System.exit(0);
        }
	   
	    }
		 
		 
}

Defenestrategy fucked around with this message at 18:24 on Oct 12, 2016

smackfu
Jun 7, 2004

The parent of FileWriter is OutputStreamWriter, whose documentation says:

quote:

Each invocation of a write() method causes the encoding converter to be invoked on the given character(s). The resulting bytes are accumulated in a buffer before being written to the underlying output stream.

Given that, the documentation is pretty lacking in those classes. Like flush() is documented as "Flushes the stream" which requires you already know what flushing means. I guess the problem is that these are methods on abstract parent classes, so they have to be documented abstractly, and then they aren't documented at all on the concrete class like FileWriter, where the description of flush() would be "Writes the buffer to disk."

smackfu fucked around with this message at 18:38 on Oct 12, 2016

Volguus
Mar 3, 2009

KildarX posted:

So I'm making a program that takes in a text document, input.txt, and then copies it to a new file it creates called output.txt. I believe my below program should work, the exception handling will work, and it will create a text file called "output", but it won't write anything to it. I think the problem is with the Writer, because the loop will print to console if I just use System.out.print(line)

[... stuff


You're missing a fw.close(); before you exit. A fw.flush() would work as well as the OS will close the file after you exit, but it's better to close it yourself and not let others clean up after you.

more like dICK
Feb 15, 2010

This is inevitable.
Files.copy(source, target) once you're out of school

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

more like dICK posted:

Files.copy(source, target) once you're out of school

I imagine part 2 of this will involve modifying the input in some way before writing it to output. But yeah.

CPColin
Sep 9, 2003

Big ol' smile.
Use try-with-resources blocks for both the Reader and the Writer and you don't have to worry about explicitly closing them!

Defenestrategy
Oct 24, 2010

So I figured out the issue, I just don't know how to solve it. So if I step through the system. It looks like the output text file is not created until the very last step. So the thing reads all the lines, writes the lines to some where, and then creates an empty text file called "output", but if you already have a text file called output it fills it with the lines it's reading, but I thought that the programs run from first to last instruction.


So by the way I have the program set up shouldn't it 1) Create a file called output.txt if one doesn't exist already. 2) create a writer 3) check for a file named Fileinput.txt and 4) read a line and write a line till it finds a null line on the input?. Instead of creating the file last?

Volguus
Mar 3, 2009

KildarX posted:

So I figured out the issue, I just don't know how to solve it. So if I step through the system. It looks like the output text file is not created until the very last step. So the thing reads all the lines, writes the lines to some where, and then creates an empty text file called "output", but if you already have a text file called output it fills it with the lines it's reading, but I thought that the programs run from first to last instruction.


So by the way I have the program set up shouldn't it 1) Create a file called output.txt if one doesn't exist already. 2) create a writer 3) check for a file named Fileinput.txt and 4) read a line and write a line till it finds a null line on the input?. Instead of creating the file last?

Yes, and that's what it does. Except it doesn't do anything until it absolutely has to. You tell it to write to a file, it's much faster for it to lie to you (say that it's all ok, don't worry), cache your bunch of writes and then , only then when you call flush or close it will actually write anything.

And even then, the OS will lie to your program and say and all is cool, it wrote poo poo when in fact it didn't even move a muscle. Why? speed. If your power goes out and the OS didn't actually get around to actually write the bytes on disk, whoops .... You want safety? Buy an UPS. 2 even and 2 power-supplies for redundancy. And now you know why servers cost that much :).

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Just to be explicitly clear since I think people are talking past each other a little - when you're writing to the stream it's not necessarily writing to the file yet. Think of it like a conveyor belt, you put stuff on it and eventually it'll get taken off and put where it's meant to be going. Exactly when that happens depends on the situation and the setup

Calling flush() will force any stuff on the conveyor to be dealt with immediately. Calling close() (which you should always do when you're finished) will also do a final flush first

Oh also, new File() doesn't actually create a file, a File object is sort of like a representation of a path. You're using them as signposts to tell things where to look for an existing file, where the source file is, where to write the output data to, that kind of thing. But you're not creating a file on the filesystem until your program finally writes something to that destination path, whenever that actually happens

baka kaba fucked around with this message at 19:21 on Oct 12, 2016

Defenestrategy
Oct 24, 2010

baka kaba posted:

Good words.

Yep this makes it clear and now it does everything right, Thanks everyone.

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

KildarX posted:

Yep this makes it clear and now it does everything right, Thanks everyone.

OutputStreams and toilets. Always flush.

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope

carry on then posted:

OutputStreams and toilets. Always flush.

Uhhuh, but should you wipe standing up or sitting down?

Data Graham
Dec 28, 2009

📈📊🍪😋



I suppose front-to-back or back-to-front depends on how bigendian you are

Data Graham fucked around with this message at 20:28 on Oct 12, 2016

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...
Something something dirty bits

spiritual bypass
Feb 19, 2008

Grimey Drawer
I'd like to give Java web development a try. I didn't see any guides in the OP.

Anyone care to recommend some books or articles about choosing tools and writing a minimal web application?

geeves
Sep 16, 2004

I am terrible with Dates and it's the first time I've used Java8 with date formatting.

I have a date string (example: 2015-11-23T12:00:40+00:00) It's pulling a date from a Wordpress formatted date in the <meta property="article:published_time"> tag.

What is the parse string?

I've tried:

yyyy-MM-dd'T'HH:mm:ss
yyyy-MM-dd'T'HH:mm:ssZ
yyyy-MM-dd'T'HH:mm:ssZZ
yyyy-MM-dd'T'HH:mm:ssZZZ

I've been following the patterns here: http://stackoverflow.com/questions/4216745/java-string-to-date-conversion

Code:

code:
public static Date dateParse(String stringDate) throws Exception {
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern(FULL_DATE); // yyyy-MM-dd'T'HH:mm:ssZZZ
    log.info(stringDate + " | " + FULL_DATE);
    LocalDateTime ldt = LocalDateTime.parse(stringDate, dtf); // ERROR is here

    return Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());

}

code:
2016-10-16 12:12:45,025 ERROR [main] - TestDateParse:122 - Text '2016-02-11T13:00:40+00:00' could not be parsed at index 19
java.time.format.DateTimeParseException: Text '2016-02-11T13:00:40+00:00' could not be parsed at index 19
	at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
	at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
	at java.time.LocalDateTime.parse(LocalDateTime.java:492)
	at common.util.DateTimeUtil.dateParse(DateTimeUtil.java:33)

geeves fucked around with this message at 17:22 on Oct 16, 2016

Sedro
Dec 31, 2008
It says in the error message that it fails on index 19, which is the "+00:00" bit. I think the correct format would be yyyy-MM-dd'T'HH:mm:ssXXX.

That's a standard ISO date though so you can use the built-in format DateTimeFormatter.ISO_OFFSET_DATE_TIME. Also you want to use OffsetDateTime instead of LocalDateTime because there is a time zone involved.

M31
Jun 12, 2012
And you don't want to convert to Date, because Date is terrible (The Java 8 equivalent is Instant).

So just do return OffsetDateTime.parse(stringDate) or return OffsetDateTime.parse(stringDate).toInstant()

The code you have forces the system's default timezone, which is probably not want you want. It will lead to incorrect dates even if you get the formatter to work.

venutolo
Jun 4, 2003

Dinosaur Gum
You want something like this (fix any typos if it doesn't compile):

code:
public static OffsetDateTime dateParse(String dateString) {
    return OffsetDateTime.parse(dateString, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}
And as mentioned above, don't use Date. Use OffsetDateTime or Instant.

geeves
Sep 16, 2004

venutolo posted:

You want something like this (fix any typos if it doesn't compile):

code:
public static OffsetDateTime dateParse(String dateString) {
    return OffsetDateTime.parse(dateString, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}
And as mentioned above, don't use Date. Use OffsetDateTime or Instant.

Thanks! That helps a lot! My only problem is that BoundStatement for Cassandra still relies on the java Date object. Typical.

venutolo
Jun 4, 2003

Dinosaur Gum

geeves posted:

Thanks! That helps a lot! My only problem is that BoundStatement for Cassandra still relies on the java Date object. Typical.

I'd still suggest using the Java 8 date/time classes up until the point you need to convert to Date. So I'd be parsing the date String to an OffsetDateTime (or Instant), using that OffsetDateTime in whatever logic/classes you have, and then converting to a Date only when you need to call the BoundStatement method that uses Date.

code:
boundStatement.setDate("someVariable", Date.from(offsetDateTime.toInstant()));

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

I've people in here talking about RxJava, right? Anyone know what's going on with this?



That's a bunch of Observables - C and E are using CombineLatest, and running a function whenever one of their inputs emits a new value.The idea is they're meant to cache all the other values they've received, so if B emits a new value then C runs functionC once and emits a new value. E gets onNext events from C and B, but it should be remembering the last value the other emitted when it runs functionE each time

Instead I'm getting this stuff
pre:
Frodo => [@Observable#getB -> onNext() -> [F@f765c34]
running functionC
Frodo => [@Observable#getB -> onNext() -> [F@f765c34]
running functionC
running functionE
I have a longer chain than this, but the same thing is happening at each step - instead of calculating values once and propagating them down, it's like the entire thing is being re-run from the beginning for each observable in the chain. Am I missing something about how this is meant to work?

Code is basically this, obsB is a BehaviourSubject (and this is on Android so I'm using RetroLambda, if that matters)

Java code:
Observable<float[]> obsC = Observable.combineLatest(
                obsA,
                obsB,
                this::functionC
        ).distinctUntilChanged();

        Observable<float[]> obsE = Observable.combineLatest(
                obsC,
                obsB,
                obsD,
                this::functionE
        ).distinctUntilChanged();
(and I know B can update E before C does, which is another issue, I'm more worried about the lack of result caching in the CombineLatests and rerunning their functions)

Sedro
Dec 31, 2008

baka kaba posted:

I've people in here talking about RxJava, right? Anyone know what's going on with this?


I've done bit of Rx in .NET and scala, so I'll try to answer. (code is in scala)

CombineLatest recomputes when a new value arrives from any of its inputs:

code:
val a = Observable.just(0)
val b = BehaviorSubject(defaultValue = 0)
val c = Observable.combineLatest(Iterable(a, b)) { xs => print("C"); xs }
val d = Observable.just(0)
val e = Observable.combineLatest(Iterable(c, b, d)) { xs => print("E"); xs }

e.subscribe()

b.onNext(0) // CEE
b.onNext(0) // CEE
b.onNext(1) // CEE
When you emit the next element for B:
- C recomputes (because it is subscribed to B)
- E recomputes (because it is subscribed to B)

When C emits its next element:
- E recomputes (because it is subscribed to C)

Therefore C recomputes once and E recomputes twice.

---

You put a DistinctUntilChanged after C which introduces some caching. Whenever C emits the same element again, the DistinctUntilChanged node will swallow the onNext event:

code:
val a = Observable.just(0)
val b = BehaviorSubject(defaultValue = 0)
val c = Observable.combineLatest(Iterable(a, b)) { xs => print("C"); xs }.distinctUntilChanged
val d = Observable.just(0)
val e = Observable.combineLatest(Iterable(c, b, d)) { xs => print("E"); xs }

e.subscribe()

b.onNext(0) // CE
b.onNext(0) // CE
b.onNext(1) // CEE
Now, when you emit the next element for B:
- C recomputes (because it is subscribed to B)
- E recomputes (because it is subscribed to B)

When C emits its next element:
- if it was the same value as last time, it get swallowed by the DistinctUntilChanged node
- otherwise, E recomputes (because it is subscribed to C)

Therefore C recomputes once and E recomputes at least once.

---

You actually want to introduce your caching closer to the source (right after B):

code:
val subj = BehaviorSubject(defaultValue = 0)

val a = Observable.just(0)
val b = subj.distinctUntilChanged
val c = Observable.combineLatest(Iterable(a, b)) { xs => print("C"); xs }
val d = Observable.just(0)
val e = Observable.combineLatest(Iterable(c, b, d)) { xs => print("E"); xs }

e.subscribe()

subj.onNext(0)
subj.onNext(0)
subj.onNext(1) // CEE
Now, nothing recomputes when B emits the same value. When B emits a different value, it works like my first example.

Sedro fucked around with this message at 22:43 on Oct 19, 2016

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Hey thanks for the reply! I was thinking that might be a lonely post

Sedro posted:


CombineLatest recomputes when a new value arrives from any of its inputs:

code:
val a = Observable.just(0)
val b = BehaviorSubject(defaultValue = 0)
val c = Observable.combineLatest(Iterable(a, b)) { xs => print("C"); xs }
val d = Observable.just(0)
val e = Observable.combineLatest(Iterable(c, b, d)) { xs => print("E"); xs }

e.subscribe()

b.onNext(0) // CEE
b.onNext(0) // CEE
b.onNext(1) // CEE
When you emit the next element for B:
- C recomputes (because it is subscribed to B)
- E recomputes (because it is subscribed to B)

When C emits its next element:
- E recomputes (because it is subscribed to C)

Therefore C recomputes once and E recomputes twice.

(Ignoring the distinct stuff for now)

See this is what I'd expect to happen, E recalculating twice because its subscribed observables both emit separately. But the results I'm getting have C calculating twice - once when B emits, and then again when E is computing. It happens if A emits once too, like this
pre:
A.onNext() <- this is from the logger, I'm only actually calling onNext() on the Subject once
functionC()
A.onNext()
functionC()
functionE()
It looks almost like for each level, it walks right back to the beginning and repeats each prior step, doing all the work again. (I have a longer chain, it does the same thing in this 1, 12, 123 way)

Is there something weird I'm missing, like I'm accidentally creating multiple subscriptions that run separately? I mean I'm just chaining Observables into CombineLatest and then subscribing once at the end, but this is really weird behaviour. I tried stepping through the source with a debugger but understanding what's going on in there looks like a serious time investment, I just want to try a few things out

This stuff I just wrote works fine though
Java code:
    public void wow() {

        BehaviorSubject<String> a = BehaviorSubject.create("A");
        BehaviorSubject<String> b = BehaviorSubject.create("B");
        Observable<String> d = BehaviorSubject.create("D");

        Observable<String> c = Observable
                .combineLatest(a, b, (x, y) -> x + y)
                .doOnNext(System.out::println);

        Observable<String> e = Observable
                .combineLatest(c, b, d, (x, y, z) -> x + y + z)
                .doOnNext(System.out::println);

        e.subscribe();
        a.onNext("X");
        b.onNext("Q");
    }

AB
ABBD
XB
XBBD
XQ
XQBD
XQQD
Really not sure where I'm going wrong or what would even cause that repeating combining function behaviour :/

Squashy Nipples
Aug 18, 2007

I'm still practicing by working my way through some games of chance. Right now I'm working on Poker Dice.

I'm having an issue with scoring the hands. (yes, I know that scoring actual Poker hands is a big and well discussed topic, but Poker Dice is much simpler game)

A hand is represented by:
Type of Hand (5 of a kind, Full house, One Pair, etc...)
Rank of Hand (which one do you have five of?)
Kickers (remaining cards, if any, used to break ties)

The second two are of variable length, so my first thought was, an Array of Arrays ( handScore[][] ).
Array 1: 1 item, contains PDiceHand Enum type (FIVEK, FULL, ONEPAIR)
Array 2: 1-2 items, contains Integers with the rank(s) of the hand ( two items for Full House and Two Pair, one for all else)
Array 3: 0-4 items, contains Integers with the rank(s) of the unused, kicker dice

The half-baked thought I just had was, if I'm trying to be OOP, shouldn't this just be a class that has various properties/fields?
I guess you would pass a Hand Object to the constructor, which would calculate what the hand is.
And then I could use the class methods to compare relative strength of hands, too.

Any advice?

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

Squashy Nipples posted:

I'm still practicing by working my way through some games of chance. Right now I'm working on Poker Dice.

I'm having an issue with scoring the hands. (yes, I know that scoring actual Poker hands is a big and well discussed topic, but Poker Dice is much simpler game)

A hand is represented by:
Type of Hand (5 of a kind, Full house, One Pair, etc...)
Rank of Hand (which one do you have five of?)
Kickers (remaining cards, if any, used to break ties)

The second two are of variable length, so my first thought was, an Array of Arrays ( handScore[][] ).
Array 1: 1 item, contains PDiceHand Enum type (FIVEK, FULL, ONEPAIR)
Array 2: 1-2 items, contains Integers with the rank(s) of the hand ( two items for Full House and Two Pair, one for all else)
Array 3: 0-4 items, contains Integers with the rank(s) of the unused, kicker dice

The half-baked thought I just had was, if I'm trying to be OOP, shouldn't this just be a class that has various properties/fields?
I guess you would pass a Hand Object to the constructor, which would calculate what the hand is.
And then I could use the class methods to compare relative strength of hands, too.

Any advice?

I'd say, rather than storing those values in a new class, it sounds pretty straighforward to calculate and store them in Hand. You could have Hand implement Comparable<Hand>, and provide a int compareTo(Hand other) that would return whether the other hand was higher, the same, or lower than your hand. (see: https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html#compareTo-T-)

Hand could then calculate the Type, Rank, and Kickers when it's given its dice, and store them in separate properties. It could have accessors to get each one, and your compareTo() method could use those to do its work. You might also consider not storing the score at all, and just calculating the requisite value on the spot when needed. EG: getType() wouldn't return a stored value, it'd look at your array of actual dice to figure out what the highest ranking type is, and return that, and so on.

Your compareTo() would first compare Types, and if one's a clear winner, return right there. Otherwise, compare ranks, and then kickers if you need to.

I assume your instances of Hand can't be changed once they are constructed. If they are, you'd have to recalculate those fields whenever you change what a Hand contains, or (if it doesn't upend your whole design so far) I'd recommend making it so they can't change after construction, and just getting a new Hand every time you need to change. Immutable objects are usually safer. :)

carry on then fucked around with this message at 17:37 on Oct 21, 2016

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

Squashy Nipples posted:

The second two are of variable length, so my first thought was, an Array of Arrays ( handScore[][] ).
Array 1: 1 item, contains PDiceHand Enum type (FIVEK, FULL, ONEPAIR)
Array 2: 1-2 items, contains Integers with the rank(s) of the hand ( two items for Full House and Two Pair, one for all else)
Array 3: 0-4 items, contains Integers with the rank(s) of the unused, kicker dice

The half-baked thought I just had was, if I'm trying to be OOP, shouldn't this just be a class that has various properties/fields?
I guess you would pass a Hand Object to the constructor, which would calculate what the hand is.
And then I could use the class methods to compare relative strength of hands, too.

Any advice?

Yeah dont' make this an array of arrays. If you know you're only going to have 1 element in one of the arrays always... that shouldn't be an array. It should definitely be a class field instead.

So PDiceHand Enum should just be a field on the Hand class.

The way I'd do it is something like

Hand implements Comparable

List<die> dice;
List<die> usedDice;
List<die> kickerDice;
PDiceHand majorValue;

public void setDice();

public void compareTo(Comparable other){
if(! other instanceof Hand){
return false;
}
else{
//compare majorValue, if tied compare usedDice or kickerDice
}
}

when you set the dice, it automatically pulls the best hand and puts that in usedDice. The rest get put into kickerDice. (dice still contains both) and the majorValue gets automatically assinged based on which hand was found. Then when doing comparisons you can use majorValue or usedDice or kickerDice without having to recalculate anything or ever look at dice, although you still have the full dice list if you need it.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

If you don't expect the scoring system or number of dice to change, you could keep it simple and just go
Java code:
List<Die> dice; // if you care about storing them
PDiceHand score;
int primaryRank;
Optional<Integer> secondaryRank;
List<Integer> kickers;
Then in your compareTo method, you can just compare on score > primaryRank > secondaryRank if there is one > kickers, moving down the line whenever a comparison is equal.

It's less flexible and harder to extend, but sometimes that's fine when the problem is pretty much fixed, so don't be afraid to write only what you need if it doesn't make more work for you. A lot of the time it can be clearer about the possible states your object can be in

Also as someone who used to use arrays all the time - stop using arrays! They have their place, but they definitely shouldn't be your go-to way of structuring data. If you want to think OO style, use all the nice language tools like Lists and Optionals that let you easily work with and transform data, and then you'll start to think the same way when you come to design and compose your own functions and classes

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

So to summarize:

Don't use another class, use your Hand class
Use compareTo()
Don't use properties that have specific meaning and whose lengths can change as you need them to

godspeed goon

Squashy Nipples
Aug 18, 2007

All good advice, thank you!

Looks like I've got some stuff to learn... I've never used List<> or compareTo()


carry on then posted:

Don't use another class, use your Hand class

That's part of the issue, I don't have a Hand class at the moment.

Class Die, which represents individual 6-sided dies.
public int rollDie(){
public void rollDieBlind(){

Class DiceCup, which contains anywhere from 2-10 Dice.
public void shakeCup(){

These are in a separate package, so I can reuse them for other dice games. Anything related to Poker Dice is in a separate package.

In the context of Poker Dice, a "Hand" isn't five cards, it's whatever "score" you get out of the five dice in the cup.
In the main package:
PDiceFaces Enum, which translates the pips on the dice into poker dice faces
PDiceHands Enum, which contains the Hand names and their relative ranks
PokerDice, main code

So, each player has their own cup. They can shake the whole cup, or just reroll individuals.
Right now, I over-rode the toString from the DiceCup class to produce a string representation of the numbers, and I was going to pass that to a method for scoring. Of course, the problem with this is needed a "score" to pass back, and of course, the score is a lot more then just a scalar number.


carry on then posted:

Don't use properties that have specific meaning and whose lengths can change as you need them to

Not sure I understand this... you mean like, don't use Arrays if one of the dimension boundaries is variable?

Adbot
ADBOT LOVES YOU

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

Squashy Nipples posted:

All good advice, thank you!

Looks like I've got some stuff to learn... I've never used List<> or compareTo()

Yeah List is basic Collections and Collections are HUGE to software. Probably THE most use libraries in Java. Learn List. (Mostly ArrayList, since List is an interface) learn HashMap. Those two alone will give you massive performance increases over using arrays, and are much easier to use than arrays.

Its good you understand how arrays work, since behind the scenes ArrayList will be using arrays (hence the name) but you shouldn't actually be using arrays all that often. Lists are usually what you want, or Sets, or Maps, or Trees. But sometimes arrays are the appropriate choice, if you know you only need a certain fixed size amount of things, etc.

No need to reinvent the wheel! Better engineers have already built fantastic containers for you; use them!

https://docs.oracle.com/javase/tutorial/collections/

compareTo is part of the Comparable interface, which allows any other Comparable object to easily be compared to another Comparable. You could implement your own method which does the same, but its good practice to use the existing standard, then your code is more re-usable. Its OOP principles.

Squashy Nipples posted:

That's part of the issue, I don't have a Hand class at the moment.

Class Die, which represents individual 6-sided dies.
public int rollDie(){
public void rollDieBlind(){

Class DiceCup, which contains anywhere from 2-10 Dice.
public void shakeCup(){

These are in a separate package, so I can reuse them for other dice games. Anything related to Poker Dice is in a separate package.

In the context of Poker Dice, a "Hand" isn't five cards, it's whatever "score" you get out of the five dice in the cup.
In the main package:
PDiceFaces Enum, which translates the pips on the dice into poker dice faces
PDiceHands Enum, which contains the Hand names and their relative ranks
PokerDice, main code

So, each player has their own cup. They can shake the whole cup, or just reroll individuals.
Right now, I over-rode the toString from the DiceCup class to produce a string representation of the numbers, and I was going to pass that to a method for scoring. Of course, the problem with this is needed a "score" to pass back, and of course, the score is a lot more then just a scalar number.

Okay, so make a Hand class if you don't have one. You need something to hold the dies, and it may as well also be able to calculate its own value and such.

As for what a hand in poker dice is, that's kinda irrelevant. The point is you need to hold a collection of die results. Although it sounds like that's what DiceCup is? In that case, everything we were saying to put in Hand, you can just put in DiceCup instead. Whatever. Same difference.

If you want to keep the die code clean from poker dice code (not a bad idea) then just make a new Hand class that takes in dice from a dicecup, or holds a dicecup. Either approach works.

Squashy Nipples posted:

Not sure I understand this... you mean like, don't use Arrays if one of the dimension boundaries is variable?

There's two things here.

One is, dont' have an array of arrays if you know you'll need to access different arrays for different purposes. That's a very old-fashioned C approach, although even then it would be kinda not great practice.

No reason to make yourself lookup one of the arrays from the array of arrays when you can just have 3 class variables that are each one of the arrays. Use an array of arrays if you need to store a 2D grid like a checkerboard, not to have multiple arrays for different purposes. Each variable should only serve one purpose.

Plus its confusing to read the code if array[0] is used for one purpose but array[1] is used for another. Better to just give them individual names, so the code is clear. Then instead you're accessing the usedDice[] array, later you use the kickerDice[] array, so the code is obvious what is doing what. (But again, lists are better than arrays for most cases) Reading the code shouldn't be a puzzle, it should be very obvious what does what.

As for the second bit, don't use static arrays when you don't know how many elements will go in the array, its wasteful and having to resize the arrays is a pain. If you learn to use ArrayList instead, it'll re-size itself for you without you having to keep up with its size. Saves you time, cleans up your code, makes it less prone to IndexOutOfBoundException.

Zaphod42 fucked around with this message at 19:38 on Oct 21, 2016

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply