Camicia error output only shows the first line

The problem is here: https://exercism.org/tracks/euphoria/exercises/camicia/edit

a sample error would be:

failed: three cards, one trick, expected: {

Here’s my code:

include std/sequence.e

integer turn = 0, num_tricks = 0, cards_played = 0, cards_left_to_pay = 0, payee = 0
sequence pile = {}, loop_status = "finished", playerA, playerB, prev_hands = {}

procedure play_card(integer p)
  if p = 0 then
    pile = prepend(pile, playerA[1])
    playerA = tail(playerA)
  else
    pile = prepend(pile, playerB[1])
    playerB = tail(playerB)
  end if
  cards_played += 1
end procedure

function get_pay_card()
  return match(pile[1], "JQKA")
end function

function replace_nums(sequence hand)
    for i = 1 to length(hand) do
        if match(hand[i], "JQKA") <= 0 then
            hand[i] = "X"
        end if
    end for
    -- printf(1, "Hand: %s\n", { join(hand) })
    return hand
end function

function add_hands(sequence hands)
    sequence masked_hands = { replace_nums(hands[1]), replace_nums(hands[2]) }
    if set_contains_seqs(prev_hands, masked_hands) then
--      printf(1, "Same hand, needle %s, haystack %s\n\n", { join(playerA), join(apply(player_a_prev_hands, routine_id("join")), ", ") })
      return 0
    else
      prev_hands &= { masked_hands }
      return 1
    end if
end function

function set_contains_seqs(sequence haystack, sequence masked_hands)
--  printf(1, "\nset_contains_seq, needle %s, haystack %s\n\n", { join(needle), join(apply(haystack, routine_id("join")), ", ") })

  for i = 1 to length(haystack) do
--     if equal_ignoring_numbers(haystack[i][1], masked_hands[1]) and equal_ignoring_numbers(haystack[i][2], masked_hands[2]) then
    if equal(haystack[i][1], masked_hands[1]) and equal(haystack[i][2], masked_hands[2]) then
--      printf(1, "\nset_contains_seq indeed, needle %s, haystack %s\n\n", { join(needle), join(apply(haystack, routine_id("join")), ", ") })
      return 1
    end if
  end for
  return 0
end function

/*
function equal_ignoring_numbers(sequence s1, sequence s2)
  if length(s1) != length(s2) then
--    printf(1, "equal_ignoring_numbers diff length, s1 %s, s2 %s\n", { join(s1), join(s2) })
    return 0
  else
    for i = 1 to length(s1) do
      integer i1 = match(s1[i], "JQKA")
      integer i2 = match(s2[i], "JQKA")
      if i1 > 0 and i1 != i2 then
--        printf(1, "equal_ignoring_numbers unequal at %d, s1 %s, s2 %s\n", { i, join(s1), join(s2) })
        return 0
      elsif i2 > 0 and i2 != i1 then
--        printf(1, "equal_ignoring_numbers unequal at %d, s1 %s, s2 %s\n", { i, join(s1), join(s2) })
        return 0
      end if
    end for
--    printf(1, "equal_ignoring_numbers equal, s1 %s, s2 %s\n", { join(s1), join(s2) })
    return 1
  end if
end function
*/

procedure take_pile(integer p)
  if p = 0 then
    playerA = playerA & reverse(pile)
  else
    playerB = playerB & reverse(pile)
  end if
  pile = {}
  num_tricks += 1
  -- printf(1, "new num_tricks %d, cards_played %d.\n", { num_tricks, cards_played })
end procedure

public function simulateGame(sequence _playerA, sequence _playerB)

  playerA = _playerA
  playerB = _playerB

  while 1 do

    -- printf(1, "\nplayer %d to play, pile %s, playerA  %s, playerB  %s\n", { turn, join(pile), join(playerA), join(playerB) })

    if turn = 0 and length(playerA) < 1 then
      -- printf(1, "player 1 out, p 2 takes the pile")
      take_pile(1)
      exit
    elsif turn = 1 and length(playerB) < 1 then
      -- printf(1, "player 2 out, p 1 takes the pile")
      take_pile(0)
      exit
    else
      if not(add_hands({ playerA, playerB })) then
        loop_status = "loop"
        goto "player_out"
      end if

      play_card(turn)
    end if

    -- printf(1, "player %d played, pile %s, playerA  %s, playerB  %s\n", { turn, join(pile), join(playerA), join(playerB) })

    cards_left_to_pay = get_pay_card()
    if cards_left_to_pay < 1 then
        turn = 1 - turn
    else
        payee = 1 - turn
        while cards_left_to_pay > 0 do

          if payee = 0 then
            if length(playerA) < 1 then
              take_pile(1)
              -- printf(1, "player 0 out\n")
              goto "player_out"
            end if
          else
            if length(playerB) < 1 then
              take_pile(0)
              -- printf(1, "player 1 out\n")
              goto "player_out"
            end if
          end if
          play_card(payee)
          -- printf(1, "player %d fined, pile %s, playerA  %s, playerB  %s\n", { payee, join(pile), join(playerA), join(playerB) })
          integer current_top_card = get_pay_card()
          if current_top_card > 0 then
            payee = 1 - payee
            cards_left_to_pay = current_top_card
            -- printf(1, "new payment card, cards left %d, new payee %d\n", { cards_left_to_pay, payee })
          else
            cards_left_to_pay -= 1
          end if

        end while
        -- payee is done paying, turn is other player, other player gets the pile
        turn = 1 - payee

        -- printf(1, "end of round, taking pile.\n")
        take_pile(turn)
        if length(playerB) < 1 or length(playerA) < 1 then
            -- printf(1, "other player out\n")
            goto "player_out"
        end if
    end if

  end while

  label "player_out"

  printf(1, "Done. turn %d, pile %s, playerA %s, playerA replaced %s, playerB %s, loop_status %s, cards_played %d, num_tricks %d\n", 
    { turn, join(pile), join(playerA), join(replace_nums(playerA)), join(playerB), loop_status, cards_played, num_tricks })

  return { {"status", loop_status}, {"cards", cards_played}, {"tricks", num_tricks} }

end function

1 Like

The unmatched squiggly bracket was suspicious so I checked Secret Handshake which also expects a sequence. There I got a similar message failed: jump for 1000, expected: {.

Locally, Euphoria expands a sequence across multiple lines when returning the results of a failed test:

failed: three cards, one trick, expected: {
  ... multiple lines clipped ...
} but got: {
  ... multiple lines clipped ...
}

The potential defect in reporting a full failure message is presumably here: euphoria-test-runner/bin/run.ex at ddb8cec4201c0d663f7759a85599713f5b970cca · exercism/euphoria-test-runner · GitHub. The test runner only reports the first line of the failure message. That seems to work fine for atoms being compared so this issue is specifically related to sequences.

I think instead of returning the first line after encountering the first failure, we need to catch successive lines until we reach the next passing or failing test and return all the caught text. That should work for both single-line and multiple-line failures if the track maintainers are interested.

Edit — PR is merged. I tried a broken solution for Camicia and got the full failure message returned (see below) so I think the issue is fixed.

failed: simple loop with decks of 3 cards, expected: {
  {
    "status",
    "loop"
  },
  {
    "cards",
    8
  },
  {
    "tricks",
    3
  }
} but got: {
  {
    "status",
    "finished"
  },
  {
    "cards",
    5
  },
  {
    "tricks",
    1
  }
}