Time for an 2014 update…

This commit is contained in:
Ingy döt Net 2014-01-17 05:32:22 +00:00
parent 372c577f83
commit 09687c4926
2520 changed files with 34227 additions and 7318 deletions

View file

@ -0,0 +1,83 @@
-module( set ).
-export( [deck/0, is_set/3, shuffle_deck/1, task/0] ).
-record( card, {number, symbol, shading, colour} ).
deck() -> [#card{number=N, symbol=Sy, shading=Sh, colour=C} || N <- [1,2,3], Sy <- [diamond, squiggle, oval], Sh <- [solid, striped, open], C <- [red, green, purple]].
is_set( Card1, Card2, Card3 ) ->
is_colour_correct( Card1, Card2, Card3 )
andalso is_number_correct( Card1, Card2, Card3 )
andalso is_shading_correct( Card1, Card2, Card3 )
andalso is_symbol_correct( Card1, Card2, Card3 ).
shuffle_deck( Deck ) -> knuth_shuffle:list( Deck ).
task() ->
basic(),
advanced().
advanced() -> common( 6, 12 ).
basic() -> common( 4, 9 ).
common( X, Y ) ->
{Sets, Cards} = find_x_sets_in_y_cards( X, Y, deck() ),
io:fwrite( "Cards ~p~n", [Cards] ),
io:fwrite( "Gives sets:~n" ),
[io:fwrite( "~p~n", [S] ) || S <- Sets].
find_x_sets_in_y_cards( X, Y, Deck ) ->
{Cards, _T} = lists:split( Y, shuffle_deck(Deck) ),
find_x_sets_in_y_cards( X, Y, Cards, make_sets1(Cards, []) ).
find_x_sets_in_y_cards( X, _Y, _Deck, Cards, Sets ) when erlang:length(Sets) =:= X -> {Sets, Cards};
find_x_sets_in_y_cards( X, Y, Deck, _Cards, _Sets ) -> find_x_sets_in_y_cards( X, Y, Deck ).
is_colour_correct( Card1, Card2, Card3 ) -> is_colour_different( Card1, Card2, Card3 ) orelse is_colour_same( Card1, Card2, Card3 ).
is_colour_different( #card{colour=C1}, #card{colour=C2}, #card{colour=C3} ) when C1 =/= C2, C1 =/= C3, C2 =/= C3 -> true;
is_colour_different( _Card1, _Card2, _Card3 ) -> false.
is_colour_same( #card{colour=C}, #card{colour=C}, #card{colour=C} ) -> true;
is_colour_same( _Card1, _Card2, _Card3 ) -> false.
is_number_correct( Card1, Card2, Card3 ) -> is_number_different( Card1, Card2, Card3 ) orelse is_number_same( Card1, Card2, Card3 ).
is_number_different( #card{number=N1}, #card{number=N2}, #card{number=N3} ) when N1 =/= N2, N1 =/= N3, N2 =/= N3 -> true;
is_number_different( _Card1, _Card2, _Card3 ) -> false.
is_number_same( #card{number=N}, #card{number=N}, #card{number=N} ) -> true;
is_number_same( _Card1, _Card2, _Card3 ) -> false.
is_shading_correct( Card1, Card2, Card3 ) -> is_shading_different( Card1, Card2, Card3 ) orelse is_shading_same( Card1, Card2, Card3 ).
is_shading_different( #card{shading=S1}, #card{shading=S2}, #card{shading=S3} ) when S1 =/= S2, S1 =/= S3, S2 =/= S3 -> true;
is_shading_different( _Card1, _Card2, _Card3 ) -> false.
is_shading_same( #card{shading=S}, #card{shading=S}, #card{shading=S} ) -> true;
is_shading_same( _Card1, _Card2, _Card3 ) -> false.
is_symbol_correct( Card1, Card2, Card3 ) -> is_symbol_different( Card1, Card2, Card3 ) orelse is_symbol_same( Card1, Card2, Card3 ).
is_symbol_different( #card{symbol=S1}, #card{symbol=S2}, #card{symbol=S3} ) when S1 =/= S2, S1 =/= S3, S2 =/= S3 -> true;
is_symbol_different( _Card1, _Card2, _Card3 ) -> false.
is_symbol_same( #card{symbol=S}, #card{symbol=S}, #card{symbol=S} ) -> true;
is_symbol_same( _Card1, _Card2, _Card3 ) -> false.
%% Nested loops 1, 2 and 3
make_sets1( [_Second_to_last, _Last], Sets ) -> Sets;
make_sets1( [Card | T], Sets ) -> make_sets1( T, make_sets2(Card, T, Sets) ).
make_sets2( _Card, [_Last], Sets ) -> Sets;
make_sets2( Card1, [Card2 | T], Sets ) -> make_sets2( Card1, T, make_sets3( Card1, Card2, T, Sets) ).
make_sets3( _Card1, _Card2, [], Sets ) -> Sets;
make_sets3( Card1, Card2, [Card3 | T], Sets ) ->
make_sets3( Card1, Card2, T, make_sets_acc(is_set(Card1, Card2, Card3), {Card1, Card2, Card3}, Sets) ).
make_sets_acc( true, Set, Sets ) -> [Set | Sets];
make_sets_acc( false, _Set, Sets ) -> Sets.

View file

@ -0,0 +1,85 @@
package main
import (
"fmt"
"math/rand"
"time"
)
var (
number = []string{"1", "2", "3"}
color = []string{"red", "green", "purple"}
shade = []string{"solid", "open", "striped"}
shape = []string{"oval", "squiggle", "diamond"}
)
type card int
func (c card) String() string {
return fmt.Sprintf("%s %s %s %s",
number[c/27],
color[c/9%3],
shade[c/3%3],
shape[c%3])
}
func main() {
rand.Seed(time.Now().Unix())
basic()
advanced()
}
func basic() {
game("Basic", 9, 4)
}
func advanced() {
game("Advanced", 12, 6)
}
func game(level string, cards, sets int) {
// create deck
d := make([]card, 81)
for i := range d {
d[i] = card(i)
}
var found [][3]card
for len(found) != sets {
found = found[:0]
// deal
for i := 0; i < cards; i++ {
j := rand.Intn(81 - i)
d[i], d[j] = d[j], d[i]
}
// consider all triplets
for i := 2; i < cards; i++ {
c1 := d[i]
for j := 1; j < i; j++ {
c2 := d[j]
l3:
for _, c3 := range d[:j] {
for f := card(1); f < 81; f *= 3 {
if (c1/f%3+c2/f%3+c3/f%3)%3 != 0 {
continue l3 // not a set
}
}
// it's a set
found = append(found, [3]card{c1, c2, c3})
}
}
}
}
// found the right number
fmt.Printf("%s game. %d cards, %d sets.\n", level, cards, sets)
fmt.Println("Cards:")
for _, c := range d[:cards] {
fmt.Println(" ", c)
}
fmt.Println("Sets:")
for _, s := range found {
fmt.Println(" ", s[0])
fmt.Println(" ", s[1])
fmt.Println(" ", s[2])
fmt.Println()
}
}

View file

@ -18,7 +18,7 @@ set_puzzle=: verb define
Hand=. y drawRandom Deck
end.
echo 'Dealt ',(": y),' Cards:'
echo sayCards Hand
echo 'Found ',(":target),' Sets:'
echo sayCards getSets Hand
echo sayCards sort Hand
echo LF,'Found ',(":target),' Sets:'
echo sayCards sort"2 getSets Hand
)

View file

@ -1,27 +1,28 @@
set_puzzle 9
Dealt 9 Cards:
one, red, solid, oval
one, green, open, squiggle
two, purple, striped, squiggle
three, red, solid, squiggle
three, red, open, oval
three, green, solid, oval
three, green, open, diamond
three, purple, open, oval
three, green, open, diamond
three, red, solid, squiggle
three, green, solid, oval
three, purple, striped, oval
three, red, open, oval
one, red, solid, oval
one, green, open, squiggle
two, purple, striped, squiggle
Found 4 Sets:
three, green, open, diamond
three, red, solid, squiggle
three, green, open, diamond
three, purple, striped, oval
three, green, open, diamond
one, red, solid, oval
two, purple, striped, squiggle
three, green, open, diamond
three, red, solid, squiggle
one, green, open, squiggle
two, purple, striped, squiggle
three, red, solid, squiggle
three, red, open, oval
three, green, solid, oval
three, purple, striped, oval
three, red, open, oval

View file

@ -0,0 +1,79 @@
#!perl
use strict;
use warnings;
# This code was adapted from the perl6 solution for this task.
# Each element of the deck is an integer, which, when written
# in octal, has four digits, which are all either 1, 2, or 4.
my $fmt = '%4o';
my @deck = grep sprintf($fmt, $_) !~ tr/124//c, 01111 .. 04444;
# Given a feature digit (1, 2, or 4), produce the feature's name.
# Note that digits 0 and 3 are unused.
my @features = map [split ' '], split /\n/,<<'';
! red green ! purple
! one two ! three
! oval squiggle ! diamond
! solid open ! striped
81 == @deck or die "There are ".@deck." cards (should be 81)";
# By default, draw 9 cards, but if the user
# supplied a parameter, use that.
my $draw = shift(@ARGV) || 9;
my $goal = int($draw/2);
# Get the possible combinations of 3 indices into $draw elements.
my @combinations = combine(3, 0 .. $draw-1);
my @sets;
do {
# Shuffle the first $draw elements of @deck.
for my $i ( 0 .. $draw-1 ) {
my $j = $i + int rand(@deck - $i);
@deck[$i, $j] = @deck[$j, $i];
}
# Find all valid sets using the shuffled elements.
@sets = grep {
my $or = 0;
$or |= $_ for @deck[@$_];
# If all colors (or whatever) are the same, then
# a 1, 2, or 4 will result when we OR them together.
# If they're all different, then a 7 will result.
# If any other digit occurs, the set is invalid.
sprintf($fmt, $or) !~ tr/1247//c;
} @combinations;
# Continue until there are exactly $goal valid sets.
} until @sets == $goal;
print "Drew $draw cards:\n";
for my $i ( 0 .. $#sets ) {
print "Set ", $i+1, ":\n";
my @cards = @deck[ @{$sets[$i]} ];
for my $card ( @cards ) {
my @octal = split //, sprintf '%4o', $card;
my @f = map $features[$_][$octal[$_]], 0 .. 3;
printf " %-6s %-5s %-8s %s\n", @f;
}
}
exit;
# This function is adapted from the perl5i solution for the
# RosettaCode Combinations task.
sub combine {
my $n = shift;
return unless @_;
return map [$_], @_ if $n == 1;
my $head = shift;
my @result = combine( $n-1, @_ );
unshift @$_, $head for @result;
@result, combine( $n, @_ );
}
__END__

View file

@ -2,13 +2,7 @@ COLORS = %i(red green purple) #use [:red, :green, :purple] in Ruby < 2.0
SYMBOLS = %i(oval squiggle diamond)
NUMBERS = %i(one two three)
SHADINGS = %i(solid open striped)
FEATURES = [COLORS, SYMBOLS, NUMBERS, SHADINGS]
@hand_size = 9
@num_sets_goal = 4
#create an enumerator which deals all combinations of @hand_size cards
@dealer = FEATURES[0].product(*FEATURES[1..-1]).shuffle.combination(@hand_size)
DECK = COLORS.product(SYMBOLS, NUMBERS, SHADINGS)
def get_all_sets(hand)
hand.combination(3).select do |candidate|
@ -17,22 +11,26 @@ def get_all_sets(hand)
end
end
def get_puzzle_and_answer
sets = []
until sets.size == @num_sets_goal do
hand = @dealer.next
def get_puzzle_and_answer(hand_size, num_sets_goal)
begin
hand = DECK.sample(hand_size)
sets = get_all_sets(hand)
end
end until sets.size == num_sets_goal
[hand, sets]
end
def print_cards(cards)
cards.each{|card| puts card.join(", ")}
puts cards.map{|card| " %-8s" * 4 % card}
puts
end
puzzle, sets = get_puzzle_and_answer
puts "Dealt #{puzzle.size} cards:"
print_cards(puzzle)
puts "Containing #{sets.size} sets:"
sets.each{|set| print_cards(set)}
def set_puzzle(deal, goal=deal/2)
puzzle, sets = get_puzzle_and_answer(deal, goal)
puts "Dealt #{puzzle.size} cards:"
print_cards(puzzle)
puts "Containing #{sets.size} sets:"
sets.each{|set| print_cards(set)}
end
set_puzzle(9)
set_puzzle(12)