2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,5 +1,7 @@
{{omit from|GUISS}}
The task is to '''solve Dinesman's multiple dwelling [http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-28.html#%_sec_4.3.2 problem] but in a way that most naturally follows the problem statement given below'''.
;Task
Solve Dinesman's multiple dwelling [http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-28.html#%_sec_4.3.2 problem] but in a way that most naturally follows the problem statement given below.
Solutions are allowed (but not required) to parse and interpret the problem text, but should remain flexible and should state what changes to the problem text are allowed. Flexibility and ease of expression are valued.
@ -7,12 +9,14 @@ Examples may be be split into "setup", "problem statement", and "output" section
Example output should be shown here, as well as any comments on the examples flexibility.
;The problem:
:Baker, Cooper, Fletcher, Miller, and Smith live on different floors of an apartment house that contains only five floors.
:Baker does not live on the top floor.
:Cooper does not live on the bottom floor.
:Fletcher does not live on either the top or the bottom floor.
:Miller lives on a higher floor than does Cooper.
:Smith does not live on a floor adjacent to Fletcher's.
:Fletcher does not live on a floor adjacent to Cooper's.
:''Where does everyone live?''
;The problem
Baker, Cooper, Fletcher, Miller, and Smith live on different floors of an apartment house that contains only five floors.<br>
* Baker does not live on the top floor.
* Cooper does not live on the bottom floor.
* Fletcher does not live on either the top or the bottom floor.
* Miller lives on a higher floor than does Cooper.
* Smith does not live on a floor adjacent to Fletcher's.
* Fletcher does not live on a floor adjacent to Cooper's.<br><br>
''Where does everyone live?''<br>
<br><br>

View file

@ -0,0 +1,70 @@
# attempt to solve the dinesman Multiple Dwelling problem #
# SETUP #
# special floor values #
INT top floor = 4;
INT bottom floor = 0;
# mode to specify the persons floor constraint #
MODE PERSON = STRUCT( STRING name, REF INT floor, PROC( INT )BOOL ok );
# yields TRUE if the floor of the specified person is OK, FALSE otherwise #
OP OK = ( PERSON p )BOOL: ( ok OF p )( floor OF p );
# yields TRUE if floor is adjacent to other persons floor, FALSE otherwise #
PROC adjacent = ( INT floor, other persons floor )BOOL: floor >= ( other persons floor - 1 ) AND floor <= ( other persons floor + 1 );
# displays the floor of an occupant #
PROC print floor = ( PERSON occupant )VOID: print( ( whole( floor OF occupant, -1 ), " ", name OF occupant, newline ) );
# PROBLEM STATEMENT #
# the inhabitants with their floor and constraints #
PERSON baker = ( "Baker", LOC INT := 0, ( INT floor )BOOL: floor /= top floor );
PERSON cooper = ( "Cooper", LOC INT := 0, ( INT floor )BOOL: floor /= bottom floor );
PERSON fletcher = ( "Fletcher", LOC INT := 0, ( INT floor )BOOL: floor /= top floor AND floor /= bottom floor
AND NOT adjacent( floor, floor OF cooper ) );
PERSON miller = ( "Miller", LOC INT := 0, ( INT floor )BOOL: floor > floor OF cooper );
PERSON smith = ( "Smith", LOC INT := 0, ( INT floor )BOOL: NOT adjacent( floor, floor OF fletcher ) );
# SOLUTION #
# "brute force" solution - we run through the possible 5^5 configurations #
# we cold optimise this by e.g. restricting f to bottom floor + 1 TO top floor - 1 #
# at the cost of reducing the flexibility of the constraints #
# alternatively, we could add minimum and maximum allowed floors to the PERSON #
# STRUCT and loop through these instead of bottom floor TO top floor #
FOR b FROM bottom floor TO top floor DO
floor OF baker := b;
FOR c FROM bottom floor TO top floor DO
IF b /= c THEN
floor OF cooper := c;
FOR f FROM bottom floor TO top floor DO
IF b /= f AND c /= f THEN
floor OF fletcher := f;
FOR m FROM bottom floor TO top floor DO
IF b /= m AND c /= m AND f /= m THEN
floor OF miller := m;
FOR s FROM bottom floor TO top floor DO
IF b /= s AND c /= s AND f /= s AND m /= s THEN
floor OF smith := s;
IF OK baker AND OK cooper AND OK fletcher AND OK miller AND OK smith
THEN
# found a solution #
print floor( baker );
print floor( cooper );
print floor( fletcher );
print floor( miller );
print floor( smith )
FI
FI
OD
FI
OD
FI
OD
FI
OD
OD

View file

@ -0,0 +1,68 @@
public class Program
{
public static void Main()
{
const int count = 5;
const int Baker = 0, Cooper = 1, Fletcher = 2, Miller = 3, Smith = 4;
string[] names = { nameof(Baker), nameof(Cooper), nameof(Fletcher), nameof(Miller), nameof(Smith) };
Func<int[], bool>[] constraints = {
floorOf => floorOf[Baker] != count-1,
floorOf => floorOf[Cooper] != 0,
floorOf => floorOf[Fletcher] != count-1 && floorOf[Fletcher] != 0,
floorOf => floorOf[Miller] > floorOf[Cooper],
floorOf => Math.Abs(floorOf[Smith] - floorOf[Fletcher]) > 1,
floorOf => Math.Abs(floorOf[Fletcher] - floorOf[Cooper]) > 1,
};
var solver = new DinesmanSolver();
foreach (var tenants in solver.Solve(count, constraints)) {
Console.WriteLine(string.Join(" ", tenants.Select(t => names[t])));
}
}
}
public class DinesmanSolver
{
public IEnumerable<int[]> Solve(int count, params Func<int[], bool>[] constraints) {
foreach (int[] floorOf in Permutations(count)) {
if (constraints.All(c => c(floorOf))) {
yield return Enumerable.Range(0, count).OrderBy(i => floorOf[i]).ToArray();
}
}
}
static IEnumerable<int[]> Permutations(int length) {
if (length == 0) {
yield return new int[0];
yield break;
}
bool forwards = false;
foreach (var permutation in Permutations(length - 1)) {
for (int i = 0; i < length; i++) {
yield return permutation.InsertAt(forwards ? i : length - i - 1, length - 1).ToArray();
}
forwards = !forwards;
}
}
}
static class Extensions
{
public static IEnumerable<T> InsertAt<T>(this IEnumerable<T> source, int position, T newElement) {
if (source == null) throw new ArgumentNullException(nameof(source));
if (position < 0) throw new ArgumentOutOfRangeException(nameof(position));
return InsertAtIterator(source, position, newElement);
}
private static IEnumerable<T> InsertAtIterator<T>(IEnumerable<T> source, int position, T newElement) {
int index = 0;
foreach (T element in source) {
if (index == position) yield return newElement;
yield return element;
index++;
}
if (index < position) throw new ArgumentOutOfRangeException(nameof(position));
if (index == position) yield return newElement;
}
}

View file

@ -0,0 +1,122 @@
package main
import "fmt"
// The program here is restricted to finding assignments of tenants (or more
// generally variables with distinct names) to floors (or more generally
// integer values.) It finds a solution assigning all tenants and assigning
// them to different floors.
// Change number and names of tenants here. Adding or removing names is
// allowed but the names should be distinct; the code is not written to handle
// duplicate names.
var tenants = []string{"Baker", "Cooper", "Fletcher", "Miller", "Smith"}
// Change the range of floors here. The bottom floor does not have to be 1.
// These should remain non-negative integers though.
const bottom = 1
const top = 5
// A type definition for readability. Do not change.
type assignments map[string]int
// Change rules defining the problem here. Change, add, or remove rules as
// desired. Each rule should first be commented as human readable text, then
// coded as a function. The function takes a tentative partial list of
// assignments of tenants to floors and is free to compute anything it wants
// with this information. Other information available to the function are
// package level defintions, such as top and bottom. A function returns false
// to say the assignments are invalid.
var rules = []func(assignments) bool{
// Baker does not live on the top floor
func(a assignments) bool {
floor, assigned := a["Baker"]
return !assigned || floor != top
},
// Cooper does not live on the bottom floor
func(a assignments) bool {
floor, assigned := a["Cooper"]
return !assigned || floor != bottom
},
// Fletcher does not live on either the top or the bottom floor
func(a assignments) bool {
floor, assigned := a["Fletcher"]
return !assigned || (floor != top && floor != bottom)
},
// Miller lives on a higher floor than does Cooper
func(a assignments) bool {
if m, assigned := a["Miller"]; assigned {
c, assigned := a["Cooper"]
return !assigned || m > c
}
return true
},
// Smith does not live on a floor adjacent to Fletcher's
func(a assignments) bool {
if s, assigned := a["Smith"]; assigned {
if f, assigned := a["Fletcher"]; assigned {
d := s - f
return d*d > 1
}
}
return true
},
// Fletcher does not live on a floor adjacent to Cooper's
func(a assignments) bool {
if f, assigned := a["Fletcher"]; assigned {
if c, assigned := a["Cooper"]; assigned {
d := f - c
return d*d > 1
}
}
return true
},
}
// Assignment program, do not change. The algorithm is a depth first search,
// tentatively assigning each tenant in order, and for each tenant trying each
// unassigned floor in order. For each tentative assignment, it evaluates all
// rules in the rules list and backtracks as soon as any one of them fails.
//
// This algorithm ensures that the tenative assignments have only names in the
// tenants list, only floor numbers from bottom to top, and that tentants are
// assigned to different floors. These rules are hard coded here and do not
// need to be coded in the the rules list above.
func main() {
a := assignments{}
var occ [top + 1]bool
var df func([]string) bool
df = func(u []string) bool {
if len(u) == 0 {
return true
}
tn := u[0]
u = u[1:]
f:
for f := bottom; f <= top; f++ {
if !occ[f] {
a[tn] = f
for _, r := range rules {
if !r(a) {
delete(a, tn)
continue f
}
}
occ[f] = true
if df(u) {
return true
}
occ[f] = false
delete(a, tn)
}
}
return false
}
if !df(tenants) {
fmt.Println("no solution")
return
}
for t, f := range a {
fmt.Println(t, f)
}
}

View file

@ -1,2 +1,6 @@
import Data.List (permutations)
main = print [ (b,c,f,m,s) | [b,c,f,m,s] <- permutations [1..5], b/=5,c/=1,f/=1,f/=5,m>c,abs(s-f)>1,abs(c-f)>1]
print [ ("Baker lives on " ++ show b
, "Cooper lives on " ++ show c
, "Fletcher lives on " ++ show f
, "Miller lives on " ++ show m
, "Smith lives on " ++ show s) | [b,c,f,m,s] <- permutations [1..5], b/=5,c/=1,f/=1,f/=5,m>c,abs(s-f)>1,abs(c-f)>1]

View file

@ -0,0 +1,54 @@
(() => {
'use strict';
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) => [].concat.apply([], xs.map(f));
// range :: Int -> Int -> [Int]
const range = (m, n) =>
Array.from({
length: Math.floor(n - m) + 1
}, (_, i) => m + i);
// and :: [Bool] -> Bool
const and = xs => {
let i = xs.length;
while (i--)
if (!xs[i]) return false;
return true;
}
// nubBy :: (a -> a -> Bool) -> [a] -> [a]
const nubBy = (p, xs) => {
const x = xs.length ? xs[0] : undefined;
return x !== undefined ? [x].concat(
nubBy(p, xs.slice(1)
.filter(y => !p(x, y)))
) : [];
}
// PROBLEM DECLARATION
const floors = range(1, 5);
return concatMap(b =>
concatMap(c =>
concatMap(f =>
concatMap(m =>
concatMap(s =>
and([ // CONDITIONS
nubBy((a, b) => a === b, [b, c, f, m, s]) // all floors singly occupied
.length === 5,
b !== 5, c !== 1, f !== 1, f !== 5,
m > c, Math.abs(s - f) > 1, Math.abs(c - f) > 1
]) ? [{
Baker: b,
Cooper: c,
Fletcher: f,
Miller: m,
Smith: s
}] : [],
floors), floors), floors), floors), floors);
// --> [{"Baker":3, "Cooper":2, "Fletcher":4, "Miller":5, "Smith":1}]
})();

View file

@ -0,0 +1 @@
[{"Baker":3, "Cooper":2, "Fletcher":4, "Miller":5, "Smith":1}]

View file

@ -0,0 +1,55 @@
(() => {
'use strict';
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) => [].concat.apply([], xs.map(f));
// range :: Int -> Int -> [Int]
const range = (m, n) =>
Array.from({
length: Math.floor(n - m) + 1
}, (_, i) => m + i);
// and :: [Bool] -> Bool
const and = xs => {
let i = xs.length;
while (i--)
if (!xs[i]) return false;
return true;
}
// permutations :: [a] -> [[a]]
const permutations = xs =>
xs.length ? concatMap(x => concatMap(ys => [
[x].concat(ys)
],
permutations(delete_(x, xs))), xs) : [
[]
];
// delete :: a -> [a] -> [a]
const delete_ = (x, xs) =>
deleteBy((a, b) => a === b, x, xs);
// deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]
const deleteBy = (f, x, xs) =>
xs.reduce((a, y) => f(x, y) ? a : a.concat(y), []);
// PROBLEM DECLARATION
const floors = range(1, 5);
return concatMap(([c, b, f, m, s]) =>
and([ // CONDITIONS (assuming full occupancy, no cohabitation)
b !== 5, c !== 1, f !== 1, f !== 5,
m > c, Math.abs(s - f) > 1, Math.abs(c - f) > 1
]) ? [{
Baker: b,
Cooper: c,
Fletcher: f,
Miller: m,
Smith: s
}] : [], permutations(floors));
// --> [{"Baker":3, "Cooper":2, "Fletcher":4, "Miller":5, "Smith":1}]
})();

View file

@ -0,0 +1 @@
[{"Baker":3, "Cooper":2, "Fletcher":4, "Miller":5, "Smith":1}]

View file

@ -1,6 +1,9 @@
use MONKEY-SEE-NO-EVAL;
sub parse_and_solve ($text) {
my %ids;
my $expr = (grammar {
state $c = 0;
rule TOP { <fact>+ { make join ' && ', $<fact>>>.made } }
rule fact { <name> (not)? <position>
@ -19,7 +22,7 @@ sub parse_and_solve ($text) {
|| { note "Failed to parse line " ~ +$/.prematch.comb(/^^/); exit 1; }
}
token name { :i <[a..z]>+ { make %ids{~$/} //= (state $)++ } }
token name { :i <[a..z]>+ { make %ids{~$/} //= $c++ } }
token ordinal { [1st | 2nd | 3rd | \d+th] { make +$/.match(/(\d+)/)[0] } }
}).parse($text).made;

View file

@ -0,0 +1,68 @@
# Floors are numbered 1 (ground) to 5 (top)
# Baker, Cooper, Fletcher, Miller, and Smith live on different floors:
$statement1 = '$baker -ne $cooper -and $baker -ne $fletcher -and $baker -ne $miller -and
$baker -ne $smith -and $cooper -ne $fletcher -and $cooper -ne $miller -and
$cooper -ne $smith -and $fletcher -ne $miller -and $fletcher -ne $smith -and
$miller -ne $smith'
# Baker does not live on the top floor:
$statement2 = '$baker -ne 5'
# Cooper does not live on the bottom floor:
$statement3 = '$cooper -ne 1'
# Fletcher does not live on either the top or the bottom floor:
$statement4 = '$fletcher -ne 1 -and $fletcher -ne 5'
# Miller lives on a higher floor than does Cooper:
$statement5 = '$miller -gt $cooper'
# Smith does not live on a floor adjacent to Fletcher's:
$statement6 = '[Math]::Abs($smith - $fletcher) -ne 1'
# Fletcher does not live on a floor adjacent to Cooper's:
$statement7 = '[Math]::Abs($fletcher - $cooper) -ne 1'
for ($baker = 1; $baker -lt 6; $baker++)
{
for ($cooper = 1; $cooper -lt 6; $cooper++)
{
for ($fletcher = 1; $fletcher -lt 6; $fletcher++)
{
for ($miller = 1; $miller -lt 6; $miller++)
{
for ($smith = 1; $smith -lt 6; $smith++)
{
if (Invoke-Expression $statement2)
{
if (Invoke-Expression $statement3)
{
if (Invoke-Expression $statement5)
{
if (Invoke-Expression $statement4)
{
if (Invoke-Expression $statement6)
{
if (Invoke-Expression $statement7)
{
if (Invoke-Expression $statement1)
{
$multipleDwellings = @()
$multipleDwellings+= [PSCustomObject]@{Name = "Baker" ; Floor = $baker}
$multipleDwellings+= [PSCustomObject]@{Name = "Cooper" ; Floor = $cooper}
$multipleDwellings+= [PSCustomObject]@{Name = "Fletcher"; Floor = $fletcher}
$multipleDwellings+= [PSCustomObject]@{Name = "Miller" ; Floor = $miller}
$multipleDwellings+= [PSCustomObject]@{Name = "Smith" ; Floor = $smith}
}
}
}
}
}
}
}
}
}
}
}
}

View file

@ -0,0 +1 @@
$multipleDwellings | Sort-Object -Property Floor -Descending

View file

@ -1,32 +1,32 @@
/*REXX pgm: Dinesman's multiple-dwelling problem with "natural" wording.*/
names= 'Baker Cooper Fletcher Miller Smith' /*names of the tenants.*/
floors=5; top=floors; bottom=1; #=floors; sols=0
/*floor 1 is the ground floor. */
do !.1=1 for #;do !.2=1 for #;do !.3=1 for #;do !.4=1 for #;do !.5=1 for #
do p=1 for words(names); _=word(names,p); upper _; call value _,!.p
end /*p*/
/* [↓] don't live on same floor.*/
do j=1 for #-1; do k=j+1 to #; if !.j==!.k then iterate !.5; end;end
/*REXX program solves the Dinesman's multiple─dwelling problem with "natural" wording.*/
names= 'Baker Cooper Fletcher Miller Smith' /*names of multiple─dwelling tenants. */
tenants=words(names) /*the number of tenants in the building*/
floors=5; top=floors; bottom=1; #=floors; /*floor 1 is the ground (bottom) floor.*/
sols=0
do !.1=1 for #; do !.2=1 for #; do !.3=1 for #; do !.4=1 for #; do !.5=1 for #
do p=1 for tenants; _=word(names,p); upper _; call value _, !.p
end /*p*/
do j=1 for #-1 /* [↓] people don't live on same floor*/
do k=j+1 to #; if !.j==!.k then iterate !.5 /*cohab?*/
end /*k*/
end /*j*/
call Waldo /* ◄══ where the rubber meets the road.*/
end; end; end; end; end /*!.5 & !.4 & !.3 & !.2 & !.1*/
call Waldo /* ◄───────────────────where the rubber meets the road.*/
end /*!.5*/; end /*!.4*/; end /*!.3*/; end /*!.2*/; end /*!.1*/
say; say 'found' sols "solution"s(sols)'.'
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────Waldo subroutine────────────────────*/
Waldo:
if Baker == top then return
if Cooper == bottom then return
if Fletcher == bottom | Fletcher == top then return
if Miller \> Cooper then return
if Smith == Fletcher-1 | Smith == Fletcher+1 then return
if Fletcher == Cooper-1 | Fletcher == Cooper+1 then return
say; sols=sols+1 /*list tenants in order in list. */
do p=1 for words(names); _=word(names,p)
say right(_,20) 'lives on the' !.p||th(!.p) "floor."
end /*p*/
return
/*──────────────────────────────────one-liner subroutines───────────────*/
s: if arg(1)=1 then return ''; return 's' /*a simple pluralizer funct.*/
th:procedure;parse arg x;x=abs(x);return word('th st nd rd',1+x//10*(x//100%10\==1)*(x//10<4))
say 'found' sols "solution"s(sols). /*display the number of solutions found*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
Waldo: if Baker == top then return
if Cooper == bottom then return
if Fletcher == bottom | Fletcher == top then return
if Miller \> Cooper then return
if Smith == Fletcher-1 | Smith == Fletcher+1 then return
if Fletcher == Cooper -1 | Fletcher == Cooper +1 then return
sols=sols+1
say; do p=1 for tenants; tenant=right( word(names, p), 30)
say tenant 'lives on the' !.p || th(!.p) "floor."
end /*p*/
return /* [↑] show tenants in order in NAMES.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
s: if arg(1)=1 then return ''; return "s" /*a simple pluralizer function.*/
th: arg x; x=abs(x); return word('th st nd rd', 1 +x// 10* (x//100%10\==1)*(x//10<4))

View file

@ -1,21 +1,13 @@
people$ = "Baler,Cooper,Fletcher,Miller,Smith"
for baler = 1 to 4 ' can not be in room 5
for cooper = 2 to 5 ' can not be in room 1
for fletcher = 2 to 4 ' can not be in room 1 or 5
for miller = 1 to 5 ' can be in any room
for smith = 1 to 5 ' can be in any room
if miller > cooper and abs(smith - fletcher) > 1 and abs(fletcher - cooper) > 1 then
if baler <> cooper and fletcher <> miller and miller > cooper and abs(smith - fletcher) > 1 and abs(fletcher - cooper) > 1 then
if baler + cooper + fletcher + miller + smith = 15 then ' that is 1 + 2 + 3 + 4 + 5
rooms$ = baler;cooper;fletcher;miller;smith
bad = 0
for i = 1 to 5 ' make sure each room is unique
rm$ = chr$(i + 48)
r1 = instr(rooms$,rm$)
r2 = instr(rooms$,rm$,r1+1)
if r2 <> 0 then bad = 1
next i
if bad = 0 then goto [roomAssgn] ' if it is not bad it is a good assignment
print "baler: ";baler;" copper: ";cooper;" fletcher: ";fletcher;" miller: ";miller;" smith: ";smith
end
end if
end if
next smith
@ -23,11 +15,4 @@ for baler = 1 to 4 ' can not be in r
next fletcher
next cooper
next baler
print "Cam't assign rooms" ' print this if it can not find a solution
wait
[roomAssgn]
Print "Room Assignment"
for i = 1 to 5
print mid$(rooms$,i,1);" ";word$(people$,i,",");" "; ' print the room assignments
next i
print "Can't assign rooms" ' print this if it can not find a solution

View file

@ -0,0 +1,11 @@
10 REM Floors are numbered 0 (ground) to 4 (top)
20 REM "Baker, Cooper, Fletcher, Miller, and Smith live on different floors":
30 REM "Baker does not live on the top floor"
40 REM "Cooper does not live on the bottom floor"
50 REM "Fletcher does not live on either the top or the bottom floor"
60 REM "Miller lives on a higher floor than does Cooper"
70 REM "Smith does not live on a floor adjacent to Fletcher's"
80 REM "Fletcher does not live on a floor adjacent to Cooper's"
90 FOR b=0 TO 4: FOR c=0 TO 4: FOR f=0 TO 4: FOR m=0 TO 4: FOR s=0 TO 4
100 IF B<>C AND B<>F AND B<>M AND B<>S AND C<>F AND C<>M AND C<>S AND F<>M AND F<>S AND M<>S AND B<>4 AND C<>0 AND F<>0 AND F<>4 AND M>C AND ABS (S-F)<>1 AND ABS (F-C)<>1 THEN PRINT "Baker lives on floor ";b: PRINT "Cooper lives on floor ";c: PRINT "Fletcher lives on floor ";f: PRINT "Miller lives on floor ";m: PRINT "Smith lives on floor ";s: STOP
110 NEXT s: NEXT m: NEXT f: NEXT c: NEXT b