Package jc.pbntools.download

Source Code of jc.pbntools.download.LinReader

/* *****************************************************************************

    jedit options: :folding=explicit:tabSize=2:noTabs=true:
   
    Copyright (C) 2011 Jaroslaw Czekalski - jarekczek@poczta.onet.pl

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   *****************************************************************************
*/

package jc.pbntools.download;

import java.io.FileWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import jc.f;
import jc.JCException;
import jc.outputwindow.SimplePrinter;
import jc.pbntools.Card;
import jc.pbntools.Deal;
import jc.pbntools.PbnTools;
import jc.SoupProxy;

/**
<h1>Lin specification</h1>

<dl>
<dt>ah - deal label</dt>
<dt>an - bid explanation (for the previous bid)
<dt>mb - a bid</dt>
<dt>mc - claim, number of tricks
<dt>md - dealer and hands
  <ul>
  <li>First goes a digit denoting the dealer 1 for S, 2 = W, 3 = N, 4 = S
  <li>Right after the dealer digit come dealers cards,
      color and cards</li>
  <li>Commas separate cards of consecutive players, only 3 hands are given
      </li>
  </ul>
  For example:
  <code>3S8QKHJD8TJKC2349J,S23459TAH368DC68K,S67JH45QKD357QC7A,</code>
</dt>
<dt>pc - play card</dt>
<dt>pg - pause game. This is done in lin files downloaded directly,
      after bidding and every 4 cards</dt>
<dt>pn - player names, comma separated</dt>
<dt>rh - ? (seen empty)</dt>
<dt>st - ? (seen empty)</dt>
<dt>sv - vulnerability, o = None, b = Both, n = NS, e = EW
    (<code>o</code> also found to denote None)</dt>
<dt></dt>
<dt></dt>
<dt></dt>
<dt></dt>
</dl>

*/

public class LinReader implements DealReader
{
  protected Document m_doc;
  protected SimplePrinter m_sp;
  protected boolean m_bSilent = true;
  protected int m_nCurCard = 0; // for gathering game play
 
  /** readNumber method {{{
   * Reads deal number from <code>Board xx</code> text.
   */
  private void readNumber(Deal deal, String sBoard)
    throws DownloadFailedException
  {
    sBoard = sBoard.replaceFirst("^.*?([0-9]+).*$", "$1");
    try {
      deal.setNumber(Integer.valueOf(sBoard));
    } catch (NumberFormatException nfe) {}
  } //}}}

  private void readPlayers(Deal deal, String sPlayers) //{{{
    throws DownloadFailedException
  {
    String asPlayers[] = sPlayers.split(",");
    if (asPlayers.length != 4)
      throw new DownloadFailedException(
        PbnTools.getStr("error.incNumberNames", asPlayers.length, sPlayers),
        m_sp, !m_bSilent);
     
    // what is described as GIB in bbo viewer, inside the file is coded
    // somehow
    for (int i=0; i<asPlayers.length; i++) {
      if (asPlayers[i].equals("~~M59370"))
        asPlayers[i] = "GiB";
    }
   
    deal.setIdentField("South",asPlayers[0]);
    deal.setIdentField("West",asPlayers[1]);
    deal.setIdentField("North",asPlayers[2]);
    deal.setIdentField("East",asPlayers[3]);
  } //}}}

  private void readVulner(Deal deal, String sLinVulner) //{{{
    throws DownloadFailedException
  {
    Map<String, String> msVul = new HashMap<String, String>();
    msVul.put("o", "None");
    msVul.put("b", "All");
    msVul.put("n", "NS");
    msVul.put("e", "EW");
    String sVulner = msVul.get(sLinVulner);
    if (sVulner == null) {
      throw new DownloadFailedException(
        PbnTools.getStr("error.linUnrecognVulner", sLinVulner),
        m_sp, !m_bSilent);
    }
    deal.setVulner(sVulner);
  } //}}}

  // setCards method {{{
  /**
   * Sets cards of given color and given person.
   * @param sArg Whole argument being processed, to show in error message
   */
  private void setCards(Deal deal, int nPerson, int nColor,
    String sCards, String sArg)
    throws DownloadFailedException
  {
    for (int i=0; i < sCards.length(); i++) {
      char chCard = sCards.charAt(i);
      Card card = new Card();
      card.setColor(nColor);
      card.setRankCh(chCard);
      if (card.getRank() == 0)
        throw new DownloadFailedException(
          PbnTools.getStr("error.linUnrecognCard", chCard, sArg),
          m_sp, !m_bSilent);
      deal.setCard(card, nPerson);
    }
  } //}}}

  private void readHands(Deal deal, String sArg) //{{{
    throws DownloadFailedException
  {
    if (sArg.length() < 2)
      throw new DownloadFailedException(
        PbnTools.getStr("error.linCmdShort", "md", sArg),
        m_sp, !m_bSilent);
    String sLinDealer = sArg.substring(0, 1);
    deal.setDealer(getPerson(sLinDealer));
   
    String sHands = sArg.substring(1);
    String asHand[] = sHands.split(",");
    if (asHand.length != 3 && asHand.length != 4)
      throw new DownloadFailedException(
        PbnTools.getStr("error.linHandCount", "3/4", asHand.length, sArg),
        m_sp, !m_bSilent);
    int nPerson = Deal.person('S');
    for (String sHand: asHand) {
      Matcher m = Pattern.compile("^S(.*)H(.*)D(.*)C(.*)$").matcher(sHand);
      if (!m.matches())
        throw new DownloadFailedException(
          PbnTools.getStr("error.linUnrecognCards", Deal.personChar(nPerson),
            "S...H...D...C...", sHand), m_sp, !m_bSilent);
      setCards(deal, nPerson, Card.SPADE, m.group(1), sArg);
      setCards(deal, nPerson, Card.HEART, m.group(2), sArg);
      setCards(deal, nPerson, Card.DIAMOND, m.group(3), sArg);
      setCards(deal, nPerson, Card.CLUB, m.group(4), sArg);
      nPerson = Deal.nextPerson(nPerson);
    }
    deal.dealRemCards();
    deal.fillHands();
  } //}}}

  private void readBid(Deal d, String sArg) //{{{
    throws DownloadFailedException
  {
    sArg = sArg.replaceFirst("!$", "");
    sArg = sArg.replaceFirst("N$", "NT");
    Map<String, String> m = new HashMap<String, String>();
    m.put("p", "Pass");
    m.put("d", "X");
    m.put("d!", "X");
    m.put("r", "XX");
    if (m.containsKey(sArg)) {
      d.addBid(m.get(sArg));
    } else {
      d.addBid(sArg);
    }
  } //}}}

  // readPlay method {{{
  /** Reads played card. */
  private void readPlay(Deal d, String sArg)
    throws DownloadFailedException
  {
    if (sArg.length() != 2)
      throw new DownloadFailedException(
        PbnTools.getStr("error.pbn.wrongCard", sArg));
    Card c = new Card(Card.color(sArg.charAt(0)), Card.rank(sArg.charAt(1)));
    if (!c.isOk())
      throw new DownloadFailedException(
        PbnTools.getStr("error.pbn.wrongCard", sArg));

    m_nCurCard += 1;
    int nHolder = d.getCardHolder(c);
    if (nHolder >= 0)
      d.addPlay((m_nCurCard - 1) / 4 + 1, nHolder, c);
  } //}}}

  // getPerson {{{
  /**
   * Gets a person (from {@link Deal} class, reading from lin char.
   * @param sPerson A string, of which first character denotes person.
   */
  public int getPerson(String sPerson)
    throws DownloadFailedException
  {
    char ch = sPerson.charAt(0);
    switch (ch) {
      case '1': return Deal.S;
      case '2': return Deal.W;
      case '3': return Deal.N;
      case '4': return Deal.E;
      default: throw new DownloadFailedException(
        PbnTools.getStr("error.invalidPerson", sPerson), m_sp, !m_bSilent);
    }
  } //}}}

  // readLin method {{{
  /**
   * Reads deals from a lin contents.
   * @param sLin Lin contents
   */
  public Deal[] readLin(String sLin, boolean bSilent)
    throws DownloadFailedException
  {
    // m_sp.addLine(sLin);
    m_bSilent = bSilent;
    m_nCurCard = 0;
    Deal d = new Deal();
    String sLastComm = "";
    Scanner sc = new Scanner(sLin).useDelimiter("\\|");
    while (sc.hasNext()) {
      String sComm = sc.next();
      if (sComm.length() == 0) {
       throw new DownloadFailedException(
         PbnTools.getStr("lin.error.emptyCmd", sc.match().start()),
           m_sp, !m_bSilent);
      }
      if (!sc.hasNext()) {
       throw new DownloadFailedException(
         PbnTools.getStr("lin.error.noArg", sComm), m_sp, !m_bSilent);
      }
      String sArg = sc.next();
      if (sComm.equals("ah"))
        readNumber(d, sArg);
      else if (sComm.equals("an") && sLastComm.equals("mb")) {
        d.annotateLastBid(sArg);
      } else if (sComm.equals("pc"))
        try {
          readPlay(d, sArg);
        } catch (DownloadFailedException dfe) {
          // ignore played cards errors, as it's not the main functionality
          m_sp.addLine(dfe.getMessage());
        }
      else if (sComm.equals("pg"))
        {} // pause game, ignore it
      else if (sComm.equals("pn"))
        readPlayers(d, sArg);
      else if (sComm.equals("mb"))
        readBid(d, sArg);
      else if (sComm.equals("mc")) {
        try {
          int cTricks = Integer.parseInt(sArg);
          if (cTricks < 0 || cTricks > 13)
            throw new NumberFormatException();
          d.setResult(cTricks);
        } catch (NumberFormatException nfe) {
          m_sp.addLine(PbnTools.getStr("error.linInvArg", sComm, sArg));
        }
      } else if (sComm.equals("md"))
        readHands(d, sArg);
      else if (sComm.equals("rh") || sComm.equals("st")) {
        if (!sArg.isEmpty() && !m_bSilent)
          m_sp.addLine(PbnTools.getStr("msg.interesting", sComm + sArg));
      }
      else if (sComm.equals("sv"))
        readVulner(d, sArg);
      else {
        if (!m_bSilent) {
          m_sp.addLine(PbnTools.getStr("msg.interesting",
            "Command: " + sComm + ", arg: " + sArg));
        }
      }
      sLastComm = sComm;
    }

    // contract must be deduced from auction
    ArrayList<String> asErrors = new ArrayList<String>();
    d.setContractFromAuction(asErrors);
    if (asErrors.size() > 0) {
      m_sp.addLine(PbnTools.getStr("lin.error.noContract"));
      for (String sMsg: asErrors)
        m_sp.addLine("  " + sMsg);
    }

    // passed out - result can be deduced :)
    if (d.getContractHeight() == 0)
      d.setResult(0);
   
    if (d.getResult() < 0 && d.getContractHeight() > 0) {
      // the result must be deduced from plays
      asErrors.clear();
      d.setResultFromPlays(asErrors);
      if (asErrors.size() > 0) {
        m_sp.addLine(PbnTools.getStr("lin.error.noContract"));
        for (String sMsg: asErrors)
          m_sp.addLine("  " + sMsg);
      }
    }
   
    // when no result, don't show the contract either
    if (d.getResult() < 0)
      d.setContractHeight(-1);
   
    return new Deal[] { d };
  } //}}}
 
  public Deal[] readDeals(String sUrl, boolean bSilent) //{{{
    throws DownloadFailedException
  {
    assert(m_doc != null);
    String sLin = m_doc.text();
    Deal[] deals = readLin(sLin, bSilent);
    for (Deal d: deals)
      d.setId(f.getFileName(sUrl));
    return deals;
  } //}}}

  // verify method {{{
  /** Verifies if the <code>sUrl</code> contains valid data in this format */
  public boolean verify(String sUrl, boolean bSilent)
  {
    // We should read lin file directly, but SoupProxy has a cache
    // so it would be more network efficient to use it.
    m_doc = null;
    try {
      SoupProxy proxy = new SoupProxy();
      m_doc = proxy.getDocument(sUrl);
    }
    catch (JCException e) {
      m_sp.addLine(e.getMessage());
      return false;
    }
    String sLin = m_doc.text();
    for (int i=0; i<sLin.length(); i++) {
      char ch = sLin.charAt(i);
      if (ch < 32 || ch > 126) {
        if (!bSilent || f.isDebugMode())
          m_sp.addLine(PbnTools.getStr("msg.unexpChar", ""+ch, i));
        return false;
      }
    }
    if (sLin.indexOf('|') < 0) {
      if (!bSilent || f.isDebugMode())
        m_sp.addLine(PbnTools.getStr("msg.missChar", "|"));
      return false;
    }
   
    String asNeededStrings[] = { "|st|", "|md|" };
    for (String sStr: asNeededStrings) {
      if (sLin.indexOf(sStr) < 0) {
        if (!bSilent || f.isDebugMode())
          m_sp.addLine(PbnTools.getStr("msg.missString", sStr));
        return false;
      }
    }
    return true;
  } //}}}
   
  // setOutputWindow method {{{
  /** Sets the window to which output messages will be directed */
  public void setOutputWindow(SimplePrinter sp)
  {
    m_sp = sp;
  } //}}}
}
TOP

Related Classes of jc.pbntools.download.LinReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.